dnsemail securitysmtp

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.

2026-06-2010 min read

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 returns permerror and the check hard-fails. Fix it by inlining static ip4 ranges instead of includes, or use a flattening service carefully — flattening has its own spoofing trade-offs.
  • →The +all footgun. +all means "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-Signature header, 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) and r (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

terminal
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":

terminal
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:

terminal
# 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:

terminal
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.