SPF, DKIM, DMARC — What They Actually Do and How to Break Them
Not just definitions — a practical look at how email authentication works at the packet level, and what happens when each record is misconfigured.
Most explanations of SPF, DKIM, and DMARC stop at "add these TXT records and email is secure." That's not wrong, but it hides the parts that actually matter to a researcher: what each protocol does and doesn't verify, and the specific ways each one quietly breaks.
This is the packet-level view — and the failure modes.
The Mental Model
Three protocols, three different questions:
- →SPF asks: is this server allowed to send for the envelope-from domain?
- →DKIM asks: was this message signed by the private key behind the header
d=domain, and has it been altered since? - →DMARC asks: do SPF/DKIM actually line up with the domain the human sees in the From header — and if not, what should the receiver do?
None of them, on its own, proves the visible sender is legitimate. That gap is where the whole game is played.
SPF — Envelope Sender, Not the From Header
SPF is evaluated against the SMTP MAIL FROM (the envelope sender, visible in the Return-Path), not the From: header a user reads. That distinction surprises people and is exactly why SPF alone is trivially spoofable: an attacker can put your brand in the From: header while the envelope sender is a domain they control and SPF happily passes.
A record like v=spf1 include:_spf.example.com ip4:1.2.3.4 -all is a small program. include chains to another domain's SPF, ip4/ip6 allow literal addresses, and the qualifier +/-/~/? sets the verdict.
The failure modes
- →The 10-lookup limit. SPF allows at most 10 DNS lookups per check. Chain enough
includes (common once a SaaS provider layers CRM, marketing, and support tools) and you cross 10 — the receiver returnspermerrorand the check hard-fails. Fix it by inlining staticip4ranges instead of includes, or use a flattening service carefully — flattening has its own spoofing trade-offs. - →The
+allfootgun.+allmeans "any server on the internet is authorised." It appears in misconfigured zones constantly. Use-all(hard fail) once you're sure your senders are complete. - →Forwarders break it. When a mailing list or forwarder re-sends your mail from a different IP, SPF can fail because the new sender isn't in your list. This is alignment, and it's DKIM/DMARC's job, not SPF's.
DKIM — A Cryptographic Seal on Headers and Body
DKIM hashes selected headers plus the body, signs that hash with the domain's private key, and drops the signature into a DKIM-Signature header. The receiver extracts the d= (domain) and s= (selector) tags, queries s._domainkey.d in DNS for the public key, and verifies. bh= covers the body; b= covers the signed headers.
The failure modes
- →Signature stripping in transit. Naive relays and mailing lists can remove or reformat the
DKIM-Signatureheader, or a proxy that edits the subject line will change a signed header and blow the verification. Nothing is "hacked" — the seal is just broken by normal handling. - →Selector hygiene. Keys live under selectors (
default,s1,google). If you decommission a sending service and leave an old selector pointing at a leaked key, you've published an attacker's signing key under your own domain. Audit selectors like you audit subdomains. - →Sub-key disclosure via logging. The signature is in a header, so anything that logs full headers (proxies, debug relays, mail archiving tools) leaks your signed messages. Not a break, but a real operational footgun worth calling out in a report.
DMARC — The Protocol That Ties It Together
DMARC is the layer that finally compares the authentication results against the domain in the visible From: header. A message passes DMARC only when it passes SPF and aligns, or passes DKIM and aligns.
Alignment is the whole point
- →SPF alignment compares the envelope domain to the From domain.
- →DKIM alignment compares the
d=domain to the From domain. - →Two modes:
s(strict — exact domain match) andr(relaxed — same organisational domain, subdomains allowed).
Real attack pattern: a message can pass SPF and DKIM yet still fail DMARC if neither domain aligns with the From header. Plenty of "authentication passed" phish live right here — technically signed, but by a domain that isn't the brand in the header. That's the signal DMARC gives receivers to apply your p=quarantine or p=reject policy.
The escalation path
p=none # monitor only — you get aggregate (rua) reports, nothing is rejected
p=quarantine # move failures to spam
p=reject # bounce failures
Go none → quarantine → reject only after reading your DMARC reports, because jumping to reject while a legitimate third-party sender (your billing tool, your CRM) isn't aligned will bounce real mail. Aggregate XML reports show you every source sending as your domain and whether it authenticates — that's the data you escalate on.
Building a Lab to See This Yourself
You don't need much to watch this happen. Start from a correct send, then break each piece and read the difference.
Here's a real message from my production setup (Postfix → Brevo relay, SPF/DKIM/DMARC configured), read through Gmail's "Show original":
From: 0xvince <0xvince@vincentiwuno.me>
Subject: Hello from 0xvince welcome
mailed-by: hb.d.sender-sib.com # the envelope/relay domain (Brevo's infra)
signed-by: vincentiwuno.me # the DKIM d= domain — aligns with From
Security: Standard encryption (TLS)
That mailed-by vs signed-by split is the alignment story in plain English. Gmail tells you the mail physically left Brevo's infrastructure (mailed-by) but was signed by vincentiwuno.me (signed-by) — the same domain the human sees in From. DMARC's whole job is to enforce that the signing domain aligns with the visible sender, and here it does, so the authentication actually means something.
Now break it on purpose and watch the verdict change:
# SPF hard-fail: send from a server not listed in the domain's SPF record
swaks --to you@gmail.com --from lab@yourdomain.com --server some-unlisted-host:25
# "Passes but doesn't align": DKIM verifies against a d= domain that is NOT the
# From domain — the classic authenticated-spoof shape.
Open "Show original" again and read the raw Authentication-Results: header. A misaligned send comes back looking like this:
Authentication-Results: mx.google.com;
spf=fail (sender IP is not authorised) smtp.mailfrom=<unlisted-host>;
dkim=pass header.d=<some-other-domain>;
dmarc=fail action=oreject header.from=<your-brand>
dkim=pass is genuine — but the d= domain doesn't line up with From, so dmarc=fail. The mail is cryptographically valid and still rejected, because it isn't yours. That one header is the clearest proof of why SPF and DKIM alone aren't enough, and why DMARC is the layer that ties them to what the reader actually sees.
What I Learned
The three protocols aren't redundant checks of the same thing — they answer different questions and fail in different ways. SPF is about the sending server, DKIM about message integrity, and DMARC about whether either actually corresponds to the domain the human sees. Most people stop at "I added the records." The research starts when you deliberately break each one and watch the verdict headers change.