Skip to content
tezvyn:

Build a system to send 1M personalized emails in 2 hours

Source: coudo.aiHardHow cards are made

Build a system to send 1M personalized emails in 2 hours

This tests async distributed throughput and deliverability. Cover partitioned queues, auto-scaling workers, per-ESP rate limits, IP rotation, and exponential backoff with dead-letter queues. Red flags: synchronous sends, skipping IP warmup, or no retry logic.

What's really being asked

This question evaluates whether you can design a high-throughput, fault-tolerant distributed pipeline that interfaces with an external provider whose reliability and rate limits you do not control. The interviewer cares about backpressure, observability, deliverability reputation, and idempotency under a concrete SLA of one million emails in two hours, which is roughly 139 emails per second sustained, with bursts likely higher.

The full answer

First, an async ingestion layer, typically an API gateway that validates requests and drops them onto a partitioned message queue such as Kafka, RabbitMQ, or SQS, where partitioning by recipient domain or campaign ID prevents head-of-line blocking. Second, auto-scaling worker pools that consume from the queue in batches; workers should be stateless and horizontally scalable, with concurrency tuned to the ESP throughput limits. Third, multi-layer rate limiting using token buckets or leaky buckets at the gateway per sender, per ESP account, and per destination domain to avoid throttling and blacklisting. Fourth, IP warmup and rotation using a pool of dedicated IPs, starting with low volumes and gradually increasing to build sender reputation, then distributing load across the pool with round-robin or weighted rotation. Fifth, transient failure handling with exponential backoff and jitter for 5xx or 429 responses, a dead-letter queue for permanent failures like 4xx invalid addresses, and circuit breakers to stop hammering a degraded ESP endpoint. Sixth, idempotency keys so duplicate sends do not happen across retries.

The mistakes people make

Proposing a single monolithic application that synchronously calls the ESP API for each email will immediately fail on volume and latency. Ignoring IP warmup and sending a million emails from a cold IP will trigger spam filters and domain blacklisting. Treating all API errors as final without distinguishing 4xx client errors from 5xx server errors shows poor operational design. Overlooking queue partitioning leads to a single slow domain stalling the entire pipeline.

What usually comes next

How would you change the design if the ESP enforces a 100 emails per second hard cap? How do you prevent duplicate sends if a worker crashes mid-batch? How do you handle unsubscribe and bounce feedback loops in real time? What metrics would you alert on, and what are your SLOs for delivery latency?

A concrete example

Suppose your ESP returns a 429 Too Many Requests at 9:05 AM during a flash sale. Your worker should catch this, pause the specific partition for 30 seconds with exponential backoff, and requeue the batch while other workers continue processing different domains. Meanwhile, your circuit breaker opens after five consecutive 5xx errors, routing traffic to a secondary ESP or IP pool. If the same email ID is retried three times, the worker checks an idempotency store such as Redis before reattempting, ensuring the user receives exactly one message. Your monitoring stack tracks queue depth, send latency, bounce rate per IP, and ESP error codes, paging you if the queue depth exceeds a 15-minute processing buffer.

Interview question

How should the pipeline distinguish handling of a 4xx invalid-address error from a 5xx ESP timeout?

  • a.Treat both as final failures and drop the messages to avoid head-of-line blocking
  • b.Route 4xx errors to a dead-letter queue and retry 5xx errors with exponential backoff and jitterCorrect
  • c.Retry both error types with exponential backoff and jitter to ensure eventual delivery
  • d.Open a circuit breaker after any 5xx and immediately shift all traffic to a secondary ESP pool
Why?

4xx errors indicate permanent client failures like invalid addresses and should move to a dead-letter queue rather than consuming retry budget, while 5xx timeouts are transient and warrant exponential backoff with jitter. Retrying 4xx wastes throughput and risks reputation damage, whereas dropping 5xx loses valid emails.

Just read this? Test yourself on what you have been reading.

Read the original → coudo.ai

You just looked this up. Could you explain it out loud?

That is the part interviews actually test. Tezvyn takes questions like this one and gives you what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.

The iPhone app is on the way

We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.

Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.

Get it on Google PlayiPhone app coming soon

We are hiring for this. Open roles that interview on system design — each one lists the topics its interview covers.

See open roles