SPF, DKIM, and DMARC End to End
Introduction¶
SPF, DKIM, and DMARC together answer one question for a receiving mail server: "is this message really from the domain in the From: header, and what should I do if it isn't?" Getting them wrong bounces your own newsletters; getting them right stops most spoofing. Here's how they fit and a rollout that's safe.
The three records¶
SPF — which servers may send¶
A TXT record at the domain apex listing authorised sending IPs:
example.com TXT "v=spf1 include:_spf.google.com ip4:203.0.113.10 ~all"
The receiver checks the envelope sender (MAIL FROM, aka Return-Path)
domain's SPF against the connecting IP. ~all = soft-fail (accept but mark),
-all = hard-fail. SPF breaks on forwarding — the forwarder's IP isn't in
your record — which is why DMARC also considers DKIM.
Limit: max 10 DNS lookups total (each include, a, mx counts). Exceed
it and SPF returns permerror. Use the SPF generator to
count them.
DKIM — a cryptographic signature¶
Your outbound server signs selected headers + body with a private key. The public key is in DNS:
sel1._domainkey.example.com TXT "v=DKIM1; k=rsa; p=MIIBIjANBg..."
The receiver fetches that key, verifies the signature. DKIM survives forwarding (the signature travels with the message) as long as the body and signed headers aren't modified. Generate the keypair with the DKIM generator.
DMARC — the policy and the reports¶
A TXT record at _dmarc.example.com:
_dmarc.example.com TXT "v=DMARC1; p=none; rua=mailto:[email protected]; adkim=r; aspf=r"
DMARC passes if SPF or DKIM passes AND is aligned. Alignment means the
domain that passed matches the From: header domain:
- SPF alignment — the Return-Path domain matches
From:(relaxed = same organisational domain; strict = exact). - DKIM alignment — the
d=in the signature matchesFrom:.
A message can pass raw SPF/DKIM for some other domain and still fail DMARC
because nothing aligned with From:.
p=none monitors only. p=quarantine → spam folder on failure.
p=reject → bounce. pct= ramps it (pct=25 applies the policy to a quarter
of failing mail). Build the record with the
DMARC generator.
A safe rollout¶
- Publish SPF with
~all(not-allyet). Include every real sender: your mail server, Google/M365, your ESP (SendGrid, Mailgun), your ticketing system, monitoring alerts. Verify with the SPF checker. - Enable DKIM signing on every outbound path. Each ESP has its own selector and key — add all of them. Verify with the DKIM checker.
- Publish DMARC
p=nonewithrua=. Wait 1–2 weeks and read the aggregate reports (a parser or a service like Postmark's free DMARC tool). They tell you every source sending as your domain and whether it aligns. - Fix the gaps the reports reveal — a forgotten SaaS tool, a subdomain, a marketing platform not signing.
- Move to
p=quarantine; pct=25, thenpct=100, watching reports at each step. - Move to
p=reject. Now tighten SPF to-all. - Consider BIMI once you're at
p=quarantine+ — verify with the BIMI checker.
Never jump straight to p=reject. You will have a sender you forgot about.
Verification and troubleshooting¶
dig +short TXT example.com | grep spf1
dig +short TXT sel1._domainkey.example.com
dig +short TXT _dmarc.example.com
# Send a test to a checker address and read the auth results, or:
# (in a received message header)
# Authentication-Results: mx.google.com;
# spf=pass ... dkim=pass header.d=example.com dmarc=pass
- DMARC fails but SPF and DKIM both "pass" — alignment. The passing domain
isn't your
From:domain. Common with ESPs that use their own Return-Path; fix by setting a custom Return-Path/CNAME on your domain, or rely on DKIM alignment (d=example.com). - SPF
permerror— over 10 lookups. Flatten includes to IPs or drop unused senders. - DKIM
failintermittently — a mailing list or forwarder rewrites the Subject or footer, breaking the body hash. This is expected; DMARC still passes if SPF aligns, or the list should use ARC. - Your newsletter goes to spam after
p=reject— the ESP isn't aligned. Set up the ESP's domain-authentication (custom CNAMEs) so DKIMd=matches. - No aggregate reports arriving —
rua=address wrong, or the mailbox domain's DMARC blocks the reports. Use a dedicated address. - Subdomain mail rejected — DMARC's
sp=(subdomain policy) inheritsp=unless set. Addsp=nonewhile you sort subdomains out.
Related tools and reading¶
- On-site: SPF Checker / Generator, DKIM Checker / Generator, DMARC Checker / Generator, Deliverability Test.
- Related posts: Postfix as a null client.
Stuck on something this site can't fix?Reach out to Prabath directly on LinkedIn.More in Web & Mail Servers
Running BIND 9 as an Authoritative Server
BIND as an authoritative server: zone files, secured AXFR with TSIG, SOA serial rules, and DNSSEC inline-signing. Here's a working master/slave setup.
October 24, 2026Varnish Cache in Front of a Site
Varnish is a caching HTTP accelerator configured in VCL. Here's the request lifecycle, why you strip cookies, how bans work, and grace mode for serving stale during backend trouble.
October 24, 2026Let's Encrypt with Certbot, Including Renewal That Doesn't Break
Getting the first cert is easy; keeping renewal working for years is the part people get wrong. Webroot vs DNS-01, deploy hooks, and the failure modes.
October 24, 2026