Case studies
Preferences, quiet hours and digests
How per-user preferences decide whether, where and when a notification is sent, including quiet hours, digests, channel cost and the compliance rules for opt-outs.
Preferences decide whether a notification is sent at all, on which channels, and when. A correct message that ignores a user's preferences or quiet hours is still spam. The preference check runs before any work reaches a provider, which saves cost as well as annoyance.
A digest collapses many events into one message on a schedule. Instead of 40 separate pushes about likes, the user gets one message that says "You have 40 new notifications".
The big idea
Each user has one preference record. It sets the channels they accept, the categories they care about, their quiet hours and any digest schedules. Two rules sit on top:
- Security messages bypass marketing opt-outs. They often bypass quiet hours too, with agreement from product and legal.
- Social messages can be digested. Low-signal events roll up. High-signal events, such as a direct message or a security alert, go out in real time.
Walking through it
A preference record looks like this. It is a sketch of the data, not runnable code:
user_id -> {
push: true,
email: true,
sms: false,
categories: { marketing: false, security: true, social: true },
quietHours: { start: "22:00", end: "08:00", tz: "America/Los_Angeles" },
digest: { social: "daily_08:00" }
}Quiet hours in practice. A social event arrives at 23:30 in the user's time zone. The quiet window ends at 08:00. The event waits 8 hours 30 minutes and goes out at 08:00. A security code in the same window still goes out, because the security category is an exception.
The channel defaults are a policy, and they drive cost. SMS is often orders of magnitude more expensive than push. One default policy is:
| Category | Default channels | Why |
|---|---|---|
| Security | SMS and email | Must arrive, and is worth the cost |
| Social | Push and inbox | Cheap, and the inbox keeps history |
| Marketing | Email and inbox, push only if opted in | Never spend SMS on a like |
Interviewers like hearing a rough cost next to the design. Sending a text to 10 million users for a like is the mistake they are listening for.
Compliance
Marketing email needs an unsubscribe link and a suppression list, which is the law in many places. SMS may need STOP handling. Store consent timestamps next to preferences when the product requires them.
Transactional messages, such as receipts and password resets, usually stay allowed after a marketing unsubscribe. Encode that in the category rules. A global "email off" flag for marketing must not accidentally turn off password-reset email. Document the matrix of categories, channels and rules, because support teams will ask.
Common mistakes
- One global email switch. It can silence password resets along with marketing.
- Digesting security messages. A one-line summary of a login code is useless.
- Per-event push for low-signal social events. The result is annoyance, and it costs provider spend.
Check yourself
-
A user turns off email globally, then requests a password reset. Should the reset email send?
Yes, if the transactional category allows it. Category rules let a marketing opt-out leave transactional mail alone.
-
A social event arrives at 23:30 with quiet hours from 22:00 to 08:00. When does it go out?
At 08:00, about 8.5 hours later, unless the category is an exception.
Key takeaways
- Check preferences before enqueuing, so a message never reaches a provider it shouldn't.
- Use digests for low-signal events, and real-time sends for high-signal ones.
- Channel policy is a cost decision, and SMS should be reserved for what must arrive.
- Encode transactional exceptions in category rules, so one flag can't disable critical mail.
Further learning
Next: idempotency for notifications, which stops retries from sending duplicates.
Related
Case study: notification system
Designing push, email and SMS delivery at scale, covering the pipeline, preference checks, idempotency, provider rate limits, retries and priority lanes.
Rate limiting
Why systems cap how much work a client can send, which algorithm counts, where the limit lives and what the client is told. Start here for the rate-limiting map.
Message queues
A durable buffer between the code that creates work and the code that does it. Start here for the map of queue concepts.