Email Delivery Service System Design Interview
Narrate an email delivery service system design interview out loud: requirements, the send pipeline, retries, idempotency and the trade-offs you have to defend.
You freeze because you try to hold the whole design in your head at once. Don't. In an email delivery service system design interview, interviewers score whether you turn a vague prompt into a pipeline with named failure handling. Open by scoping it: "I'll design a service that accepts send requests from internal apps, queues them, delivers via SMTP or a provider, and tracks delivery status." Then narrate in order: requirements, architecture, one request end to end, retries and duplicates, trade-offs. This article gives you the wording for each step so you can say it out loud without rambling.
What is an email delivery service actually being asked to do?
Separate the three jobs interviewers conflate. First, accepting a send request from another service and returning quickly. Second, delivering to the recipient's mail server, which is slow, unreliable and outside your control. Third, reporting what happened, which is not the same as the recipient reading it.
State the scope out loud. Say you are designing transactional email — receipts, password resets, account alerts — not a full marketing suite. Give the reason: transactional mail has tighter latency expectations and lower volume per send, and you don't need campaign scheduling or audience segmentation. Scoping narrows the problem and shows you know what you're leaving out.
Then give your one-sentence framing and pause. It tells the interviewer you have a plan, and it invites them to correct your scope before you spend ten minutes drawing the wrong diagram.
Which requirements should you nail down before drawing anything?
Ask before you draw. The answers change the design, and asking shows you treat requirements as system design requirements rather than a formality.
- Volume per day, and peak per second. Changes whether a single queue and a small worker pool suffice or you need partitioning and autoscaling.
- Attachment support. Changes storage: you store blobs separately and pass references, not bytes through the queue.
- Multi-tenant or single-tenant. Changes auth, rate limits and how you isolate one customer's spike from another's.
- Compliance needs. Retention, audit logs and data residency change what you store and for how long.
- Latency target for "accepted". Usually a fast API response matters more than fast delivery, so you decouple the two.
Write your non-functional requirements as numbers you choose and defend: throughput, a latency target for the accept call, durability of queued mail, and at-least-once delivery with deduplication. If you want a sharper way to set and defend those numbers, see consistency models in a system design interview.
What does the high-level architecture look like, component by component?
Draw left to right and narrate as you go:
- API gateway — authenticates the calling service and applies rate limits.
- Validation — checks sender, recipient format and the suppression list.
- Durable queue — persists the accepted request before you acknowledge it.
- Worker pool — pulls messages and attempts delivery.
- Outbound delivery — SMTP or a provider API, depending on your build-versus-buy choice.
- Status store — records every state change for the caller to query.
Explain why the queue sits between acceptance and delivery: it absorbs spikes and decouples the caller's latency from the mail server's. A slow recipient server should never make your API slow.
Name the storage split. A request and status table tracks each message. A suppression list holds addresses that bounced hard or complained. A template store exists only if you support templates. Keeping these separate means a bounce update never touches the hot status path.
How do you walk through the send path from request to inbox?
This is the part to rehearse until it sounds like one continuous sentence. Here is a worked walkthrough you can adapt:
"A caller posts a send request with an idempotency key. I validate the recipient format and check the suppression list — if the address is suppressed, I reject immediately and record why. I compute a dedupe key and check it; if it exists, I return the original message ID instead of enqueuing again. Otherwise I assign a message ID, write the request to the status table as accepted, and enqueue it. I acknowledge the caller. A worker picks it up, marks it sending, attempts delivery over SMTP or the provider API, and records the result: delivered, bounced or failed. Transient errors go back on the queue with a backoff; hard bounces update the suppression list and are terminal. The caller polls or receives a webhook with the final status."
Say the status model plainly: accepted, queued, sending, delivered, bounced, failed. Name the terminal states — delivered, bounced and failed don't change again. That one detail stops the interviewer wondering whether your state machine loops.
How do retries, bounces and duplicates get handled without double-sending?
Say each row as a decision, not a component.
| Error type | Action | Why |
|---|---|---|
| Transient SMTP error (timeout, 4xx) | Retry with exponential backoff and jitter | The server may recover; jitter stops retries from arriving in lockstep |
| Hard bounce (invalid address, 5xx) | No retry; add to suppression list | Retrying a permanent failure wastes effort and damages sender reputation |
| Duplicate request | Return the stored result via the dedupe key, with a TTL | At-least-once delivery plus dedupe beats promising exactly-once |
| Attempts exhausted | Move to a dead-letter queue | Keeps the pipeline clear and leaves the failure visible |
Explain idempotency in practice: store the dedupe key with the message ID and a TTL, and check it before enqueue. It's a hash of sender, recipient and body, or a client-supplied key. Then say the sentence that earns points: at-least-once plus deduplication is honest; exactly-once across an external mail server is not something you can promise.
Treat the suppression list as a deliverability requirement, not a nice-to-have. Provider feedback about bounces and complaints updates it, and future sends to those addresses are blocked before they reach the queue.
Which trade-offs will the interviewer push on, and how do you defend them?
Listing options is not defending them. Here is the difference, using queue choice.
Weak: "We could use Kafka, RabbitMQ or SQS. Kafka is good for scale, SQS is managed and simple."
Stronger: "I'll use a managed queue. The workload is high-volume but each message is independent, and I don't need replay or ordering across the whole stream. A managed queue gives me durability and retries without running brokers. If the interviewer wants replay for auditing, I'd move to Kafka and accept the operational cost of owning it."
The stronger version names a constraint, makes one decision, and states what would change it. Use that shape for the other trade-offs too.
- Build vs. buy delivery. Your own SMTP infrastructure buys control over IP reputation and costs operational burden; a provider API buys deliverability expertise and costs you visibility into the sending layer.
- Ordering. Per-recipient ordering rarely matters for transactional mail; it matters when a sequence must arrive in order, and then you partition by recipient.
- Consistency. Status reads can be slightly stale without harm, which lets you keep the status store simple.
When you're challenged, use a short script: restate the constraint, name the alternative, say what you'd give up. That keeps you calm and gives the interviewer something to score. If the follow-ups keep coming, responding to follow-up questions covers how to extend rather than repeat.
What are the most common mistakes in this interview question?
- Jumping to components before requirements. Fix: spend the first five minutes on scope and numbers, and say them out loud.
- Ignoring failure modes. Fix: name your retry policy, dead-letter queue and suppression list before you're asked.
- Treating "delivered" as "read". Fix: say what the service can observe — handoff to the recipient server — and that opens and reads need tracking pixels or provider events.
- Rambling through provider comparisons. Fix: make one decision, give one reason, move on.
How do you practise this walkthrough out loud before the interview?
Run a 25-minute routine. Five minutes writing requirements and the clarifying questions. Ten minutes narrating the architecture and the send path aloud, without notes. Five minutes on trade-offs, answering your own challenge out loud. Five minutes of self-review.
Record yourself and check for three tells: skipping requirements, listing components without reasons, and going silent when challenged. If you catch yourself speeding up under pressure, the techniques in event-driven architecture in a system design interview apply to your narration as much as to a queue. Then run the same structure on the notification system walkthrough and note where the pipelines differ — email's suppression and bounce handling is the part notifications usually lack.
Before you walk in
The design is less important than the narration: scope first, one request end to end, failures named as decisions. Pick one trade-off — queue choice is a good one — and rehearse the weak-then-stronger version until the strong one is your default. Then record a single five-minute run and listen only for the three tells. Fix one per practice session and you'll walk in with a structure you trust.
Frequently asked questions
Should I use a real email provider in the design or keep it abstract?
Name a category, not a brand. Say you'd deliver through a provider API or your own SMTP infrastructure, then state the trade-off: control and IP reputation versus operational burden. Choosing a specific vendor invites a comparison debate you don't need and dates the answer. The interviewer is scoring whether you can make and justify a build-versus-buy decision.
How much detail on SMTP should I show if I've never built mail infrastructure?
Enough to show you know delivery is a conversation with an external server. Mention connection setup, the envelope sender and recipient, and that responses split into transient and permanent failures. You don't need command-level detail. If pushed, say you'd lean on a provider for the protocol layer and focus your design on queueing, retries and status.
What if the interviewer asks about attachments or large volumes mid-design?
Answer in one adjustment, then return to your thread. For attachments, store the blob separately and pass a reference through the queue. For large volume, add partitioning by recipient or tenant and scale workers independently of the API tier. Say what stays the same — the accept, queue, deliver, record path — so the interviewer sees your design bends rather than breaks.
How is this different from designing a notification system?
Email adds a delivery layer you don't control. A notification system fans out across channels and tracks user preferences; an email delivery service must handle bounces, complaints, a suppression list and sender reputation, because the receiving mail server can reject you permanently. The queue and retry skeleton is similar, but the failure handling is email-specific.
Do I need to discuss spam filtering and IP reputation?
Mention them as constraints, not as a design you'll build. Say that deliverability depends on sender reputation and authentication, and that using a provider delegates much of that. Then move on. Spending minutes on spam filtering signals you've lost the thread; one sentence shows you know the inbox is not guaranteed.
Practise your walkthrough out loud and review the recording.