Three DNS records decide whether your invoices reach the inbox or the spam folder, and most setups have all three and still fail. The reason is alignment: DMARC does not ask whether SPF passed, it asks whether the domain SPF authenticated matches the domain in the From header. This is the working order to set them up, why SPF alone breaks the moment a message is forwarded, the ten lookup limit that silently voids your record, and how to move from p=none to p=reject without losing a week of mail.
Most deliverability problems are not spam filters being unfair. They are three DNS records that exist, look right, and do not do what their owner thinks.
The three answer different questions. SPF says which servers may send for your domain. DKIM signs the message so a receiver can prove it was not altered. DMARC ties both back to the address your recipient actually sees, and tells receivers what to do when neither ties.
That last part is where working setups fail, so it is worth taking first.
Alignment is the whole game
DMARC does not ask "did SPF pass". It asks whether the domain that passed is the same domain as the one in the From: header, the only address the recipient ever sees.
A message passes DMARC when either of these holds:
- SPF passed, and the domain it authenticated aligns with the From domain.
- DKIM passed, and the
d=domain in the signature aligns with the From domain.
The SPF check authenticates the envelope sender, the Return-Path, not the From header. Send through a marketing platform that uses its own bounce domain and SPF passes for that platform and aligns with nothing. The mail is authenticated and still fails DMARC.
This is why DKIM matters more than it looks. It is also why the fix for a failing platform is usually to sign with your own domain, not to add another include: to SPF.
SPF, and the limit that voids it
One TXT record at the apex, listing who may send.
v=spf1 include:_spf.example-provider.com ip4:203.0.113.10 -all
Two things to get right.
The ten lookup limit. SPF allows at most ten DNS-querying mechanisms while evaluating a record. Every include, a, mx, ptr, exists and redirect counts, and every include drags in whatever that provider's record expands to. Cross the limit and the result is a permanent error, which most receivers treat as no SPF at all. Four or five providers is enough to cross it without a single obvious mistake in your record.
Check the expansion, do not count the words in your own record.
-all or ~all. Hard fail says anything else is forged. Soft fail says treat it as suspicious. Start on ~all while you are still discovering who sends on your behalf, and move to -all once the reports are quiet. Leaving it on ~all forever is the common half-measure.
SPF also breaks on forwarding. A message forwarded by a mailing list arrives from the list's server, which is not in your record, and SPF fails through no fault of anyone. DKIM survives that trip, which is the second reason to sign.
DKIM
Your mail server signs outgoing messages with a private key. The public half goes in DNS under a selector you choose.
selector1._domainkey.example.com TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkq..."
Use 2048-bit keys. Publish a second selector before you rotate, switch signing to it, and remove the old one a few days later, so no message is ever signed with a key that is not published.
Sign with your own domain wherever a provider allows it. Every platform that sends on your behalf, invoicing, marketing, ticketing, should sign as d=example.com. That single change fixes more alignment failures than any SPF edit.
DMARC, starting at none
_dmarc.example.com TXT "v=DMARC1; p=none; rua=mailto:dmarc@example.com; fo=1"
p=none changes nothing about delivery. It asks receivers to send you aggregate reports about what they saw. That is the point: you cannot safely enforce a policy over senders you have not enumerated, and almost nobody can list them correctly from memory. Invoicing, the CRM, a monitoring tool, a form on the website, an old server somebody set up in 2019.
Run it for two to four weeks and read the reports. They will show you sources you forgot.
Then tighten in two steps: p=quarantine, watch, then p=reject. Use pct= to ramp a percentage of mail into the new policy if the volume makes you nervous.
By default both alignment modes are relaxed, which means a subdomain aligns with its parent. aspf=s and adkim=s demand an exact match. Relaxed is the right default; strict is for people who know why they want it.
The order that works
- Publish SPF with
~alland check the expansion stays under ten lookups. - Turn on DKIM signing everywhere, with your own domain in
d=. - Publish DMARC at
p=nonewithrua. - Read reports until nothing surprising appears.
- Move SPF to
-all, DMARC toquarantine, thenreject.
Skipping step 3 and going straight to p=reject is how a company discovers, on a Monday, that its invoices have been rejected since Friday.
If mail is currently landing in spam and you would rather have it diagnosed than described, that is part of our security and compliance work, and our free mail tools will check the three records for you first.
Frequently asked questions
Why does an email fail DMARC even though SPF passes?
SPF authenticates the envelope sender, the Return-Path, and DMARC asks whether that domain aligns with the domain in the From header. A marketing platform that uses its own bounce domain passes SPF for the platform and aligns with nothing, so the message is authenticated and still fails DMARC. The usual fix is to have the platform sign with DKIM using the sender's own domain in d=, instead of adding another include to SPF.
Does DMARC require both SPF and DKIM to pass?
No, one aligned pass is enough. A message passes DMARC when SPF passed and the domain it authenticated aligns with the From domain, or when DKIM passed and the d= domain in the signature aligns with the From domain. DKIM carries more of the weight in practice, because a DKIM signature survives forwarding where SPF breaks.
What happens when an SPF record needs more than 10 DNS lookups?
SPF evaluation returns a permanent error, which most receivers treat as no SPF at all. Every include, a, mx, ptr, exists and redirect counts toward the limit of ten, and each include also drags in whatever the provider's record expands to. Four or five providers can cross the limit without one obvious mistake, so check the full expansion, since counting the mechanisms in your own record misses what each include pulls in.
Should an SPF record end in -all or ~all?
Start with ~all, the soft fail that marks other senders as suspicious, while still discovering who sends on the domain's behalf. Move to -all, the hard fail that declares anything else forged, once the DMARC reports are quiet. Leaving ~all in place forever is a common half-measure.
Why does SPF fail when an email is forwarded?
A forwarded message, for example one sent on by a mailing list, arrives from the forwarder's server, and that server is not in the original domain's SPF record. SPF then fails through no fault of anyone. A DKIM signature survives the trip, which is a strong reason to sign outgoing mail with DKIM as well.
How do I rotate DKIM keys without breaking mail delivery?
Publish a second selector before rotating, switch signing to it, and remove the old selector a few days later. Following that order, no message is ever signed with a key that is not published. Use 2048-bit keys, with each public key published as a TXT record under its selector, such as selector1._domainkey.example.com.
How long should DMARC stay at p=none before moving to p=reject?
Run p=none with an rua reporting address for two to four weeks, and keep reading the aggregate reports until nothing surprising appears. The p=none policy changes nothing about delivery, but the reports reveal forgotten senders such as invoicing, the CRM, a monitoring tool or a form on the website. Then tighten to p=quarantine, watch, and move to p=reject, using pct= to ramp a percentage of mail if the volume is a concern.
What is the difference between relaxed and strict DMARC alignment?
Relaxed alignment, the default for both SPF and DKIM, lets a subdomain align with its parent domain. Strict alignment, set with aspf=s and adkim=s, demands an exact match. Relaxed is the right default for most senders, and strict is for those who know why they want it.
Read how we handle it in Cybersecurity.
Related Articles
How to Read a CVE and Decide in Ten Minutes If It Touches You
An alarming headline and a severity score are not a decision, and the score cannot become one because the part of it that would describe your environment is the part nobody filled in. This is the ten minute route from a CVE number to a defensible answer, covering what the scoring specification actually says, why your installed version number may be lying about whether you are patched, and which public sources report real exploitation rather than the possibility of it.
SecurityApache 2.4.71 Closes a Critical HTTP/2 Flaw in mod_http2
Apache 2.4.71 fixes CVE-2026-119618, a critical mod_http2 flaw that can let an unauthenticated attacker run code where HTTP/2 is on. Where each fix stands, a one-minute check, and how to switch HTTP/2 off until your patch lands.
SecurityWhat AI Attacks Taught Cloudflare About Its Own WAF
Cloudflare let AI models attack a staging site behind its WAF. Of 607 counted requests, 558 were blocked and 48 of the 49 findings were command injection or SSRF. The test used Enterprise-only settings, so here is what a Free or Pro zone can copy.