# Low Level Design: Newsletter Service

Source: https://www.techinterview.org/post/3233471958/lld-newsletter-service/
Updated: 2026-04-18 · techinterview.org

## What Is a Newsletter Service?

A newsletter service lets product teams send bulk email campaigns to segmented subscriber lists. It handles subscription management, campaign scheduling, batch delivery, tracking, and deliverability — at scale, reliably, and without hammering the ESP rate limits.

## Functional Requirements

- Subscribe / unsubscribe / re-subscribe users

- Create and schedule campaigns with rich HTML or plain-text content

- Send campaigns to full lists or filtered segments

- Track opens, clicks, bounces, and unsubscribes per campaign

- Honor unsubscribes immediately (CAN-SPAM / GDPR)

- Provide aggregated deliverability and engagement dashboards

## Non-Functional Requirements

- Send millions of emails per campaign within a reasonable time window

- Idempotent sends — no duplicate delivery on retry

- Unsubscribe processing must be near-real-time

- Dashboard queries should be fast (pre-aggregated)

- High availability for subscription API; eventual consistency for analytics

## Core Entities

| Entity | Key Fields |
| --- | --- |
| Subscriber | id, email, status ('active'|'unsubscribed'|'bounced'), subscribed_at, list_ids |
| List | id, name, description, created_at |
| Campaign | id, list_id, subject, body_html, body_text, status ('draft'|'scheduled'|'sending'|'sent'), scheduled_at |
| Send | id, campaign_id, subscriber_id, status ('queued'|'delivered'|'bounced'|'failed'), sent_at |
| Event | id, send_id, type ('open'|'click'|'bounce'|'unsubscribe'), occurred_at, metadata |

## High-Level Architecture

The system splits into three planes: the **Subscription API**, the **Campaign Sender**, and the **Event Processor**.


```
Client
  |
  v
Subscription API (REST)
  |-- Subscriber DB (Postgres)
  |-- List DB (Postgres)

Campaign Scheduler (cron / admin UI)
  |-- Campaign DB (Postgres)
  |-- Segment query -> Subscriber DB
  |-- Enqueue sends -> Send Queue (Kafka / SQS)

Send Workers (horizontally scaled)
  |-- Dequeue from Send Queue
  |-- Check unsubscribe / suppression list (Redis set)
  |-- Call ESP (SendGrid / SES) via HTTP
  |-- Write send status -> Send DB

ESP Webhook Receiver
  |-- Ingest bounce / open / click / unsub events
  |-- Publish to Event Queue (Kafka)

Event Consumer
  |-- Update Send status
  |-- Update Subscriber status (bounced / unsubscribed)
  |-- Increment campaign counters (Redis)
  |-- Write raw events to analytics store (ClickHouse / BigQuery)

Dashboard API
  |-- Read from analytics store
```


## Subscriber List Management

Subscribers belong to one or more lists. Segmentation is a query-time filter (e.g., `status = 'active' AND list_id = X AND country = 'US'`). For very large lists, the campaign scheduler pages through the subscriber table with a cursor and writes batches of (campaign_id, subscriber_id) rows into the send queue rather than loading everything into memory.

## Campaign Scheduling and Batch Sending

A cron job checks for campaigns where `scheduled_at <= NOW()` and status is `'scheduled'`. It atomically transitions the campaign to `'sending'` (optimistic lock or `SELECT FOR UPDATE`) and fans out send tasks to the queue. Workers pull tasks and call the ESP. Each task carries a unique idempotency key (`campaign_id + subscriber_id`) to prevent double-send on retry.

## Unsubscribe Handling

Every email contains a one-click unsubscribe link with a signed token (`HMAC(subscriber_id, campaign_id, secret)`). On click, the Subscription API flips the subscriber status to `'unsubscribed'` and adds the email to a Redis suppression set. Send workers check the suppression set before calling the ESP, so even queued messages that haven't been sent yet are dropped.

## Open and Click Tracking

Opens are tracked by embedding a 1x1 pixel image whose URL encodes the send ID (`/track/open/{send_id}`). Clicks are tracked by rewriting links to a redirect URL (`/track/click/{send_id}/{link_hash}`). Both endpoints log the event and redirect (clicks) or return the pixel (opens). Events flow through a lightweight append-only event service into ClickHouse for analytics.

## Deliverability Monitoring

Key metrics computed per campaign: delivery rate, open rate, click-through rate, bounce rate (hard vs. soft), and unsubscribe rate. Hard bounces automatically suppress the address. Soft bounces increment a counter; after N soft bounces the address is suppressed. Spam complaint rates from ESP feedback loops are monitored; high rates trigger campaign pausing and alerts.

## Scaling Considerations

- **Fan-out bottleneck:** Use cursor-based pagination when generating send tasks; never load a full list into memory.

- **ESP rate limits:** Control concurrency of send workers per ESP account; use token-bucket throttling.

- **Multiple ESP accounts:** Shard sends across accounts/domains to distribute reputation and throughput.

- **Analytics write throughput:** Buffer events in Kafka before writing to ClickHouse; avoid write amplification on the campaign counters table.

- **Suppression list lookup:** A Redis set or Bloom filter gives O(1) lookups at high throughput.

## Interview Talking Points

- Why separate the send queue from the campaign scheduler? (decoupling, back-pressure, retry isolation)

- How do you guarantee exactly-once delivery? (idempotency key at ESP call; send status written atomically)

- How do you handle a campaign to 10M subscribers? (fan-out cursor, worker pool, multi-account ESP sharding)

- How do you comply with CAN-SPAM / GDPR in real time? (suppression set checked before every send)

- How do you prevent a noisy campaign from destroying deliverability? (circuit-breaker on complaint rate)

See also: [Scale AI Interview Guide 2026: Data Infrastructure, RLHF Pipelines, and ML Engineering](https://www.techinterview.org/post/3233460275/scale-ai-interview-guide-2026-data-infrastructure-rlhf-pipelines-and-ml-engineering/)

See also: [Netflix Interview Guide 2026: Streaming Architecture, Recommendation Systems, and Engineering Excellence](https://www.techinterview.org/post/3233460274/netflix-interview-guide-2026-streaming-architecture-recommendation-systems-and-engineering-excellence/)

See also: [LinkedIn Interview Guide 2026: Social Graph Engineering, Feed Ranking, and Professional Network Scale](https://www.techinterview.org/post/3233460278/linkedin-interview-guide-2026-social-graph-engineering-feed-ranking-and-professional-network-scale/)
