Design Notification System
Design a notification system: email, SMS, push notifications with delivery guarantees and preferences.
What is a notification system?
A notification system turns a product event, such as an order update or security alert, into one or more messages delivered through email, SMS, push, or in-app channels. It accepts work quickly, stores a durable notification intent, applies the user's latest communication policy, and sends through external providers asynchronously.
The core invariant is: an accepted intent is durable, no external send bypasses current policy, and retries create at most one logical channel delivery. "Accepted" therefore means the platform owns the work; it does not mean a provider or device has delivered it.
This walkthrough assumes familiarity with message queues, then builds from requirements and volume estimates to provider failures and production operations.
Durability
Separate acceptance from delivery
Commit the intent and outbox event before acknowledging it. Template rendering, scheduling, fanout, and provider calls continue asynchronously.
Safety
Recheck policy before send
An enqueue-time decision can become stale. Consent, quiet hours, frequency caps, and channel eligibility are authoritative immediately before an external call.
Correctness
Make retries harmless
Use stable delivery and attempt identities across queues, workers, provider requests, and callbacks. At-least-once transport should still produce one logical send.
What is the notification contract?
The contract states what callers may request, what users may control, and which result the system can honestly promise. These decisions shape the data model and failure behavior before any vendor or database is chosen.
User actions
Functional requirements
- Accept transactional, security, product, and marketing events.
- Target one recipient, a saved audience, or a large campaign.
- Deliver through push, email, SMS, and in-app channels.
- Support templates, personalization, scheduling, and approved fallback channels.
- Expose accepted, scheduled, suppressed, dispatched, delivered, and failed states.
Permission
User policy
- Enable or disable categories and channels.
- Enforce immediate opt-outs and verified destination changes.
- Respect recipient-local quiet hours and frequency caps.
- Keep security and legally required messages in explicit policy classes.
- Record the policy version and reason used for every suppression.
Observable
Service objectives
- Sustain 100 million accepted intents per day and about 50K intents/s during a campaign burst.
- Keep acceptance P95 below 150 ms when the durable tier is healthy.
- Start eligible critical sends within one second at P99.
- Start normal sends within one minute and marketing sends within ten minutes at P99.
- Preserve accepted work through a worker, queue partition, or single-region failure.
Out of scope
First-version boundary
- No guarantee that a provider can deliver to an offline or invalid destination.
- No universal exactly-once claim across independent providers and devices.
- No recommendation model for choosing content or optimal send time.
- No full campaign authoring suite, billing system, or engagement attribution model.
- No emergency broadcast guarantee without a separately validated product contract.
Questions to ask the interviewer
- Does one request target one user or an audience that may contain millions? Assume both, but expand large audiences asynchronously.
- Which channels and message classes are required? Assume push, email, SMS, and in-app across security, transactional, product, and marketing classes.
- Does critical mean "ignore all limits"? Assume it may bypass marketing frequency caps, but never consent rules, legal restrictions, destination validation, or provider quotas.
- What does delivery mean? Treat provider acceptance, provider delivery, device receipt, and user engagement as distinct states.
- How quickly must opt-outs take effect? Assume a user change must stop queued marketing work before the next provider call.
- Are channel fallbacks automatic? Assume only an explicit policy may authorize fallback because cost, consent, and user experience differ by channel.
Correctness boundaries
- A successful ingestion response refers to one durable
notification_idfor the caller's idempotency key. - A recipient-channel pair has one stable
channel_delivery_id, even when workers replay the event. - A provider retry reuses the same attempt key after an ambiguous result; a deliberate failover creates a sequenced new attempt under the same logical delivery.
- Policy is evaluated once to plan work and again immediately before an external send.
- Callback events advance delivery state monotonically; a late "accepted" event cannot overwrite "delivered" or "permanently failed."
Do not promise 99.9% end-user delivery without defining eligible destinations and provider behavior. The platform can own durable acceptance, time-to-first-attempt, policy compliance, and status accuracy; a disconnected device or invalid phone number remains outside its control.