CYART // SCHEMA · DEFENSE-LAYERS7 NODES · 7 LINKSBLOCKED HERETELEMETRYALERTTHREAT · Attacker — phish, creds, exploitTHREAT01Attackerphish, creds, exploitEDGE · Edge — WAF, DDoS, TLSEDGE02EdgeWAF, DDoS, TLSSERVICE · Identity — SSO, MFA, deviceSERVICE03IdentitySSO, MFA, deviceSERVICE · Application — input validation, authzSERVICE04Applicationinput validation, authzDATA · Data — encryption, DLP, KMSDATA05Dataencryption, DLP, KMSSTREAM · Detection — logs, EDR, SIEMSTREAM06Detectionlogs, EDR, SIEMSTREAM · Response — runbooks, isolate, rotateSTREAM07Responserunbooks, isolate, rotate

Design an email security gateway

Design the inbound mail filter that sits in front of 100,000 mailboxes: MX cut-over, SPF, DKIM and DMARC evaluation with alignment, URL rewriting with time-of-click checks, attachment sandboxing sized in VMs, quarantine, and a false-positive process users trust.

● MediumFREEDesign problem·18 min read·Intermediate → Advanced
email security gatewaySPF DKIM DMARCDMARC alignmentURL rewritingattachment sandboxingphishing

01Understand the problem and size it

✓What you will learn
  • Place the gateway in the mail flow with MX records and lock the mailbox provider so it cannot be bypassed
  • Evaluate SPF, DKIM and DMARC correctly, including alignment with the visible From domain
  • Design URL rewriting with time-of-click checks and attachment sandboxing, sized in messages per second and sandbox VMs
  • Run quarantine and false-positive handling without allow-lists that attackers can ride
◎Interview radar

What they probe: why SPF pass does not mean the sender is who the From line says, what happens to mail sent straight to the mailbox provider, how long sandboxing delays mail, why URLs are rewritten, how a user gets a wrongly quarantined invoice back. Where candidates slip: treating SPF as anti-spoofing, bouncing spam after acceptance, allow-listing by sender address, no plan for links weaponised after delivery.

An email security gateway (SEG) is an SMTP relay that receives a company's inbound mail first, inspects it, and forwards what is safe to the mailbox provider (Exchange Online, Google Workspace). The company points its MX record (the DNS record that tells senders where to deliver mail for a domain) at the gateway.

Functional requirements

  1. Receive all inbound mail for the company's domains over SMTP and deliver clean mail to the mailbox provider.
  2. Authenticate senders (SPF, DKIM, DMARC, ARC) and detect spoofing, lookalike domains and business email compromise (BEC).
  3. Rewrite URLs for time-of-click checks and sandbox unknown attachments.
  4. Quarantine suspicious mail with user and admin release, and remediate mail found malicious after delivery.

Non-functional requirements

  1. 100,000 mailboxes; added delivery latency < 30 s p95 for mail without attachments needing detonation.
  2. Never lose an accepted message: once we answer 250 OK, we own it.
  3. Phishing catch rate high, but false positive rate on business mail < 0.01 %.
  4. Scale with bursts (Monday 9 a.m., marketing blasts).

Back of the envelope

Sizingtxt
mailboxes                100,000
inbound per mailbox      100 messages / day (incl. spam)   = 10 M messages / day
average                  10 M / 86,400 s                   ≈ 116 messages / s
peak (x5)                                                  ≈ 580 messages / s
average size             75 kB                             -> 750 GB / day, ~70 MB/s at peak
messages with attachments  20 %                            = 2 M / day
unknown after hash cache + static AV   5 % of those        = 100,000 detonations / day
detonation rate          100,000 / 86,400                  ≈ 1.16 / s
sandbox time             180 s per sample
concurrent VMs           1.16 x 180                        ≈ 208 on average, ~1,040 at peak (x5)
spool (durable queue)    1 h of peak backlog: 580 x 3,600 x 75 kB ≈ 157 GB
▭On the whiteboard · Scope3 points
01
FR
SMTP in/out | SPF, DKIM, DMARC, ARC, BEC | URL rewrite + sandbox | quarantine + post-delivery pull
02
NFR
100k mailboxes | < 30 s p95 added | no loss after 250 | FP < 0.01 %
03
out
outbound DLP, mail archiving, the mailbox provider itself

02High-level design: the inbound pipeline

FigLayers of the inbound pipeline
CYART // SCHEMA · DEFENSE-LAYERS7 NODES · 7 LINKSBLOCKED HERETELEMETRYALERTTHREAT · Attacker — phish, creds, exploitTHREAT01Attackerphish, creds, exploitEDGE · Edge — WAF, DDoS, TLSEDGE02EdgeWAF, DDoS, TLSSERVICE · Identity — SSO, MFA, deviceSERVICE03IdentitySSO, MFA, deviceSERVICE · Application — input validation, authzSERVICE04Applicationinput validation, authzDATA · Data — encryption, DLP, KMSDATA05Dataencryption, DLP, KMSSTREAM · Detection — logs, EDR, SIEMSTREAM06Detectionlogs, EDR, SIEMSTREAM · Response — runbooks, isolate, rotateSTREAM07Responserunbooks, isolate, rotate
  • EDGE
  • SERVICE
  • DATA
  • STREAM
  • THREAT
  • Live flow
  • Lookup / async
//Mail passes connection-level checks, SMTP envelope checks, sender authentication, content and threat analysis, then policy, before delivery to the mailbox provider. Each layer is cheaper than the next, so most junk is dropped before the expensive stages.
  1. Connection: TLS (STARTTLS), connecting IP reputation and DNS blocklists, per-IP connection and rate limits. Reject here with a 5xx and the sender's own server generates any bounce.
  2. Envelope: valid recipient check (RCPT TO against the directory, so mail to non-existent users is refused, not bounced later), size limits.
  3. Spool: write the full message to a replicated durable queue and only then answer 250 OK.
  4. Authentication: SPF, DKIM, DMARC, ARC; results stamped into an Authentication-Results header.
  5. Content and threat: spam and phishing classifiers, BEC and impersonation checks, URL analysis and rewriting, attachment static analysis, sandbox for unknowns.
  6. Policy and delivery: deliver, deliver with banner, quarantine, or drop; relay to the mailbox provider over TLS on a connector that accepts only our IPs.

SPF, DKIM, DMARC: what each one proves

CheckStandardProvesDoes not prove
SPFRFC 7208The connecting IP is authorised to send for the envelope sender domain (MAIL FROM, or HELO)Anything about the visible From header; breaks on forwarding; max 10 DNS lookups
DKIMRFC 6376The signing domain (d=) signed these headers and body, unchanged in transit; key at selector._domainkey.domainThat d= matches the From header
DMARCRFC 7489The visible From domain aligns with a passing SPF or DKIM domain; tells you the owner's policy (p=none/quarantine/reject)That the sender is honest; a lookalike domain can pass its own DMARC
ARCRFC 8617A chain of signed authentication results from intermediaries (mailing lists, forwarders)Anything if you do not trust the sealing intermediary
Records and the result headertxt
; DNS published by the sender domain
example.com.                  TXT "v=spf1 include:_spf.google.com ip4:203.0.113.0/24 -all"
s1._domainkey.example.com.    TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqh...IDAQAB"
_dmarc.example.com.           TXT "v=DMARC1; p=reject; rua=mailto:dmarc@example.com; adkim=r; aspf=r"

; Header our gateway adds after evaluation (RFC 8601)
Authentication-Results: mx1.gw.cyart.io;
  spf=pass smtp.mailfrom=bounce.example.com;
  dkim=pass header.d=example.com header.s=s1;
  dmarc=pass (p=reject) header.from=example.com

; A spoof that passes SPF but fails DMARC
MAIL FROM:<x@attacker.net>       -> spf=pass smtp.mailfrom=attacker.net
From: "CEO" <ceo@cyart.io>       -> dkim=none, no aligned domain
                                  -> dmarc=fail (p=reject) header.from=cyart.io

Alignment is the key idea: with relaxed alignment (aspf=r, adkim=r), bounce.example.com aligns with example.com because they share an organisational domain. The attacker in the last example passes SPF for their own domain, but nothing aligns with cyart.io, so DMARC fails and the domain owner's p=reject tells us to refuse it.

▭On the whiteboard · Pipeline3 points
01
edge
TLS, IP reputation, rate limits, recipient check, reject in-session
02
own it
durable spool before 250 OK
03
inspect
auth results → classifiers → URLs → attachments → policy → deliver

03Deep dives: URLs, attachments, quarantine

URL rewriting and time-of-click

Attackers send links that are clean at delivery and weaponise them hours later, after the gateway has scanned them. So the gateway rewrites every URL to point at its own click service, which checks the destination when the user clicks: reputation, a fresh crawl in an isolated browser, lookalike detection, and the policy for that user.

Rewritten link and click-time flowtxt
original : https://docs.vendor-invoices.com/inv/8841
rewritten: https://click.gw.cyart.io/v2/r?u=aHR0cHM6Ly9kb2NzLnZlbmRvci1pbnZvaWNlcy5jb20vaW52Lzg4NDE
           &m=4f2a9c...  (message id)  &r=jdoe  &sig=HMAC-SHA256(key, u|m|r)[:16 bytes, base64url]

click service on GET:
  1. verify sig; reject if invalid       -> never an open redirect
  2. decode u, re-check verdict (cache 5 min), detonate in isolated browser if unknown
  3. clean   -> 302 to original
     unknown -> interstitial warning or open in remote browser isolation
     bad     -> block page, log click by (message, recipient), alert SOC
!Unsigned rewrites become an open redirect

If the click service redirects to any u= parameter, attackers use your trusted domain to launder their phishing links. Sign the URL together with the message and recipient and refuse anything that does not verify.

Attachment sandboxing

  • Cheap first: hash lookup against known good and known bad, then static analysis (file type by magic bytes, macros, embedded objects, archive contents). Most attachments never reach the sandbox.
  • Detonate unknowns in instrumented VMs (Windows with Office, a PDF reader, a browser) for about 3 minutes, watching for process launches, network calls and file drops. Sized above: around 200 VMs on average, 1,000 at peak, so autoscale and cap per tenant.
  • Delay trade-off: holding the whole message for 3 minutes annoys users. Dynamic delivery sends the body immediately with a placeholder and attaches the file once clean.
  • Password-protected archives cannot be inspected; try passwords found in the message body, otherwise quarantine with a banner or block by policy.

Quarantine and post-delivery remediation

  • Quarantine is a store keyed by message, with the verdict, reasons and the original raw message, kept 30 days.
  • Users get a daily digest and can release low-risk categories (bulk, spam); phishing and malware need admin release.
  • When a verdict changes after delivery (a URL turns bad, a sandbox result arrives late, a user reports phishing), the gateway pulls the message from mailboxes through the provider's API and records who had opened it or clicked.

04False positives, failure modes and trade-offs

False positives without weakening the filter

  • Allow-list entries must require authentication: "allow vendor.com when DMARC passes", never "allow From: vendor.com", which any spoofer can write.
  • Release requests and "not junk" reports feed a review queue and the classifiers, with per-tenant thresholds.
  • Track false positives per rule and per model version; a rule that quarantines invoices from one supplier gets fixed, not allow-listed globally.
  • Show users why in the quarantine view ("external sender impersonating an executive") so they can judge.
iReject in-session, never bounce later

If you accept a message and later bounce it, the bounce goes to the forged envelope sender: an innocent third party. That is backscatter, and it gets your gateway blocklisted. Decide spam at SMTP time with a 5xx, or accept and quarantine silently.

Failure modes

FailureBehaviourWhy
Gateway region downMultiple MX records with priorities across regions; senders retry for daysSMTP's retry is a built-in buffer
Mailbox provider unreachableSpool holds mail and retries; alert at 15 min backlogWe already said 250 OK
Sandbox saturatedDynamic delivery holds attachments longer; never release unscanned filesFail safe on the dangerous part only
Direct-to-provider deliveryProvider connector accepts only gateway IPs or a certificateOtherwise attackers skip the gateway via the provider's own MX host
DNS timeouts on SPF/DKIMResult temperror; do not treat as fail or pass; score as neutralAvoid quarantining good mail on resolver blips

Trade-offs to state

ChoiceGainCost
Gateway in front (MX) vs API-based scanning inside the mailboxBlocks before delivery, works with any providerExtra hop, MX change, bypass risk if the provider is not locked down
URL rewritingTime-of-click protection, click telemetryBreaks some links and signatures, users see odd URLs
Dynamic deliveryFast mail flowUsers see placeholders, more complexity
Strict DMARC enforcementKills exact-domain spoofingMisconfigured legitimate senders get rejected; mitigate with ARC and per-sender overrides that still need DKIM

05Final design, follow-ups and self-test

▭On the whiteboard · Final design3 points
01
flow
MX to gateway in two regions, durable spool before 250, provider locked to our IPs
02
auth
SPF, DKIM, DMARC with alignment, ARC for forwarders, results in Authentication-Results
03
threat
signed URL rewrite + click-time check, hash → static → sandbox with dynamic delivery, quarantine + post-delivery pull
“How to say it in the room

"The MX points at the gateway in two regions and the mailbox provider only accepts mail from us, so there's no bypass. We reject cheaply in the SMTP session, spool durably before saying 250, then authenticate: SPF only covers the envelope sender, so the real anti-spoofing check is DMARC alignment against the visible From. Links are rewritten to a signed click service because they get weaponised after delivery, and unknown attachments go to a sandbox, about 200 VMs on average for 100k mailboxes, with dynamic delivery so the body isn't held. Quarantine has user release for spam, admin release for phishing, and verdicts that change later trigger a pull from mailboxes."

Q1How do you handle mail from a mailing list that breaks DKIM by adding a footer?+

Trust ARC seals from known intermediaries; the list's ARC chain shows DKIM passed on arrival. Without a trusted ARC chain, treat it as a DMARC failure under the owner's policy.

Q2How do you catch BEC that has no link and no attachment?+

Impersonation features: display name matches an executive but the domain is external, lookalike domains (edit distance, homoglyphs), first-time sender, reply-to differs from From, urgency and payment language. Add a banner or quarantine.

Q3A user reports a phish that reached 400 inboxes. What happens?+

The report opens a case, the verdict updates, the gateway searches for the same sender, URLs and hashes across the tenant and pulls all copies via the provider API, then lists who clicked from the click logs.

Q4Why not just run the sandbox on every attachment?+

Cost and latency: 2 M attachments a day at 3 minutes each is about 4,200 concurrent VMs on average. Hash and static filtering remove most of them first.

Test yourself

A message has `MAIL FROM:<x@attacker.net>` (SPF passes for attacker.net) and `From: ceo@cyart.io`, with no DKIM signature. cyart.io publishes `p=reject`. What should the gateway do?

Finished this one?
Tick it and it shows as done on the roadmap and the course.