Email authentication

An interactive guide to SPF, DKIM & DMARC

Every email arrives carrying three different sender names:

The envelope sender that mail servers use for routing and bounces, the signing domain embedded in a cryptographic signature, and the From: display header that a human being reads. They are set independently, by whoever operates the sending server, and they do not have to agree.

In the demonstration below you can press to collapse a real message down to what a mail client normally displays.

The MAIL FROM address is sent at the start of the SMTP conversation, before the message content. The DKIM-Signature header names which domain signed the message. Both are usually hidden, and only the From: line is visible. The underlying protocols, as designed in the 1980s, let anyone write anything into this field.

The three authentication mechanisms divide the work. SPF vouches for the amber name, DKIM vouches for the purple one, and DMARC chains both of them to the teal name you can see. We'll build each layer in turn.

SPF — who is allowed to send mail for this domain?

SPF is a single DNS TXT record. The owner of acme.com publishes a list of servers allowed to use acme.com in the envelope sender, and a receiving server checks whether the IP address that just connected is on the list.

The record is evaluated left to right. The include: instruction pulls in another domain's SPF record — because in practice nobody sends their own mail anymore. Google sends it, Mailchimp sends it, the CRM sends it. Each vendor brings its own record, and those records contain further includes.

Every include:, a, mx, exists: or redirect= costs one DNS query, and the standard imposes a hard budget of 10 lookups for the whole evaluation. Drag the services slider below and watch the lookup budget drain as ordinary vendors are added.

1

Seven perfectly normal SaaS vendors, and the record is dead. Past ten lookups the evaluation returns permerror and receivers treat the record as broken. Notice that plain ip4: blocks cost nothing: only mechanisms that trigger DNS queries count. That loophole is why domains with too many services resort to "SPF flattening" — replacing includes with their resolved IP blocks. The drawback is that flattened records silently rot when vendors rotate IP addresses, so usually this should be reserved to the services you control yourself.

SPF has a second, deeper limitation. When a message is forwarded, the forwarder's IP is not on the original domain's list, so SPF would fail on perfectly legitimate mail. And most importantly: SPF validated the amber name. The From: line your user reads was never examined.

DKIM — a signature that must survive the journey

DKIM attaches mathematics to the message itself. The sending server hashes the body, hashes a chosen set of headers, and signs the result with a private key. The matching public key sits in DNS at <selector>._domainkey.example.com so any receiver can verify:

signature = Signkey( H( canon(headers) ∥ body hash ) ), body hash = H( canon(body) )

The subtlety hides inside canon. Mail systems mangle messages in transit — they re-encode whitespace, unfold header lines, adjust trailing newlines — and a hash treats every mangled byte as forgery. So DKIM defines two canonicalization modes: simple hashes the bytes nearly as-is, while relaxed first collapses runs of whitespace and normalizes header names, tolerating cosmetic damage.

Below, the left column shows the message as it was signed; the right shows it as received. You can apply a few transformations that typical mail infrastructure performs, switch between and , and watch the recomputed hashes.

Try alone: under relaxed the signature survives, under simple it becomes invalid. Essentially everyone signs with relaxed/relaxed. Now try . A mailing list that appends three lines of unsubscribe boilerplate breaks every DKIM signature passing through it.

Note what a valid signature actually proves: that the domain in d= signed this exact content. Nothing stops an attacker from signing their message with a key for evil.com. DKIM, like SPF, can vouch for a name the recipient never sees.

DMARC — chaining the hidden names to the visible one

Now we have added authentication to two of the three sender names in use, but a competent attacker can still rent a server, point evil.com's SPF record at it, generate a DKIM key for evil.com, and send mail with From: billing@acme.com. SPF: pass. DKIM: pass. Both checks succeed and the forgery is perfect.

DMARC closes the loop with one rule, called alignment. A message passes DMARC if at least one of these holds:

SPF passed and the envelope domain matches the From: domain or DKIM verified and the d= domain matches the From: domain

In relaxed alignment the organizational domains must match (mail.acme.comacme.com); in strict mode the names must be identical.

What the receiver does with a fail is the domain owner's choice, published in a TXT record at _dmarc.<domain>:

Below you can try out the different variants. Pick a sending server, set all three sender names, and read the verdict.

In the preset both raw checks glow green — and both alignment arrows glow red, because neither authenticated domain has anything to do with acme.com. The attacker authenticated as themselves, which is exactly what DMARC forces them to do. The preset shows the mirror image: Mailchimp authenticating via its own mcsv.net fails DMARC too. This is the state before you complete their domain-authentication setup where you add the right DNS entries.

Where the policy lives — the DNS tree walk

When mail arrives from subdomains that publish no policy of their own, the receiver must find the nearest applicable record. For this we do a tree walk up the DNS hierarchy, capped at eight queries. Domains like com mark themselves psd=y meaning: public suffix domain, walk no further.

Click the domains below to add or remove DMARC records, then press and watch the receiver search upward from the sender's domain.

The first record found walking upward supplies the policy, and the record-bearing domain nearest the root — that isn't a public suffix — is treated as the organizational domain for relaxed alignment. Remove every record and the walk comes up empty: no DMARC policy at all, and receivers fall back to judging SPF and DKIM on their own, unaligned terms. This is why it is important as a domain owner to publish a DMARC record even on domains that send no mail at all.

The whole machine

This is everything: two authentication checks, one alignment rule, and the published policy. This is how a receiving email server decides which emails to reject outright.

1 / 6

The scenario is legitimate mail getting rejected: the list rewrote the envelope (so SPF passes only for the list's domain), appended its footer (killing the DKIM signature, as you demonstrated earlier), and left the From: untouched — so nothing aligns. Because of this, mailing lists use the ARC protocol: forwarders attach their own signed attestation of the authentication state they observed, letting receivers make an informed exception.

What this does not do

DMARC makes it expensive to forge one exact string: the domain after the @ in From:.

It does not protect against someone registering a similar domain like acme-billing.com, or a display name that says "Acme Billing" over a random address, or against a genuinely compromised mailbox at the real domain.