If you only remember one thing: an SPF pass and a DMARC pass are not the same test. SPF asks “is this IP allowed to send for the envelope domain?” DMARC asks a second, stricter question — “does the domain that just passed SPF match the domain in the visible From address?” You can sail through the first and still fail the second. That single gap is behind a large share of confusing dmarc=fail reports, and it almost always traces back to your ESP’s bounce address rather than anything wrong with your DNS.
Two different “From” addresses
Every email actually carries two sender addresses, and they are frequently different:
- The envelope sender — also called the Return-Path, MAIL FROM, or bounce address. It is set during the SMTP conversation, it is where bounce messages go, and recipients normally never see it. This is the domain SPF checks.
- The header From — the
From:line rendered in the inbox, the address a human reads. This is the domain DMARC cares about.
When you send your own mail from your own server, these two are usually the same domain, so the distinction never bites you. But the moment a marketing platform, transactional ESP, or CRM sends on your behalf, they typically set the envelope sender to their bounce domain (so bounces return to their infrastructure) while leaving your address in the header From. Now the two domains diverge — and SPF and DMARC start disagreeing.
What SPF actually authenticates
SPF (RFC 7208) validates the sending IP against the SPF record of the envelope domain — the smtp.mailfrom value. If your ESP sends from mail.acme-esp.net and that domain’s SPF record authorises the IP, SPF returns pass. Note carefully what it did not check: it never looked at acme.com, the domain in your From line. SPF has no opinion about the visible From at all. That is by design, and it is exactly why SPF on its own can be trivially bypassed by a spoofer who puts your address in From while sending from their own authenticated envelope domain.
What DMARC adds: alignment
DMARC (RFC 7489) closes that hole with a rule called alignment. For DMARC to pass on the SPF side, two things must both be true:
- SPF must pass for the envelope domain, and
- that envelope domain must align with the header From domain.
“Align” means match. In relaxed mode (aspf=r, the default) the organizational domains must match — mail.acme.com aligns with acme.com because they share the same registered domain. In strict mode (aspf=s) the domains must be identical. In our problem case the envelope domain is mail.acme-esp.net and the From domain is acme.com — completely different registered domains, so alignment fails no matter which mode you use. SPF passed; SPF alignment did not; and DMARC needs the alignment.
A real header where spf=pass but dmarc=fail
Here is the exact pattern in an Authentication-Results header. Read smtp.mailfrom (the envelope domain SPF checked) against header.from (what DMARC evaluated):
Return-Path: <bounces+7f3a9@mail.acme-esp.net>
From: "Acme Billing" <billing@acme.com>
Authentication-Results: mx.google.com;
spf=pass (google.com: domain of bounces+7f3a9@mail.acme-esp.net
designates 198.51.100.24 as permitted sender)
smtp.mailfrom=bounces+7f3a9@mail.acme-esp.net;
dkim=none;
dmarc=fail (p=REJECT sp=REJECT dis=REJECT) header.from=acme.comEverything about SPF is green: the ESP’s IP 198.51.100.24 is authorised for mail.acme-esp.net. But look at the last line — dmarc=fail with header.from=acme.com. DMARC compared the passing SPF domain (mail.acme-esp.net) against the From domain (acme.com), found no alignment, and — because DKIM was absent here too (dkim=none) — had no aligned identifier left to pass on. With a policy of p=reject, that message gets bounced. For a walkthrough of every field in this block, see how to read the Authentication-Results header.
The fix: a custom Return-Path on your own domain
To make SPF align, the envelope sender has to live under your domain, not the ESP’s. Almost every provider supports this through a custom Return-Path (sometimes called a custom bounce domain, custom MAIL FROM, or return-path CNAME). You publish a subdomain such as bounce.acme.com and point it at the provider with a CNAME they give you; they then use bounce.acme.com as the envelope sender instead of their shared bounce domain. Now SPF passes and bounce.acme.com aligns with acme.com under relaxed mode, so DMARC passes on the SPF side. The full walkthrough is in how to set up a custom Return-Path.
Your DMARC record itself does not need to change to make alignment work — it just needs to keep asking for relaxed mode, which is the default:
_dmarc.acme.com TXT
"v=DMARC1; p=reject; rua=mailto:dmarc@acme.com; aspf=r; adkim=r"Don’t rely on SPF alone — align DKIM too
Even with a perfect custom Return-Path, SPF alignment has a fragile spot: SPF breaks on forwarding. When a recipient auto-forwards your message or a mailing list relays it, the new hop’s IP is not in your SPF record, and SPF fails on that leg. DMARC can still pass on those hops if DKIM is aligned, because a DKIM signature survives forwarding. That is why the durable target is to have both identifiers aligned: aligned SPF for the direct path, aligned DKIM as the forwarding-proof backstop. If your DKIM is passing but still not aligned, that is its own trap — see why DKIM passes but DMARC fails.
Diagnose and verify
- Confirm what SPF sees. Check that your envelope domain resolves, has a valid single record, and stays under ten lookups with the SPF Checker. If it throws a PermError, read SPF too many DNS lookups first — a PermError is not a pass.
- Confirm alignment end-to-end. Run your live mail through the DMARC Checker and read the raw
Authentication-Resultswith the Email Header Analyzer so you can seesmtp.mailfromandheader.fromside by side. - Check DKIM as your forwarding backstop with the DKIM Checker.
For the bigger picture of how all three records fit together, start with the complete SPF, DKIM & DMARC guide. Once every legitimate sender is aligned, you can safely tighten policy — see how to move DMARC to p=reject safely. The authoritative references are RFC 7208 (SPF), RFC 7489 (DMARC), and Google’s DMARC guidance.