InterviewKata
System design · Worked design D37 of 46 · Social and content · Long form

Design an email service

Design a large email provider like Gmail or Outlook.com: hundreds of millions of mailboxes, mail arriving from the whole internet over a protocol from 1982, most of it spam, and users who expect search across years of mail to be instant on every device.

1. The prompt

"Design an email service: users send and receive email with anyone on the internet, organise it with labels or folders, search it, and use it on the web and on phones."

What makes it hard:

2. Frame the problem

How many users and messages?

About 500 million accounts; 20 billion incoming messages a day, most of them spam; 1 billion legitimate deliveries to inboxes; 300 million sent.

Spam dominates inbound volume: filtering must be cheap and happen before storage.

How much storage per user?

A quota of 15 GB; average use around 2 GB.

500 M × 2 GB ≈ 1 EB. Bodies and attachments belong in object storage, not a database.

Folders or labels?

Labels: one message can have several.

A message is stored once, with a set of label ids; "folders" are a view.

Conversation threading?

Yes, group replies into threads.

Thread ids are computed at delivery from headers (References, In-Reply-To) and subjects.

Which clients?

Web, mobile apps, and third-party clients over IMAP.

We need a sync protocol with change tracking, plus push for new mail.

Search?

Full text over all of a user's mail, results in under a second.

An inverted index per user (or per partition of users), updated at delivery.

Security expectations?

Encryption in transit and at rest; protection against phishing and spoofing; account takeover defences.

Sender authentication (SPF, DKIM, DMARC) is part of the inbound pipeline.

3. What it must do

  1. A user receives email from anyone on the internet, filtered for spam and malware, in their inbox within seconds.
  2. A user sends email to anyone, and it's delivered (or they learn why not).
  3. A user reads, labels and searches their mail on any device, kept in sync.

Not now: calendar and contacts, end-to-end encryption, mailing-list hosting, ads.

4. How well it must do it

TargetWhy this number
Never lose an accepted message: once we answer SMTP "250 OK", it's durable data safetyThe sender deletes its copy when we accept; losing it then loses it for good.
Delivery to the inbox within 10 s at p99 after acceptance speedPeople wait for verification codes.
Spam and phishing kept out of the inbox (well over 99%), with very few legitimate messages misfiled securityA missed bank email is worse than one spam message.
Search under 500 ms p99 over years of mail speedSearch replaced folders for most users.
Availability 99.9%+ for reading; inbound mail queues briefly rather than bounces surviving failuresSMTP senders retry for days, so short inbound outages delay mail but don't lose it.

5. Numbers that change the design

QuantityWorking→ so we…
Inbound connections20 B messages a day ≈ 230,000/s average, peaks ~3×→ so cheap rejection (IP reputation, rate limits) happens at the edge, before the message body is even accepted
Storage500 M users × 2 GB ≈ 1 EB; bodies average ~75 KB, attachments far larger→ so bodies and attachments go to object storage (D35), compressed; metadata and indexes stay in databases
Duplicate attachmentsThe same PDF sent to 50 colleagues→ so attachments are stored content-addressed (by hash) and deduplicated
Per-user dataA heavy user has 500,000 messagesEverything is naturally partitioned by user → so we shard by user id; one user's mailbox lives in one partition

Illustrative numbers. Skipped: send volume (small compared with inbound).

6. The nouns

message        (user_id, message_id) → thread_id, labels[], flags, received_at, size, blob_ref, snippet
blob           sha256 → compressed body or attachment bytes             (object storage, shared across users)
thread         (user_id, thread_id) → subject, message_ids[], last_activity
change_log     (user_id, modseq) → kind (added | labels_changed | deleted), message_id
search_index   per user partition: term → postings of message_ids

7. The contract

Internet-facing
  SMTP (port 25): receive from other providers;  STARTTLS, MTA-STS for encryption policy
  SMTP submission (port 587): our users' clients send through us, authenticated
  IMAP: third-party clients

Our apps (JMAP-style JSON API)
  GET  /v1/mailboxes/me/messages?label=INBOX&page_token=…          → summaries
  GET  /v1/messages/{id}                                        → full message
  POST /v1/messages/{id}/labels   {add[], remove[]}
  GET  /v1/search?q=invoice from:acme after:2025-01-01
  GET  /v1/changes?since_modseq=8841                             → changes, new modseq
  POST /v1/messages:send   {to[], subject, body, attachments[]}  Idempotency-Key: …
  Push: a WebSocket or mobile push "mailbox changed" signal; clients then fetch changes

The user comes from the session token. Sync is "give me everything since change number N", which works for a phone that was offline for a minute or a month.

Data flow (inbound): SMTP edge (reputation, rate limits) → accept into a durable queue → authenticate sender (SPF, DKIM, DMARC) → spam and malware scoring → store blobs → write message metadata and change log → index for search → push to devices.

8. First working version

SMTP servers, a durable delivery queue, a filtering stage, mailbox storage sharded by user, a search indexer, and an API with sync and push.

8.1 Receiving a message

The SMTP server says "250 OK" only after the message is written to a replicated queue: that's the durability promise. Everything after (filtering, storage, indexing) runs from the queue and can retry.

8.2 Sending a message

Outgoing mail is signed with DKIM, put on an outbound queue per destination domain, and delivered over SMTP to the recipient's provider (found through its MX record). Temporary failures are retried with backoff for up to a few days; permanent ones produce a bounce message to the sender.

8.3 Reading and syncing

A client lists the inbox from message metadata (labels, snippet, date) and fetches bodies from object storage only when opened. Every change bumps the mailbox's change number; devices ask for changes since their last number, so a label applied on the laptop shows up on the phone.

Parked for laterspam and spoofing (9.1, 9.2) · an exabyte of mail (9.3) · search (9.4) · getting our mail delivered (9.5) · sync and push at scale (9.6).

9. Make it hold up

9.1 Filtering 20 billion messages a day security · cost

ApproachWhy
✗ BadAccept everything, store it, then run one big classifierWe'd store and process billions of spam messages a day.
~ GoodA classifier before storageSaves storage, but every spam connection still costs a full SMTP conversation and body transfer.
✓ GreatA funnel: reject by IP reputation and rate limits at connection time; check sender authentication; then content scoring (machine learning, URL and attachment scanning); finally per-user signals ("report spam", contacts)Each stage is cheaper than the next and removes most of what reaches it. User feedback trains the models.

The threshold between "inbox" and "spam folder" trades missed spam against misfiled real mail; that trade-off is tuned per message category, and messages that fail authentication for a domain that publishes a strict policy are treated much more harshly.

9.2 Who really sent this? security

Try the scenarios in the lab in section 13: forwarding breaks SPF but usually not DKIM; a mailing list that edits the subject breaks DKIM.

9.3 An exabyte of mail cost · data safety

ApproachWhy
✗ BadMessages as rows in a relational databaseExabytes of large text and binary in a database is slow and very expensive.
~ GoodA file per user mailbox (mbox/maildir) on file serversSimple, but hard to replicate, search or share across users.
✓ GreatSplit metadata from content: metadata and labels in a database sharded by user; bodies and attachments compressed in object storage, content-addressed so identical attachments are stored once; older mail moved to colder tiersEach part on the storage that suits it; deduplication and tiering cut cost; durability from the object store's replication or erasure coding.

Deduplicated blobs need reference counting (or periodic mark-and-sweep) so a shared attachment is deleted only when no mailbox references it.

Build an inverted index per user (or per small group of users in one index shard), updated asynchronously at delivery from the queue. Queries touch only one user's index, so they're small even when the total corpus is huge. Structured operators (from:, has:attachment, label:, dates) are fields in the same index. Recent mail is in a small, fast-updating segment; older segments are merged in the background, as in any search engine (Module 12).

9.5 Getting our mail delivered delivery

9.6 Sync and push for hundreds of millions of devices delivery speed

Devices don't poll every few seconds. Phones get a platform push notification; web clients hold a connection (WebSocket or long poll) to a gateway that subscribes to their user's change events. Either way, the signal only says "something changed", and the client fetches the delta from the change log. Change logs are trimmed after some weeks; a device that's further behind does a full resync.

9.7 The whole design after the deep dives

10. Interviewer follow-ups

A user receives 50,000 emails an hour (a misconfigured script).

Per-recipient rate limits at the edge return temporary failures (4xx), so senders retry later instead of filling the mailbox; quotas cap storage. The partition holding that user is protected from one hot mailbox.

Our inbound edge is down for an hour.

Sending servers retry for days, so mail is delayed, not lost. MX records list several sites so senders try another first.

How do you delete an account's data?

Delete metadata, indexes and change logs; decrement references on blobs and delete unreferenced ones; purge from backups on their retention schedule. Per-user encryption keys allow crypto-shredding.

Undo send.

Hold outgoing messages in the outbound queue for a short delay (say 10 seconds) before delivery; undo deletes it from the queue. Once handed to another provider, it can't be recalled.

A phishing campaign uses lookalike domains.

Authentication can't stop a domain that is genuinely someone else's. Content models, URL reputation, new-domain signals and warnings ("first message from this sender") do; user reports feed back quickly.

Why is the change log per user?

Sync, push and conflict handling are all per mailbox; a per-user sequence is cheap, ordered and easy to shard with the mailbox.

Ten times the users.

Mailbox shards, index shards and object storage grow horizontally; edge and filtering scale with traffic. The per-user design means no global bottleneck.

11. When things break

FailureWhat users seeHow we detect itWhat limits the damage
Inbound site lostDelayed mailSMTP health per siteMultiple MX sites; senders retry
Filtering stage slowMail arrives lateQueue depth and ageDurable queue absorbs it; scale filters
Mailbox shard downSome users can't read mailError rate per shardReplicated shards fail over; inbound queues until it's back
Search index behindNew mail missing from searchIndex lagRecent mail searched from metadata as a fallback
Our IPs blocklistedSent mail bounces at some providersBounce rates per destinationSeparate IP pools, outbound spam controls, delisting process
Spam waveSome spam in inboxesUser spam reports spikeFast model updates from reports; temporary rules

12. Wrap-up and the clock

Trade-offs we made:

What we'd watch: inbound queue age · time from acceptance to inbox (p99) · spam reports and "not spam" rescues · search latency and index lag · outbound bounce and deferral rates per destination · storage per user and dedup ratio.

At 10×: more shards everywhere; the per-user partitioning keeps it linear. Spam volume grows faster than users, so the funnel's early stages matter most.

A 60-minute interview

0–5Frame: users, inbound volume, storage, clients
5–10Must do, how well, numbers
10–15Nouns, protocols, inbound data flow
15–25First version: receive, send, read and sync
25–50Deep dives: filtering (9.1), authentication (9.2), storage (9.3)
50–60Search or sync, follow-ups, wrap-up

A 90-minute interview

0–8Frame, including labels and threading
8–15Must do, how well, numbers
15–22Nouns, protocols, data flow
22–35First working version
35–75Deep dives 9.1–9.6 and the final picture
75–85Follow-ups: floods, undo send, deletion
85–90Trade-offs, metrics, 10×
LevelWhat a strong answer shows
Mid-levelSMTP in and out, a queue, mailbox storage per user, labels, an API for clients.
SeniorDurable acceptance, a filtering funnel, SPF/DKIM/DMARC, metadata vs blob storage with dedup, per-user search indexes, change-log sync with push.
Staff+Sender reputation as a system to protect, the spam threshold as a product trade-off, storage tiering economics, account deletion across deduplicated blobs and backups, abuse from our own users.

Common mistakes:

13. Try it, check yourself, read more

Who sent this? An authentication lab. Pick a delivery scenario and see how SPF, DKIM and DMARC judge it. The visible From address is billing@bank.example, and bank.example publishes p=reject.

Simplified: real receivers also use ARC, reputation and content signals. "Aligned" means the authenticated domain matches the From domain (relaxed alignment allows subdomains).

When may the SMTP server reply 250 OK to a sender?

The sender deletes its copy after 250 OK.

When does DMARC pass?

Alignment ties authentication to the address the user actually sees.

Where should attachments be stored?

Exabytes of blobs belong in cheap, durable storage; dedup saves a lot.

How do devices stay in sync without polling?

Small signals, delta sync, and a full resync only when far behind.
ResourceWhy
RFC 5321: SMTPHow mail moves between servers, including retries and bounces.
SPF (RFC 7208), DKIM (RFC 6376), DMARC (RFC 7489), ARC (RFC 8617)Sender authentication, from the standards.
MTA-STS (RFC 8461)Requiring encryption between mail servers.
JMAP (RFC 8620) and JMAP for Mail (RFC 8621)A modern JSON sync protocol with change tracking.
Email sender guidelines (Google)What a large receiver requires of senders today.