SPF, DKIM and DMARC, Explained
Three DNS records decide whether your mail is trusted or quietly binned. What SPF, DKIM and DMARC each check, how alignment ties them together, the mistakes that break them, and how to check your own domain.
The order confirmations stop arriving. Nothing bounces, and nothing shows up in a log. Customers just write in asking whether their order went through, and the answer turns out to be sitting in their spam folder, where it has been going for a week.
When this happens, the cause is usually one of three DNS records: SPF, DKIM and DMARC. Between them they decide whether a receiving mail server believes your message really came from you. This post covers what each one checks, how they fit together, and the mistakes that break them.
Why mail needs proving at all
Email was designed in an era when everyone on the network knew each other. The protocol that carries it, SMTP, lets the sending server claim any sender address it likes. Nothing in the original design stops a server anywhere from sending mail that says it comes from your domain.
So receivers have to check, and to understand how, you need to know that a message carries two different "from" addresses:
- The envelope sender, also called the Return-Path or
MAIL FROM. The sending servers use it to route bounces. People never see it. - The header From, the address shown in the mail client. This is the one people trust, and the one spammers forge.
Keep that distinction in mind. Most of the confusion around these three records comes from which address each one checks.
SPF: which servers may send for you
SPF, the Sender Policy Framework, is a TXT record on your domain that lists the servers allowed
to send mail for it:
example.com. TXT "v=spf1 include:_spf.google.com include:spf.mtasv.net ~all"
When a message arrives, the receiver takes the domain of the envelope sender, looks up its SPF
record, and checks whether the connecting server's IP address is on the list. The include:
entries pull in the lists published by your providers, so you do not have to track their IP
addresses yourself.
The record ends with what to do about everyone else. -all says mail from anywhere else fails.
~all says it soft-fails, meaning it is suspicious but not to be rejected on this alone. Once DMARC
is in place, ~all is a perfectly good choice, because DMARC makes the final decision anyway.
There are two rules that catch people out:
- One SPF record per domain. If you publish two
v=spf1records, the result is a permanent error, which receivers usually treat as a failure. This happens all the time, because every new tool's setup guide says "add this SPF record" instead of "add this include to your existing one". - At most ten DNS lookups. The standard, RFC 7208, caps the number of mechanisms that need a
DNS query (
include,a,mx,ptr,existsandredirect) at ten, counting everything nested inside every include. Go over the limit and SPF fails outright.ip4andip6entries cost nothing, which is why SPF-flattening tools replace includes with raw addresses. The catch is that someone then has to keep those addresses current.
SPF has one structural weakness. It checks the envelope sender, not the address people see, so on its own it does nothing to stop someone forging your header From. It also breaks when mail is forwarded, because the forwarding server is not on your list.
DKIM: a signature on the message itself
DKIM, DomainKeys Identified Mail, takes a different approach. Instead of vouching for servers, it
signs the message. The sending server hashes the body and a chosen set of headers, signs the result
with a private key, and adds a DKIM-Signature header:
DKIM-Signature: v=1; a=rsa-sha256; d=example.com; s=pm2026;
h=from:to:subject:date; bh=...; b=...
The d= tag names the signing domain and s= names the selector. The receiver fetches the
public key from pm2026._domainkey.example.com and checks the signature. If anything covered by it
changed in transit, the check fails.
Selectors are what let you run several providers at once, each with its own key, and rotate keys
without downtime: publish a new selector, switch signing to it, then retire the old one. Many
providers ask you to add a CNAME instead of the key itself, so they can rotate keys without you
touching DNS again. Use 2048-bit keys. The 1024-bit keys you still see in old setups are past their
safe age.
Because the signature travels with the message, DKIM usually survives forwarding. Mailing lists that add a footer or rewrite the subject line do break it.
DMARC: tying it to the address people see
Neither SPF nor DKIM on its own says anything about the header From. DMARC closes that gap with one idea, alignment. A message passes DMARC when SPF or DKIM passes and the domain it passed for matches the domain in the visible From address.
By default the match is relaxed, meaning the same organisational domain is enough, so
mail.example.com aligns with example.com. You can make it strict with aspf=s and adkim=s,
but few senders need to.
The record lives at _dmarc under your domain:
_dmarc.example.com. TXT "v=DMARC1; p=none; rua=mailto:dmarc@example.com"
p= is the policy, meaning what you ask receivers to do with mail that fails:
| Policy | What receivers do with failing mail |
|---|---|
p=none |
Deliver it as normal, and include it in reports |
p=quarantine |
Treat it as suspicious, which usually means the spam folder |
p=reject |
Refuse it during the SMTP conversation |
rua= is where the aggregate reports go. These are daily XML files from Google, Microsoft, Yahoo
and others, listing every source that sent mail claiming to be you, with pass and fail counts. They
are unreadable by hand and invaluable through any of the free or cheap report parsers. They are
also how you find the invoicing tool someone signed up for last year that has been sending as you
ever since.
sp= sets a separate policy for subdomains. Without it they inherit p=.
The 2026 update
In May 2026, after years of drafts, the IETF published the revised DMARC specification as RFC 9989,
with reporting split out into RFC 9990 and RFC 9991. It makes DMARC a standards-track protocol for
the first time. For most domains, nothing breaks. Existing v=DMARC1 records keep working. The
pct tag, which applied a policy to a percentage of mail, is gone, replaced by a simpler t=y flag
for a policy you are still testing. A new np= tag sets a policy for subdomains that do not exist,
which is where a lot of spoofing hides.
Why receivers now insist
For years this was best practice that only large senders bothered with. That changed in February
2024, when Gmail and Yahoo started requiring bulk senders to have SPF, DKIM and a DMARC record, with
alignment. Gmail draws the line at around 5,000 messages a day to its users, and requires every
sender below it to have at least SPF or DKIM. Microsoft followed in May 2025 for Outlook.com,
Hotmail and Live addresses, and non-compliant bulk mail there is rejected outright with a
550 5.7.15 error instead of landing in junk.
A small shop sending a few hundred order confirmations a day is below those thresholds. It still gets judged by the same filters, and unauthenticated mail from a small domain with no sending history is exactly what those filters are built to distrust.
A rollout that does not break your own mail
Going straight to p=reject is how companies discover, the hard way, that their helpdesk was
sending password resets from an unauthenticated server. The safe order is:
- List every service that sends as your domain. Your mailbox provider, transactional email, newsletters, helpdesk, CRM, invoicing, the store platform, and the contact form on the website.
- Fix SPF. Keep one record, include each sender, and stay under ten lookups.
- Turn on DKIM for your own domain in every service. This is the step people skip. Many providers sign with their own domain by default, which passes DKIM but does not align with yours. Look for "custom domain", "domain authentication" or "sender domain" in each one's settings.
- Publish DMARC with
p=noneand aruaaddress. - Read the reports for two to four weeks. Every legitimate source should show as aligned. Chase down whatever is not.
- Move to
p=quarantine, thenp=reject.
The mistakes I see most
A second SPF record, added by a new tool's setup wizard. Both stop working.
The ten-lookup limit, reached quietly as providers add includes inside their own includes. Nothing changed in your record and SPF started failing anyway.
A provider signing with its own domain. DKIM passes and DMARC fails, and the reports are the only place you will see it.
-all on a domain whose mail gets forwarded, combined with no DKIM. Forwarded mail fails SPF,
has nothing else to pass on, and disappears.
Unprotected parked domains. A domain that never sends mail is a gift to spoofers unless you say so explicitly. Three records close it off:
example.net. TXT "v=spf1 -all"
_dmarc.example.net. TXT "v=DMARC1; p=reject;"
example.net. MX 0 .
The last one is a null MX, which tells the world the domain accepts no mail at all.
Checking your own domain
You do not need a paid tool to see what you have published:
dig +short TXT example.com | grep spf1
dig +short TXT _dmarc.example.com
dig +short TXT pm2026._domainkey.example.com
The DKIM selector is the awkward one, because you cannot list selectors from DNS. The easiest way
to find yours is to send yourself a message from each service and read the headers. In Gmail,
"Show original" gives you a summary of SPF, DKIM and DMARC results at the top, and the
Authentication-Results header shows the full detail, including the s= and d= that signed it.
Authentication is not reputation
Passing all three proves who sent a message. It does not prove anyone wants it. A fully authenticated domain can still end up on a domain blacklist like Spamhaus DBL, SURBL or URIBL, which list domains that appear in spam. Once it is listed, the mail it sends and the links pointing to it are filtered no matter how clean the DNS looks.
Authentication does help you stay off those lists. A domain at p=reject is much harder to use
in someone else's spam run, because forged mail claiming to be from it gets refused at the door.
Barkme does not audit your SPF or DMARC records. It watches for the listing: every verified domain is checked daily against Spamhaus DBL, SURBL and URIBL, as well as the DNS filters that block sites for visitors. You get one alert when the domain is listed, naming the lists, and another when it clears. When your domain lands on a blacklist covers how listings happen and how to get off them.
For the DNS basics underneath all of this, see how DNS works. For the other email that must never land in spam, the registrar's renewal reminder, see the expiry dates that take websites down. The how it works page and the F.A.Q cover what Barkme checks and how often.
Barkme watches your sites around the clock and barks the moment one goes down. Free plan, no card required.
Keep reading
More from the blog
Checkout Down Is Not Site Down
A shop can have a perfectly healthy homepage and a cart that has been failing since Friday. Which URLs to monitor on an online store, what an uptime check can and cannot prove, and the quiet failures that cost sales without taking anything down.
What to Put Behind a /health Endpoint
A health route is the URL your uptime monitor trusts more than any other. What a shallow and a deep check should each touch, when to return 503, how to keep it fast and safe to expose, and a small example you can adapt.
The Alert Nobody Read
Monitoring that catches an outage and delivers the alert to an inbox nobody opens has still failed. How to route uptime alerts by who has to act, when a ticket beats a message, and how to prove a channel works before you need it.