Design a Notification System
mediumA notification platform delivers transactional and marketing messages to users across push, email, SMS, in-app, and chat. The architecture problem is rarely any single channel — it's the orchestration: preferences, dedup, rate limits, vendor failover, and lane separation.
Key Concepts
High-level design
Producers → NotificationRequest API.
Notification service → preference check, rate limit, dedup, template render.
Kafka topics per channel + priority (push-tx, push-bulk, email-tx, email-bulk, ...).
Per-channel worker pools → vendor API call with retries.
Vendor webhooks → status update → audit store.
Bounce handler → update suppression list.
Analytics → opens, clicks, conversion.
Components
- Notification API gateway.
- Preference service (per-user channel preferences).
- Suppression list (bounces, opt-outs).
- Rate limiter (per user, per template, per recipient).
- Template renderer (with localization, A/B variants).
- Channel workers (push, email, sms, in-app, slack).
- Vendor abstraction layer (multi-vendor with health-based routing).
- Audit + analytics store (Cassandra or ClickHouse).
- Webhook receiver for vendor status updates.
- Bounce / unsub processor.
Multi-channel preferences
User preferences: per-channel (email yes, SMS no) per-template-category (transactional always, marketing opt-in).
Suppression overrides preferences for bounces and TCPA / GDPR.
Cross-channel dedup: if you already sent an email about this event, don't also send a push.
Fallback chain: try push; if no device registered, fall back to email.
Vendor strategy
Multi-vendor for redundancy: primary + backup per channel.
Vendor abstraction layer routes to primary; on 5xx or timeout, fails over.
Vendor-specific rate limits respected via per-vendor rate limiters.
Async delivery status via webhooks; sometimes delayed by hours.
Periodic reconciliation: compare what we sent vs what the vendor reports delivered.
Trade-offs
Single queue for all: simple but bulk starves transactional.
Separate queues per priority: better isolation, more infra.
Sync API for transactional, async for bulk: lower latency for critical paths.
Push tokens churn — apps reinstall, devices change. Background cleanup of invalid tokens essential.
Email warm-up takes weeks; cold IPs land in spam.
SMS expensive — gate behind verification flows; A2P 10DLC compliance in US.
Compliance and deliverability
Email: SPF, DKIM, DMARC alignment required for good deliverability.
IP warming: send small volumes from new IPs gradually; reputation builds.
Marketing vs transactional IP separation prevents marketing bounces from poisoning transactional reputation.
Unsubscribe link in every marketing message (CAN-SPAM).
Preference center; honor opt-outs across channels.
TCPA for SMS in US: prior express written consent for marketing; carrier registration (A2P 10DLC).
GDPR for EU: explicit consent, data subject rights, audit trail.