Mail forwarding breaks SPF, and what survives it
The message you sent direct passed SPF. The copy that went through a forwarding alias failed it, from an IP address you’ve never seen, and no change to your SPF record will make that copy pass. Forwarding breaks SPF by design, because the final receiver checks the server that handed it the message, and that server belongs to the forwarder. What survives the hop is a DKIM signature made with your own domain, and DMARC only needs one of the two to pass.
A forwarded message makes three hops, and each check either survives or dies at a particular one.
Hop one: your server sends, and SPF passes
Your mail server connects to the recipient’s provider and announces an envelope sender, the address that bounces would go back to. That address lives in the Return-Path (RFC5321.MailFrom), and it’s the domain SPF is evaluated against. The visible From header plays no part in SPF at all.
The receiving server looks up your domain’s v=spf1 record, finds your server’s IP in it, and records the result:
Authentication-Results: mx.receiver.example;
spf=pass smtp.mailfrom=yourdomain.example;
dkim=pass header.d=yourdomain.example;
dmarc=pass header.from=yourdomain.example
This is the copy you can reproduce. Send yourself a test, open the headers, and this is what you’ll find, which is why the bug looks impossible when someone else reports it.
Hop two: the forwarder retransmits from an address you didn’t list
Now the recipient has set up auto-forwarding, or the address you wrote to is an alias at a registrar, or a university account, or a group address that fans out to members. The forwarder’s server accepts your message and opens a new connection to the next provider to pass it on.
On that new connection the transmitting IP is the forwarder’s, while the Return-Path (RFC5321.MailFrom) is, in most setups, still your domain. The forwarder didn’t write your record and doesn’t appear in it. It’s carrying your envelope sender on its own address.
The message itself hasn’t changed. Your DKIM signature, if you have one, is still sitting in the headers exactly as your server wrote it.
Hop three: the final receiver reads the header and fails the message
The last server in the chain runs the same SPF check the first one did: which IP handed me this, and does the Return-Path domain’s record authorise it? Since the IP belongs to the forwarder and your record only lists your own senders, the answer is no, and the receiver writes it down:
Authentication-Results: mx.final.example;
spf=fail (sender IP is 198.51.100.7) smtp.mailfrom=yourdomain.example;
dkim=pass header.d=yourdomain.example;
dmarc=pass header.from=yourdomain.example
That header is your diagnostic. The direct copy shows spf=pass from your IP; the forwarded copy shows spf=fail from the forwarding service’s IP, while dkim=pass carries a d= that matches your From domain, and DMARC passes on the strength of it. If you see that pattern, forwarding is the cause and your SPF record is behaving as specified.
If instead the forwarded copy shows dkim=pass with a d= that belongs to your mail provider rather than to you, or shows no DKIM at all, DMARC has nothing left to pass on, and that’s the gap to close. A free scan tells you which of those two situations you’re in before you touch DNS.
Why you can’t add the forwarder to your record
The first instinct is to find the forwarding service’s IP range and put it in your SPF record. However carefully you do it, that doesn’t hold up.
You can’t enumerate forwarders, because any recipient, anywhere, can forward your mail through any service they like, and the same message forwarded through a different service tomorrow fails from a different IP. Your record would need to list servers you have no way of knowing about in advance.
Even if you could list them, doing so would defeat the purpose, since a large forwarding service relays mail for millions of customers. Put its ranges in your record and any message any of its users relays, including one from a spoofer who signed up for a free account, passes SPF as you. You’d have authorised strangers to send as your domain to stop a check failing that DMARC was already rescuing.
The same logic rules out changing the qualifier at the end of the record. Of the 150,103,209 domains publishing SPF in the September 2026 census, 84,153,065 end the record in ~all and 57,704,429 end it in -all. Neither group’s forwarded mail passes SPF, because the qualifier decides what a receiver records when an IP isn’t listed, and the forwarder’s IP isn’t listed either way. The argument about which qualifier to use is settled on its own terms in the ~all versus -all piece; for forwarded mail it isn’t the lever.
SRS and ARC are the forwarder’s tools
SRS and ARC both soften this, and if you’ve been told to “implement” one of them for your domain, the advice was aimed at someone else. Neither happens in your DNS or on your server.
| Mechanism | When mail is forwarded | Who runs it | Repairs your DMARC? |
|---|---|---|---|
| SPF | Fails, because the forwarder’s IP isn’t in your record | You publish the record; the forwarder defeats it | No |
| SRS (Sender Rewriting Scheme) | The forwarder rewrites the Return-Path to its own domain, so its retransmission passes SPF | The forwarder | No. The pass belongs to the forwarder’s domain, which doesn’t align with your From |
| ARC (RFC 8617) | The forwarder seals the authentication results it saw; the final receiver may trust the sealed chain | The forwarder and the final receiver | Sometimes, at the receiver’s discretion |
| Aligned DKIM | The signature travels in the headers and still verifies, with your domain on it | You | Yes |
SRS makes the forwarder’s SPF problem go away. Rewriting the Return-Path changes whose record gets checked at hop three, and the resulting pass belongs to the forwarder’s domain. Your From header, the domain DMARC defends, is untouched, so an SRS pass does nothing for your alignment. If a guide tells you to set up SRS as a domain owner, it has confused you with the forwarding provider.
ARC is a trust decision between the forwarder and the final receiver. The forwarder seals what it saw at hop two; the receiver at hop three decides whether it believes that seal. It can help, when both parties support it and the receiver chooses to honour it, and there’s no DNS record you can publish to make that happen.
The half that survives the hop: aligned DKIM
DMARC asks for one aligned pass, SPF or DKIM. When forwarding kills the SPF leg, aligned DKIM keeps the message authenticated, because the signature travels inside the message rather than with the connection.
A DKIM signature is a header your server adds before the message leaves. It’s computed over the headers you chose to sign and over a hash of the body, using a private key whose public half sits in your DNS. Any receiver, at any hop, can fetch that public key and verify the signature. The forwarder’s IP doesn’t enter into it, and neither does the Return-Path. As long as the signed content wasn’t modified in transit, dkim=pass at hop three is the same result as at hop one.
What DMARC checks is alignment: the d= domain in the signature has to match the domain in your From header. Mail providers commonly sign with their own domain by default, and that produces a dkim=pass that DMARC ignores, because the signer isn’t you. The difference in the header is one token:
dkim=pass header.d=yourdomain.example aligned, DMARC can use it
dkim=pass header.d=mail-provider.example passes, does nothing for you
So the work is to turn on DKIM signing with your own domain at each service that sends as you, mailbox provider first, then any marketing platform and transactional sender. Each one needs its own selector and its own key in your DNS. How to set up DKIM walks the records and the checks; the point for this page is that once it’s done, the forwarded copy in your headers reads spf=fail, dkim=pass, dmarc=pass, and the recipient’s spam filter has what it needs.
The one path DKIM doesn’t survive
A mailing list that modifies the message, by adding a subject tag or appending an unsubscribe footer, changes the content the body hash was computed over. At hop three the hash no longer matches, DKIM fails alongside SPF, and DMARC has nothing to pass on.
Only the list can mitigate that, either by rewriting the From to its own domain so DMARC evaluates the list’s authentication rather than yours, or by sealing the message with ARC so a willing receiver can see it was authentic when the list received it. Both are list-side settings and good list software offers them. If your users live on lists that don’t, this residue is what staged DMARC enforcement is for.
What to do with your SPF record and your DMARC policy
Leave the SPF record accurate for the mail you send direct. It still authenticates most of your traffic and gives DMARC its second leg. Widening it to chase forwarders would authorise senders you don’t control, so keep it under the lookup limit and stop expecting it to cover a hop you don’t own. The SPF page covers what an accurate record looks like.
Then move DMARC up in stages. With aligned DKIM live, publish p=quarantine and read the aggregate reports for a few weeks. The reports show you which of your mail flows through rewriting lists and which sending services you forgot to sign, and they show it before any receiver starts bouncing.
Once the report volume from unsigned sources has gone to nothing you can afford, move to p=reject. Don’t jump straight there on a domain whose users are heavy list members, and don’t sit at p=none indefinitely either, because p=none asks receivers to do nothing with a failure, which is where you started.
Do it in that order: diagnose from the Authentication-Results header, confirm the forwarded copy fails SPF alone while DKIM passes, sign with your own domain wherever you send from, verify the d= aligns, and then tighten the policy, leaving the SPF record you were about to edit exactly as it was.
Figures as of 5 September 2026, from the September 2026 edition of the defaults.exposed census. Census numbers move every month; the current values are on the census data page.