Learn
DMARC fails even though SPF passes
A message can pass SPF and still fail DMARC, because DMARC only counts SPF when it checked your own domain. Here is how to confirm that from the headers or a report, and the two ways to fix it.
By Ahmet Karaca · Updated · Checked against RFC 9989 (DMARC, May 2026), RFC 7208 (SPF), RFC 9990 (DMARC aggregate reports) and Gmail Help on full headers on
The symptom
You open the full headers of a message your newsletter tool sent, or a DMARC report lands in your inbox, and the results look contradictory. SPF says pass. DMARC says fail. If your policy is p=none nothing visible happens yet, but at p=quarantine those messages go to spam and at p=reject they bounce. The instinct is to suspect a broken record or a receiver bug. Almost always it is neither: the SPF check passed for a different domain than the one DMARC protects.
Here is what such a message typically looks like when it was sent through a marketing platform:
Return-Path: <bounce-7f3a@bounces.esp.example.net>
From: Example Shop <news@example.com>
Authentication-Results: mx.receiver.example;
dkim=pass header.d=esp.example.net;
spf=pass smtp.mailfrom=bounces.esp.example.net;
dmarc=fail header.from=example.comRead the domains, not the verdicts. The reader sees news@example.com in the From line. SPF, however, was evaluated for bounces.esp.example.net, the address in Return-Path, and the platform has, quite correctly, authorized its own servers for its own bounce domain. The DKIM signature also passed, but it was made with the platform's domain, esp.example.net. Two valid checks, neither of them about example.com.
Two senders in every message
Every email carries two sender addresses. The envelope sender is given in the SMTP MAIL FROM command and is where bounces go; receivers copy it into the Return-Path header. RFC 7208, section 2.4, makes this MAIL FROM identity the one SPF verifies. The header From is the address in the message itself, the one a mail app displays. The two can differ freely, and with sending services they usually do, because the service wants bounces delivered to its own systems so it can clean your list.
DMARC protects the header From domain, which RFC 9989 calls the Author Domain. A pass from SPF or DKIM only counts toward DMARC when the domain that check authenticated is aligned with the Author Domain. Section 4.4.2 of RFC 9989 gives the reason plainly: any domain owner, a bad actor included, can publish an SPF record for a domain of their own and earn an SPF pass. Without the alignment requirement, a phisher could pass SPF for attacker.example while showing your name in From.
A message passes DMARC when at least one authenticated identifier aligns, either the SPF domain or the d= domain of any valid DKIM signature. In the example above neither does, so DMARC fails even though both underlying checks passed.
Relaxed and strict alignment
RFC 9989 defines two modes. In relaxed mode, the default, two domains align when they share the same Organizational Domain: bounces.example.com aligns with example.com, and so does mail.example.com with news.example.com. In strict mode the domains must be identical, so bounces.example.com no longer aligns with example.com. Your DMARC record chooses the mode separately for each method with aspf (SPF) and adkim (DKIM); both default to r. The RFC notes that in practice nearly all domain owners have found relaxed alignment sufficient. DMARC alignment explained covers the Organizational Domain in detail.
Confirm it before you change anything
Two quick looks settle the question: one message's headers, and the rows of your DMARC reports.
In the headers
In Gmail on a computer, open the message, click the three-dot More menu next to Reply and choose Show original, as Gmail Help describes. The top of that page summarizes SPF, DKIM and DMARC, and the raw headers below include Authentication-Results. Find three values in it:
smtp.mailfrom, the domain SPF checked;header.don eachdkim=result, the domain that signed;header.fromon thedmarc=result, the domain DMARC protects.
If header.from is example.com and neither of the other two ends in example.com, you are looking at an alignment failure. If one of them is a subdomain of yours, such as bounces.example.com, and DMARC still fails, look at your record for aspf=s or adkim=s; the section on strict mode below covers that case.
In a DMARC report
Aggregate reports show the same picture for every source at once. In each record, RFC 9990 puts the From domain in identifiers/header_from and the envelope domain in identifiers/envelope_from. The raw results live in auth_results, where SPF may well say pass for the service's domain. The verdict that matters is in policy_evaluated: its spf element is the DMARC-level result, pass only when the SPF domain passed and aligned. A row with pass in auth_results and fail in policy_evaluated is this exact problem, repeated for every message from that source.
Fix 1: sign with your own domain (usually the easier one)
Since DMARC needs only one aligned pass, you do not have to touch SPF at all. Have the service sign its mail with a DKIM key under your domain, so the signature carries d=example.com instead of its own. Nearly every serious sending platform supports this. In its dashboard the option is usually called domain authentication, sender authentication or a custom sending domain, and it hands you two or three DNS records to publish, typically CNAMEs named something like s1._domainkey.example.com that point at keys the platform manages and rotates.
Publish the records exactly as given, wait for the platform to confirm them, then send yourself a test message and check that header.d now shows your domain. You can also look the key up directly: the DKIM key checker takes the selector from the record name (the part before ._domainkey) and shows whether a valid key answers there. If you are unsure which selector a service uses, see how to find your DKIM selector.
DKIM is the better fix for a second reason. When a recipient forwards your message, the next server sees it arriving from the forwarder's IP, and SPF fails there no matter how well you configured it. An untouched DKIM signature survives forwarding, so an aligned signature keeps DMARC passing in cases SPF never can. What is DKIM? explains how the signature works.
Fix 2: a custom return-path on your domain
The other route is to make the envelope sender yours. Many platforms let you set a custom return-path, also called a bounce domain or custom MAIL FROM: you choose a subdomain such as bounces.example.com, publish the DNS records the platform specifies for that subdomain, and the platform starts using that subdomain in MAIL FROM. The SPF check then runs against bounces.example.com, which aligns with example.com under relaxed alignment.
The headers of the earlier example would then read:
Return-Path: <bounce-7f3a@bounces.example.com>
From: Example Shop <news@example.com>
Authentication-Results: mx.receiver.example;
spf=pass smtp.mailfrom=bounces.example.com;
dmarc=pass header.from=example.comOne tempting shortcut does not work: adding the platform's include: to the SPF record on your root domain. As long as the platform sends with its own domain in MAIL FROM, receivers never look at your root record for those messages, so the new include changes nothing for DMARC. It only spends one of your 10 DNS lookups. Add an include to your own SPF record only when the service's documentation says its mail uses your domain in the envelope. The SPF lookup limit is worth keeping in mind before you add anything.
Doing both fixes is the most robust setup. Aligned SPF and aligned DKIM give you two independent ways to pass, so a key rotation gone wrong or a forwarding hop does not drop you straight into your DMARC policy.
When aspf=s is the cause
Sometimes the envelope domain already belongs to you and DMARC still fails. Check your DMARC record for aspf=s. Strict SPF alignment requires the envelope domain to be identical to the From domain, so mail with MAIL FROM at bounces.example.com and From at example.com fails SPF alignment, even though both are clearly yours. The same applies to DKIM with adkim=s when a service signs with a subdomain.
Strict mode is a deliberate choice. RFC 9989 suggests it for domain owners who hand control of subdomains to others, because under relaxed alignment anyone who controls the SPF or DKIM records of a subdomain can produce a DMARC pass for the parent. If no such delegation exists, removing aspf=s returns you to the relaxed default, and the subdomain return-path aligns. If you want to keep strict mode, the message must carry an identifier that matches the From domain exactly; in practice that means a DKIM signature with d=example.com, which aligns even under adkim=s, or an envelope sender at example.com itself. The DMARC record checker shows the record exactly as receivers read it, so you can confirm which tags are actually published.
Finding every affected source with Patchkit
One message tells you about one service. To find every service with this problem, you need your reports. When you add a domain to Patchkit, it gives you a reporting address and parses each aggregate report that arrives. Every source on a report page shows the header From domain, the envelope From domain and the DKIM domains side by side, with separate chips for whether DKIM and SPF aligned, so an SPF pass for someone else's domain is easy to spot. Services we recognise appear by name, and a recognised service that is failing alignment is labelled misconfigured and links to its setup guide. When a server is allowed by your SPF record but its mail is not aligned, the domain page says so and points you to the two fixes above.
How to read DMARC aggregate reports walks through the fields if you prefer to read the XML yourself. If you are tightening alignment because of the new bulk-sender rules, the Gmail, Yahoo and Outlook sender requirements spell out what each provider expects, and once every source aligns, the staged move from p=none to p=reject is the next step. For a quick look at a domain without an account, the email domain health check reports SPF, DKIM and DMARC together.