If you've ever set up a mail server, migrated email providers, or debugged why your transactional emails land in spam, you've bumped into SPF, DKIM, and DMARC. These three protocols form the backbone of email authentication — but most explanations either oversimplify them or drown you in RFCs.
This post is the guide I wish I'd had. We'll cover what each protocol does, how they interact, the most common misconfigurations, and how to verify them programmatically.
The Problem: Email Has No Built-in Identity
SMTP was designed in 1982. It has no concept of verifying who's sending a message. Anyone can set the From: header to ceo@yourcompany.com and send mail from any server. That's not a bug — it's how the protocol works.
SPF, DKIM, and DMARC were bolted on over the years to fix this. Each solves a different part of the problem:
- SPF — "Which servers are allowed to send mail for this domain?"
- DKIM — "Was this message actually sent by the domain it claims, and is it unmodified?"
- DMARC — "What should receivers do when SPF or DKIM fail, and where should they report it?"
SPF: Sender Policy Framework
SPF lets a domain owner publish a DNS TXT record listing which IP addresses and servers are authorized to send mail on their behalf. When a mail server receives a message, it checks the envelope sender (the MAIL FROM in the SMTP conversation, not the visible From: header) against the domain's SPF record.
What an SPF record looks like
v=spf1 include:_spf.google.com include:sendgrid.net ip4:203.0.113.5 -all
Breaking this down:
v=spf1— version identifier (required)include:_spf.google.com— allow any IP that Google Workspace authorizesinclude:sendgrid.net— also allow SendGrid's IPsip4:203.0.113.5— allow this specific IP-all— reject everything else (~all= softfail,?all= neutral)
Common SPF mistakes
- Too many DNS lookups. SPF has a 10-lookup limit. Each
include:anda:counts. Exceed it and SPF returnspermerror— effectively no protection. This is the #1 misconfiguration on domains using multiple SaaS providers. - Using
~allinstead of-all. Softfail (~all) tells receivers "this probably shouldn't pass but don't reject it." It's training wheels — fine while testing, bad in production. - Forgetting subdomains. SPF only covers the exact domain. If you have SPF on
example.combut send frommail.example.com, you need a separate record.
DKIM: DomainKeys Identified Mail
DKIM adds a cryptographic signature to every outgoing email. The sending server signs specific headers and the message body with a private key; the corresponding public key is published in DNS. The receiving server fetches the public key and verifies the signature.
How it works in practice
When you send an email, your mail server adds a header like this:
DKIM-Signature: v=1; a=rsa-sha256; d=example.com; s=selector1;
h=from:to:subject:date:message-id;
bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=;
b=AuUoFEfDxTDkHlLXSZEpZj79LICEps6eda7W3deTVFOk...
Key fields:
d=example.com— the signing domains=selector1— which public key to look up (selector1._domainkey.example.com)h=— which headers were signedb=— the actual signaturebh=— hash of the body
The receiving server queries selector1._domainkey.example.com for a TXT record containing the public key, then verifies the signature. If it matches, the message hasn't been tampered with and genuinely came from (or through) that domain's infrastructure.
Common DKIM mistakes
- Key rotation neglect. Old 1024-bit keys are increasingly crackable. Use 2048-bit and rotate annually.
- Signing with a third-party domain. If your ESP signs with
d=sendgrid.netinstead ofd=yourdomain.com, DMARC alignment fails — the signature doesn't match theFrom:domain. Always configure custom DKIM. - Not signing enough headers. At minimum, sign
from,to,subject,date, andmessage-id.
DMARC: Domain-based Message Authentication, Reporting & Conformance
DMARC ties SPF and DKIM together. It tells receiving servers: "Check if SPF or DKIM passes and aligns with the From: domain. If neither aligns, here's what to do."
What a DMARC record looks like
v=DMARC1; p=reject; rua=mailto:dmarc@example.com; ruf=mailto:dmarc@example.com; adkim=s; aspf=r; pct=100
p=reject— policy:none(monitor),quarantine(spam folder), orreject(drop it)rua=— where to send aggregate reports (XML, daily)ruf=— where to send forensic/failure reports (per-message)adkim=s— DKIM alignment:s= strict (exact domain match),r= relaxed (subdomains OK)aspf=r— SPF alignment modepct=100— apply policy to 100% of failing messages
The alignment concept
This is where most people get confused. DMARC doesn't just check if SPF or DKIM pass — it checks if they align with the domain in the visible From: header.
This is why configuring custom domains on your ESP matters. If SendGrid sends with MAIL FROM: bounce@sendgrid.net and signs with d=sendgrid.net, both SPF and DKIM pass for sendgrid.net, but DMARC fails because the From: says @example.com.
The recommended rollout path
- Start with
p=none— monitor only. Set uprua=to receive aggregate reports. - Analyze reports for 2-4 weeks — identify legitimate senders that fail alignment.
- Fix alignment issues — configure custom SPF/DKIM on all ESPs.
- Move to
p=quarantine— failing messages go to spam. - Finally,
p=reject— full protection.
How They Work Together
Here's the full authentication flow when a message arrives:
A message passes DMARC if either SPF or DKIM passes and aligns. You don't need both — but having both provides redundancy. DKIM survives forwarding (SPF doesn't, since the forwarding server's IP won't be in the original SPF record). SPF works even when DKIM signatures break (which can happen with mailing lists that modify headers).
Checking Email Authentication Programmatically
During development, you'll want to verify that your DNS records are correct and that emails from your domain actually pass authentication. Here are a few approaches:
Manual DNS checks
# Check SPF
dig +short TXT example.com | grep spf
# Check DKIM (you need to know the selector)
dig +short TXT selector1._domainkey.example.com
# Check DMARC
dig +short TXT _dmarc.example.com
Using the MailCheck API
If you're building an app that needs to verify email authentication for arbitrary domains — say, checking if a customer's email is properly authenticated before adding them to your platform — the MailCheck Authentication Verification endpoint does this in a single API call:
curl -X POST https://api.mailcheck.dev/v1/verify/auth \
-H "Authorization: Bearer sk_live_your_key" \
-H "Content-Type: application/json" \
-d '{"domain": "example.com"}'
The response includes the full SPF, DKIM, and DMARC configuration for the domain, parsed and validated — including alignment analysis and specific misconfigurations. It's useful for onboarding flows where you need to tell customers exactly what DNS records to fix.
Use the free Domain Check tool to inspect any domain's SPF, DKIM, and DMARC configuration instantly. Or grab an API key to integrate it into your app — 100 free checks/day, no credit card required.
Quick Reference: DNS Records Cheat Sheet
Takeaways
- SPF authorizes sending IPs — watch the 10-lookup limit.
- DKIM cryptographically signs messages — always use custom signing domains and 2048-bit keys.
- DMARC enforces alignment between SPF/DKIM and the
From:header — roll out gradually fromnonetoreject. - Alignment is the key concept. Individual SPF/DKIM passes mean nothing if they don't align with the visible
From:domain. - Test everything. Use
dig, send test emails, check DMARC reports, or use an API like MailCheck's auth verification to catch issues before your users do.
Getting email authentication right isn't glamorous work, but it's the difference between your emails landing in the inbox and disappearing into the void. Set it up once, monitor with DMARC reports, and you're done.