SPF, DKIM & DMARC, Demystified
Three DNS records, three completely different jobs. Together they decide whether the mail you send from your domain lands in someone's inbox, gets quietly junked, or vanishes entirely. They're individually pretty simple — what trips most people up is misunderstanding what each one actually proves.
SPF says which servers are allowed to send mail for your domain. DKIM proves the message wasn't tampered with by signing it with a key only your sending servers know. DMARC tells receiving servers what to do if SPF or DKIM fails — and where to send reports about the failures. You need all three; missing any one of them is increasingly treated as “please send my mail to spam” by big providers like Google and Microsoft.
The big picture: what each one actually does
Email was designed in 1982 with zero authentication. Any server can claim to be sending mail “from” any domain, and the receiving server has no way to verify the claim. SPF, DKIM, and DMARC are three separate bolt-ons that tried to fix this over the next 30 years. Here's how each one slots into the journey of an email:
SPF, DKIM, and DMARC are three independent checks the receiving server runs against your domain's DNS records before deciding whether to accept the message.
SPF: who's allowed to send
SPF (Sender Policy Framework) is the oldest of the three. It's a single TXT record at your apex domain that
lists, in machine-readable form, every server allowed to send mail from your domain. When a receiving server
gets a message claiming to be from yourdomain.com, it checks the connecting IP against this list.
If the IP isn't authorised, the message fails SPF.
A typical SPF record looks like this:
v=spf1 include:_spf.google.com include:mailgun.org -all
Reading it left to right:
v=spf1— required prefix that identifies this as an SPF record.include:_spf.google.com— “also accept anything listed in Google's SPF record.” This is how you authorise a third party (Google Workspace) to send mail for you.include:mailgun.org— same, for transactional mail through Mailgun.-all— the catch-all at the end: everyone not on this list, fail hard.
The qualifiers (this is where it gets weak fast)
That last -all is the most important part of the record and is misunderstood constantly. There are four versions:
| Qualifier | What it means |
|---|---|
-all | Fail. “If the sender isn't in this list, reject the mail.” This is what you want. |
~all | SoftFail. “Mark as suspicious but accept anyway.” A safe default while you're testing, but mail can still get through. |
?all | Neutral. “Don't apply any policy.” Essentially turns SPF off. Avoid. |
+all | Pass. “Accept everything.” This is catastrophic — it means anyone in the world can send mail from your domain. Never use this. |
The multi-SPF trap
The single most common SPF misconfiguration: two SPF records on the same domain. This happens
when a team adds a new email provider (say Mailchimp) without realising they already have one for Google
Workspace. Both records are valid TXT records, both start with v=spf1, but RFC 7208 ยง3.2 is explicit
that there must be exactly one. When receivers see two, they don't pick the right one — they return
permerror and treat your SPF as broken.
The fix: merge the includes into a single record. If you had
v=spf1 include:_spf.google.com ~all and v=spf1 include:mailgun.org -all, replace
both with v=spf1 include:_spf.google.com include:mailgun.org -all. FatDig detects this case
automatically and generates the merged record for you with a one-click copy button.
The 10-lookup limit
Each include:, a, mx, ptr, exists:, and
redirect= mechanism in your SPF record costs one DNS lookup when a receiver evaluates it. The RFC
sets a hard cap of 10 lookups total. Go over and the record permerrors the same way as having
two records does.
It's easier to hit than you'd think. include:_spf.google.com looks like one lookup — but
Google's SPF record itself contains several includes, and those count toward your budget. Mailchimp's
is even more expensive. FatDig shows your current lookup count in the SPF section of the Email Authentication
card so you can watch the budget.
DKIM: cryptographically signing the message
DKIM (DomainKeys Identified Mail) is the second pillar. It's a cryptographic signature added to every outgoing email. The sending server signs the message with a private key; the receiving server verifies the signature using a public key published in your DNS. If the signature checks out, the recipient knows two things: the message was sent by something with access to your DKIM private key, and the message hasn't been modified in transit.
DKIM records live at a slightly unusual DNS path: <selector>._domainkey.<domain>. The
selector is just a label your mail provider chose — Google uses google, Microsoft 365 uses
selector1 and selector2, Mailgun uses k1, and so on. A real record looks
like:
google._domainkey.yourdomain.com. 300 IN TXT
"v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQ
DkfYW1KJp7QO9..."
You typically don't write these yourself — your mail provider generates the keypair, gives you the public
side as a TXT record to add, and keeps the private side server-side. Once it's added, every message they send
gets a DKIM-Signature: header attached.
Why FatDig probes a list of selectors: there's no central registry
of which selector your provider uses, and the record lives at a path that depends on it. FatDig probes ~25
of the most common selectors (default, google, selector1,
k1, sendgrid, etc.) and lists whichever return a match. If your provider uses a
custom selector, you'd need to check it directly — but for the major providers, FatDig will find it.
DMARC: telling receivers what to do
SPF and DKIM each give the receiving server a signal. DMARC (Domain-based Message Authentication, Reporting and Conformance) is the policy layer that says what to do with that signal. It also tells receivers where to send aggregated reports so you can see what mail is being sent “as” your domain.
A DMARC record lives at _dmarc.<domain> and looks like this:
_dmarc.yourdomain.com. 3600 IN TXT
"v=DMARC1; p=reject; pct=100; rua=mailto:dmarc@yourdomain.com; adkim=s; aspf=s"
The key tags:
| Tag | What it does |
|---|---|
p= | The policy. One of none (monitor only), quarantine (mark as spam), or reject (refuse). This is the single most important field. |
pct= | Percentage of mail to apply the policy to. Useful during a rollout: pct=10 applies the policy to 10% of failing mail. |
rua= | Address to send aggregate reports to (XML, daily). This is how you find out what mail claiming to be from your domain is actually being sent. |
ruf= | Address to send forensic reports (per-message). Less commonly supported; many providers don't send these. |
adkim= | DKIM alignment mode. s (strict) or r (relaxed, default). |
aspf= | SPF alignment mode. Same options as adkim. |
The DMARC rollout pattern
Going from no DMARC to p=reject overnight is a great way to break your transactional email for a
week. The safe rollout pattern, followed by basically every team that's done this without an outage, is:
- Publish
p=nonewith arua=address pointing to a service that parses the XML (Dmarcian, Postmark, EasyDMARC, etc. all have free tiers). Run it for at least two weeks. - Review the reports. You'll discover servers sending as your domain that you'd completely forgotten about — a newsletter platform, an internal monitoring tool, a vendor's reminder system. Add each of them to your SPF record or configure DKIM for them.
- Move to
p=quarantineatpct=10, then50, then100, watching reports at each step. - Finally move to
p=reject.
p=none isn't “DMARC enabled”: a lot of
teams publish p=none for the rollout, get the reports, and never move on. p=none
tells receiving servers to do nothing when SPF or DKIM fails — it's monitoring-only. As of
2024, Google and Yahoo require senders of bulk mail to have at least p=quarantine;
p=none in their eyes counts as “no enforcement.”
What FatDig shows you
Drop a domain into the Advanced Dig and the Email Authentication card shows you all three at a glance, each with a status badge (OK / Warning / Missing / Invalid):
- SPF: the full record, the qualifier (
-all/~all/ etc.), and your current DNS lookup count out of the 10-lookup limit. If multiple SPF records exist, the card flags it as Invalid and shows you a one-click merged record to deploy. - DMARC: the full record, the policy, the reporting address, and a warning if you're stuck
on
p=none. - DKIM: every selector FatDig found by probing the ~25 most common names, with the public key truncated for readability.
Try it on FatDig: dig google.com and look at its email auth setup — a perfect example of a fully configured trio. Then dig your own domain and compare. Most personal/small-business domains are missing at least one of the three.