Design a Notification System — Email, Push, SMS at Scale
Notifications are harder than they look#
Send an email when someone likes your post. Simple, right? Until you have 10M users, 50 notification types, three delivery channels, user preferences, rate limiting, and a CEO asking why the welcome email arrived 4 hours late.
The architecture#
Event → Router → Template Engine → Delivery Queue → Channel Providers
↓ ↓
Preference Store Delivery Tracking
Step 1: Event ingestion#
Every notification starts with an event:
{
"type": "comment_reply",
"userId": "user-123",
"data": { "commenter": "Mo", "postTitle": "My Architecture" },
"timestamp": "2026-03-23T10:00:00Z"
}
Events come from many sources: API calls, webhooks, cron jobs, other services. A single ingestion endpoint normalizes them all.
Step 2: User preferences#
Before sending anything, check what the user wants:
{
"userId": "user-123",
"preferences": {
"comment_reply": { "email": true, "push": true, "sms": false },
"weekly_digest": { "email": true, "push": false, "sms": false },
"marketing": { "email": false, "push": false, "sms": false }
},
"quietHours": { "start": "22:00", "end": "08:00", "timezone": "US/Pacific" }
}
Never send a notification the user didn't opt into. This isn't just good UX — it's legally required (CAN-SPAM, GDPR).
Step 3: Template rendering#
Separate content from delivery logic:
Template: "{{commenter}} replied to your post '{{postTitle}}'"
Data: { commenter: "Mo", postTitle: "My Architecture" }
Result: "Mo replied to your post 'My Architecture'"
Templates per channel:
- Email: HTML template with header, body, CTA button, unsubscribe link
- Push: Title (50 chars) + body (100 chars) + deep link
- SMS: Plain text, 160 chars, include opt-out instructions
Step 4: Rate limiting and batching#
Per-user rate limiting: Max 5 push notifications per hour. If exceeded, batch remaining into a digest.
Batching: Don't send 50 individual "someone liked your post" pushes. Batch into "Mo and 49 others liked your post."
Frequency capping: No more than 1 email per day for non-critical notifications. Digests are your friend.
Step 5: Delivery#
Each channel has its own queue and provider:
| Channel | Provider | Considerations |
|---|---|---|
| SendGrid, SES, Postmark | SPF/DKIM, bounce handling, deliverability | |
| Push | FCM (Android), APNs (iOS) | Token management, badge counts |
| SMS | Twilio, Vonage | Cost ($0.01/msg), opt-out compliance |
| In-app | WebSocket/polling | Real-time, no cost, highest engagement |
Priority queues: Password reset emails go to the high-priority queue (deliver in seconds). Weekly digests go to the low-priority queue (deliver within hours).
Step 6: Delivery tracking#
Track every notification:
- Sent — handed to provider
- Delivered — provider confirmed delivery
- Opened — tracking pixel loaded (email) or notification tapped (push)
- Clicked — CTA link clicked
- Failed — bounce, invalid token, blocked
This data feeds back into the system: stop sending to bounced emails, remove invalid push tokens, identify which notification types have the best engagement.
Common mistakes#
Sending too many notifications. Users will disable notifications entirely. Less is more.
No unsubscribe. Legal requirement for email. Every email needs a one-click unsubscribe link.
Not handling failures. Push tokens expire, emails bounce, phone numbers change. Handle every failure gracefully.
Sending during quiet hours. Nobody wants a push notification at 3am. Respect timezone-aware quiet hours.
No deduplication. The same event fires twice → user gets duplicate notifications. Use event IDs for dedup.
See the full architecture#
On Codelit, search "notification" in ⌘K to load the complete notification system — event triggers, channel routing, template engine, delivery queues, and tracking.
Design your notification system: search "notification" on Codelit.io and explore the full architecture.
Try it on Codelit
Chaos Mode
Simulate node failures and watch cascading impact across your architecture
90+ Templates
Practice with real-world architectures — Uber, Netflix, Slack, and more
Related articles
Try these templates
Uber Real-Time Location System
Handles 5M+ GPS pings per second using H3 hexagonal geospatial indexing.
6 componentsNetflix Video Streaming Architecture
Global video streaming platform with adaptive bitrate, CDN distribution, and recommendation engine.
10 componentsE-Commerce Checkout System
Production checkout flow with Stripe payments, inventory management, and fraud detection.
11 componentsBuild this architecture
Generate an interactive architecture for Design a Notification System in seconds.
Try it in Codelit →
Comments