A practical ExpressJS backend for email and system notifications with MongoDB persistence, reusable templates, notification history, retries, scheduling, priorities, read state, filtering, pagination, and status tracking.
- Email notifications with Nodemailer
- System / in-app notifications
- Immediate notifications
- Scheduled notifications
- Bulk notifications
- Reusable email templates
- Notification priorities
- Pending, sent, failed, and scheduled status
- Delivery attempt tracking
- Failure reason tracking
- Retry failed notifications
- Notification history
- Search
- Recipient filtering
- Type filtering
- Status filtering
- Priority filtering
- Read / unread filtering
- Sorting
- Pagination
- Mark notification as read
- Mark notification as unread
- Mark all notifications for a recipient as read
- Delete notification history
- MongoDB persistence
- Mongoose validation
- Centralized error handling
- Graceful shutdown
- Health check endpoint
- Bearer API key protection for notification routes
- API testing with
requests.http
- Node.js
- ExpressJS
- MongoDB
- Mongoose
- Nodemailer
- Nodemon
email
system
pending
sent
failed
scheduled
low
normal
high
All /api/v1/notifications routes require Authorization: Bearer <API_KEY>. The root and health endpoints remain public for basic availability checks.
GET /GET /api/v1/healthPOST /api/v1/notificationsPOST /api/v1/notifications/bulkGET /api/v1/notificationsGET /api/v1/notifications/:idPOST /api/v1/notifications/:id/retryPOST /api/v1/notifications/process-scheduledPATCH /api/v1/notifications/:id/readPATCH /api/v1/notifications/:id/unreadPATCH /api/v1/notifications/mark-all-readDELETE /api/v1/notifications/:idGET /api/v1/notifications?page=1&limit=5GET /api/v1/notifications?search=welcomeGET /api/v1/notifications?recipient=user-001GET /api/v1/notifications?type=systemGET /api/v1/notifications?status=sentGET /api/v1/notifications?priority=highGET /api/v1/notifications?isRead=falseGET /api/v1/notifications?sort=createdAt&order=descCreate a .env file using .env.example.
PORT=1198
HOST=127.0.0.1
NODE_ENV=development
API_KEY=replace-with-a-random-64-character-hex-string
MONGODB_URI=mongodb://127.0.0.1:27017/notification_service
SMTP_HOST=smtp.example.com
SMTP_PORT=587
SMTP_SECURE=false
SMTP_USER=your_smtp_username
SMTP_PASS=your_smtp_password
MAIL_FROM=Notification Service <notifications@example.com>Generate a private API key with node -p "require('node:crypto').randomBytes(32).toString('hex')" and replace the placeholder. Keep the key private and send it only in the Authorization header. The server binds to 127.0.0.1 by default; configure HOST=0.0.0.0 only when a container or hosting platform requires it.
Real email delivery requires valid SMTP credentials.
Without valid SMTP values:
- System notifications still work
- MongoDB history still works
- Filtering, pagination, read state, and scheduling still work
- Email delivery attempts can fail and remain available for retry testing
npm ciRequires Node.js 22.13 or newer in the 22.x line, or Node.js 24 or newer.
npm run devnpm startThe API key is a shared service credential, not user authentication or per-recipient authorization. Do not expose this demo directly to the public internet; add identity, authorization, rate limiting, and HTTPS for a real multi-user service.
1198
Create Request
|
v
Validation
|
v
MongoDB Record
|
+----------------------+
| |
Immediate Scheduled
| |
v v
Delivery Service Wait Until Due
| |
v v
Email / System Process Scheduled
|
v
Status Update
|
+--> sent
|
+--> failed
Failed Notification
|
v
Retry Endpoint
|
v
Set Pending
|
v
Attempt Delivery
|
+--> Sent
|
+--> Failed Again
notification-service/
├── src/
│ ├── config/
│ │ ├── database.js
│ │ └── mailer.js
│ ├── controllers/
│ │ └── notification.controllers.js
│ ├── middlewares/
│ │ ├── errorHandler.middleware.js
│ │ └── notFound.middleware.js
│ ├── models/
│ │ └── notification.model.js
│ ├── routes/
│ │ └── notification.routes.js
│ ├── services/
│ │ └── notification.service.js
│ ├── templates/
│ │ └── notification.templates.js
│ ├── validators/
│ │ └── notification.validators.js
│ ├── app.js
│ └── server.js
├── .env.example
├── .gitignore
├── package.json
├── package-lock.json
├── README.md
└── requests.http
Detailed project and code documentation is available in DOCUMENTATION.md.
Ashish Ranjan
- Portfolio: https://www.ashishranjan.net
- GitHub: https://github.com/a2rp
- CodePen: https://codepen.io/ash1198
- LinkedIn: https://www.linkedin.com/in/aashishranjan
- Facebook: https://www.facebook.com/theash.ashish/
- YouTube: https://www.youtube.com/@ashishranjan-ashz?sub_confirmation=1
- Email: mailto:ash.ranjan09@gmail.com
- Support: https://a2rp-donation-page.netlify.app/
- Buy Me A Coffee: https://buymeacoffee.com/a2rp
- Patreon: https://patreon.com/a2rp
MIT License