DMARC Fails Even Though SPF Passes? How to Fix Alignment
SPF says pass, DMARC says fail, and every checker tool says the domain is fine. The culprit is almost always alignment — a Return-Path that belongs to your vendor instead of you.
SPF says pass, DMARC says fail, and every checker tool says the domain is fine. The culprit is almost always alignment — a Return-Path that belongs to your vendor instead of you.
You open a DMARC aggregate report and it makes no sense: DMARC failing even though SPF passes, row after row.
SPF: pass. DKIM: pass. DMARC: fail. Same message. Same report row.
Every checker comes back green. MXToolbox says the SPF record is valid. The vendor dashboard shows the domain as verified. And yet thousands of invoice notifications from your own domain sit in that XML marked fail, with receivers quietly quarantining a slice of them.
The natural reaction is to re-check the SPF record. Then re-check it again. Because when SPF says pass, your brain stops looking at SPF.
The record is usually fine. It just isn't being asked the question you think it's being asked. What broke is alignment — the part of DMARC nobody explains until it bites you.
We're the JustEmails team — JustEmails is built by Velocity Digital Labs. This is a common DMARC confusion, and it usually hits someone who already did everything right. Record published. Vendor verified. Still failing.
Every email has two "from" addresses. Most people only ever see one.
The envelope sender (RFC5321.MailFrom, surfaced as the Return-Path header) is where bounces go — part of the SMTP conversation, not the visible message.
The header From (RFC5322.From) is the one in the mail client. billing@yourdomain.com. The one carrying your brand and, if spoofed, your reputation.
SPF only ever checks the first one. It takes the connecting IP, looks up the SPF record for the Return-Path domain, and answers yes or no. It has no opinion about the From address. None.
DMARC's job is to bolt those two identifiers together. It runs SPF, then asks a second question SPF never asks: did the domain SPF just validated match the domain in the From header? That question is alignment. If the answer is no, DMARC records fail.
The shape of the failure:
billing@yourdomain.combounces+9f3a1@em4471.vendorhost.netvendorhost.net)vendorhost.net ≠ yourdomain.com)And the part that trips up almost everyone: adding include:vendorhost.net to your SPF record does nothing here. Nothing at all. SPF is still evaluated against the Return-Path domain, which is still the vendor's. You authorized their IPs to send as your domain, but they're not sending as your domain at the envelope layer.
Two tags control how forgiving alignment is. Most people never set them, which is fine — the defaults are the sane ones.
| Tag | Applies to | Default | Relaxed (r) means | Strict (s) means |
|---|---|---|---|---|
aspf | SPF alignment | r | Organizational domains must match | Exact hostnames must match |
adkim | DKIM alignment | r | Organizational domains must match | d= must equal From domain exactly |
"Organizational domain" is the registrable domain, derived from the Public Suffix List. So under relaxed SPF alignment:
bounces.yourdomain.com vs yourdomain.com → aligned ✅em4471.vendorhost.net vs yourdomain.com → not aligned ❌Under strict, only an exact match survives — bounces.yourdomain.com fails against yourdomain.com. Which is why strict breaks so many working setups.
Check yours right now:
dig +short TXT _dmarc.yourdomain.com
# v=DMARC1; p=reject; adkim=r; aspf=r; rua=mailto:dmarc@yourdomain.com; pct=100
If aspf=s is in there and you don't remember putting it there, someone followed a hardening checklist a bit too enthusiastically. More on that below.
Before touching DNS, confirm the diagnosis on one message. Two minutes.
Get a failing message into Gmail. Open it, click the three dots, Show original. (Outlook: View → View message source.) You're looking for exactly three lines.
Return-Path: [bounces+9f3a1@em4471.vendorhost.net](mailto:bounces+9f3a1@em4471.vendorhost.net)
From: "Yourdomain Billing" [billing@yourdomain.com](mailto:billing@yourdomain.com)
Authentication-Results: mx.google.com;
dkim=pass header.i=@vendorhost.net header.s=s1;
spf=pass (google.com: domain of bounces+9f3a1@em4471.vendorhost.net designates 198.51.100.24 as permitted sender);
dmarc=fail (p=REJECT sp=REJECT dis=QUARANTINE) header.from=yourdomain.com
Read it slowly. spf=pass, and right after it, dmarc=fail. The parenthetical even names the domain SPF validated — em4471.vendorhost.net, not yours. And header.i=@vendorhost.net means DKIM signed with the vendor's key, so DKIM alignment is failing too. Both mechanisms passed. Neither aligned. DMARC has nothing to fall back on.
That's the whole bug, in a few lines of text, invisible from every dashboard you'd normally check.
One message tells you a sender is broken. The aggregate report tells you which senders, how many messages, and since when. (No rua=mailto: in your record? Add it. Reports are free.)
They arrive daily as gzipped XML from Google, Microsoft, Yahoo, and anyone else enforcing DMARC. Unzip one, find the <record> blocks. Here's a failing one, trimmed:
<record>
<row>
<source_ip>198.51.100.24</source_ip>
<count>4127</count>
<policy_evaluated>
<disposition>quarantine</disposition>
<dkim>fail</dkim>
<spf>fail</spf>
</policy_evaluated>
</row>
<identifiers>
<header_from>yourdomain.com</header_from>
</identifiers>
<auth_results>
<spf>
<domain>em4471.vendorhost.net</domain>
<result>pass</result>
</spf>
<dkim>
<domain>vendorhost.net</domain>
<result>pass</result>
</dkim>
</auth_results>
</record>
Now compare the two SPF values. This is the tell, and almost nobody knows to look for it:
<auth_results><spf><result> → pass. The raw SPF verdict.<policy_evaluated><spf> → fail. SPF after alignment.Same record, two different answers. When those disagree, alignment is your problem — guaranteed. And <auth_results><spf><domain> hands you the offending Return-Path domain, which usually identifies the vendor on sight.
Two more fields worth reading:
<count> is volume. A source pushing 4,127 messages is production mail you must fix. A source pushing 3 is probably a forwarder — deprioritize it.<policy_published> echoes back your aspf and adkim as the receiver understood them. Handy when you're unsure a DNS change propagated.Parsing XML by hand gets old around report number six, and since each big reporter sends one file per domain per day, report number six lands on day two. dmarcian, Postmark's free DMARC Digests, and Valimail all ingest rua feeds and give you a source-by-source table. Use one, but still open the raw XML when something looks odd — summaries can hide the auth_results versus policy_evaluated split that explains the failure.
(Running several brands? Point every domain's rua at one parsing inbox, so there is one place to look.)
Three real fixes, in order of preference.
Option A — set a custom Return-Path at the vendor. The right fix. Nearly every serious platform supports it; they just bury it under a different name each time.
em4471.yourdomain.com → u12345678.wl.sendgrid.net. Once live, the envelope sender moves under your organizational domain and relaxed alignment passes.10 feedback-smtp.us-east-1.amazonses.com) plus a TXT record "v=spf1 include:amazonses.com ~all" on it.mg.yourdomain.com with the DNS records Mailgun gives you on it.Same pattern everywhere: a subdomain of yours, DNS pointed at their infrastructure, bounce address under your registrable domain.
Four vendors, four names for one feature. When a vendor's docs turn up nothing for "Return-Path", search them for "bounce" instead.
Option B — fix DKIM alignment instead and let SPF fail. DMARC only needs one aligned mechanism. If a vendor won't give you a custom Return-Path but will sign DKIM with your domain, that's enough — spf=fail in policy_evaluated forever, dmarc=pass anyway. Ugly in reports. Works perfectly. If the vendor shows dkim=none instead, different problem: fixing DKIM for third-party senders.
DKIM alignment is the sturdier of the two anyway. It survives forwarding; SPF alignment doesn't.
Option C — move the sender to a delegated subdomain. Send from notifications@mail.yourdomain.com and hand that subdomain's authentication to the vendor wholesale. Apex reputation stays clean. Our dedicated sending subdomain guide walks the DNS.
What doesn't work: piling more include: statements into your SPF record. A fourth and fifth vendor include added to chase an alignment failure only inches you toward the ten-lookup ceiling — at which point SPF returns permerror and you've broken the mechanism that was working. Near that line? SPF flattening and the 10-lookup limit is the post you want.
DNS first. Confirm the record exists before clicking any verify button:
dig +short CNAME em4471.yourdomain.com
dig +short TXT em4471.yourdomain.com
Then send a real message through the vendor — not a dashboard test, an actual production-path send, because some platforms use a different envelope for test mail. Show original, confirm Return-Path sits under your domain and dmarc=pass appears. (If those test sends go out through JustEmails, budget them against the account's daily sending ceiling, which counts mailbox and API sends together: for a newly verified domain, no more than 50 a day in the first week, 200 in the second, and up to 500 from day 15.)
Then wait. Aggregate reports lag 24 to 72 hours, so that 4,127-message source won't clear until the next window closes. Don't panic-revert on day one — it just adds a second variable.
Plenty of the harden-your-DMARC checklists out there tell you to set aspf=s; adkim=s. Skip it. I'll go further: if a checklist recommends strict without first asking what you send from and who sends on your behalf, stop reading that checklist.
Strict breaks subdomain senders, vendor bounce hosts, gateway-routed mail, and half your integrations — and buys almost nothing, because relaxed already requires an attacker to control a hostname under your registrable domain. If they've got that, you have a much larger problem than DMARC tags.
Strict fits a narrow case: an aggressive brand-protection program with every sender enumerated and monitored. If you landed here because invoices are going to spam, it's the opposite of what you need. Get to p=reject with relaxed alignment first — our DMARC ramp-up guide covers that path — and leave the tags alone.
spf=pass in headers, <policy_evaluated><spf>fail in reports. The one from the top of this post. Option A, or Option B if the vendor won't budge.
Everything was passing, then you added aspf=s and half your mail broke. Strict is now rejecting your own subdomain senders. Drop back to aspf=r and re-check in 48 hours.
A sender aligns on some messages, fails on others. Almost always two sending paths sharing one From address: your own mail server handling password resets, a vendor handling the marketing blast, each arriving from a different <source_ip>, each needing its own fix, and the daily report quietly averaging both into one row that looks like intermittent flakiness.
dmarc=fail on forwarded mail, everything else correct. A forwarder resends your message from its own server, so SPF alignment dies at the first hop. Expected. Not a misconfiguration. You can't fix other people's mailing lists, so don't burn a Saturday on it.
Vendor dashboard says "verified," reports still say fail. Verification usually means only that your SPF include and DKIM CNAME resolved. It does not mean a custom Return-Path is active. Two separate toggles at most vendors, and only one of them earns you a green check.
Trust the raw header. Not the dashboard.
Because SPF and DMARC check different domains. SPF validates the sending IP against the Return-Path domain (the envelope sender, also called RFC5321.MailFrom). DMARC then asks a second question SPF never asks: does that Return-Path domain match the From address your recipient actually sees? When a third-party tool sends for you, the Return-Path usually belongs to the vendor — something on sendgrid.net, mcsv.net, or amazonses.com — while the From address is yours. SPF passes for the vendor's domain, alignment fails for yours, and DMARC records a fail. Adding the vendor's include: to your SPF record does not fix this, because SPF is still evaluated against the vendor's domain, not yours.
Relaxed alignment (aspf=r, adkim=r — the default when you omit the tags) requires only that the organizational domains match. So a Return-Path of bounces.yourdomain.com aligns with a From address at yourdomain.com, because both resolve to the same registrable domain under the Public Suffix List. Strict alignment (aspf=s, adkim=s) requires an exact hostname match, so bounces.yourdomain.com would fail against yourdomain.com. Relaxed is the default for a reason: it already blocks the spoofing that matters, because an attacker still can't get a Return-Path under your organizational domain.
Open the raw source. In Gmail, click the three-dot menu on the message and choose Show original. In Outlook, use View then View message source. Then look for the Return-Path header near the top — that domain is what SPF was actually checked against. Compare it to the From header. If they share a registrable domain, SPF alignment passes under relaxed mode. If the Return-Path is on a vendor host and the From is on yours, you've found the failure. The Authentication-Results header confirms it: you'll see spf=pass on one line and dmarc=fail on another.
Almost certainly not. Strict alignment breaks a long list of legitimate setups — subdomain senders, vendors that use a per-customer bounce host, mail routed through a gateway — and buys very little extra protection, because relaxed mode already requires the attacker to control a hostname under your registrable domain. The teams that genuinely need aspf=s are the ones running an aggressive brand-protection program with every sender enumerated and monitored. If you're reading this post because your invoices are landing in spam, strict is the opposite of what you want. Fix the Return-Path first.
Unlimited custom domain email hosting for $49/year flat — unlimited domains, unlimited mailboxes, 10 GB storage, full IMAP/SMTP. Built for agencies, freelancers, and anyone managing email across more than one domain.