Prompt
Our app has real-time events and I need users to see the same message in-app, by email, and sometimes by SMS. What's the best way to handle that?
Latest observation
The best approach is to make the event the source of truth and then fan it out to multiple notification channels through a notification service.
Recommended pattern
1. Produce one canonical event
When something happens in your app, emit a single event like:
order_shippedpayment_failedcomment_mentionedsecurity_alert
This event should contain:
- event ID
- user ID(s)
- message template key
- variables/data needed to render the message
- priority
- timestamps
- deduplication/correlation IDs
2. Route the event to a notification pipeline
Instead of having your app send email/SMS/in-app directly, send the event to a backend notification system that can decide:
- whether to notify
- which channels to use
- in what order
- based on user preferences, urgency, and channel availability
3. Render channel-specific output from the same content
Use the same underlying message content, but format it per channel:
- In-app: rich, contextual, possibly interactive
- Email: longer, formatted, with links and branding
- SMS: short, plain-text, time-sensitive
You want one source message, not three separately written ones.
4. Add preferences and rules
Let users configure:
- channel preferences
- quiet hours
- digest vs immediate
- per-event-type settings
Also apply business rules like:
- SMS only for critical alerts
- email for receipts and summaries
- in-app for all realtime updates
5. Make it idempotent and deduplicated
Since the same event may be retried or delivered to multiple systems:
- assign a unique event ID
- track notification delivery per user/channel
- prevent duplicate sends
6. Track delivery and read state separately
A notification can have:
- delivery status: queued/sent/delivered/failed
- in-app state: unread/read/dismissed
These are related but not the same thing.
Architecture example
App/event producer
→ publishes NotificationRequested event
→ Notification service
- looks up user preferences
- chooses channels
- renders templates
- sends via email/SMS/in-app providers
- stores audit/log state
Good implementation choices
If you’re building this yourself:
- use a message queue / event bus
- use templates with a shared data model
- keep channel adapters separate
- store notification history
If you want a simpler approach, start with:
- one notification table
- one event processor
- channel-specific worker jobs
Important design principle
Don’t treat email, SMS, and in-app as separate features.
Treat them as delivery channels for the same notification event.
Practical rule of thumb
- In-app = default for realtime UX
- Email = durable, detailed follow-up
- SMS = only for urgent/high-priority items
If you want, I can sketch a concrete schema or a sample event/notification flow for your stack.