Why Did My Email Bounce? What 21 Mailbox Providers Said When SPF Failed

Why Did My Email Bounce? What 21 Mailbox Providers Said When SPF Failed

Estimated reading time: 14 minutes

When a message doesn’t arrive, the bounce is often the only explanation a sender gets: a reply code, a line of text, and whatever the sending platform makes of them. We wanted to know how much a bounce actually tells you when the problem is SPF.

In October 2026, we published 13 SPF configurations, two clean controls and eleven variations on common SPF mistakes, and sent about 3,800 messages using those configurations to GlockApps seed mailboxes at 21 mailbox providers and five spam filters. Every test domain published a DMARC policy of p=reject. Except for one control on each sending path, the messages carried no aligned DKIM signature, so DMARC depended on SPF alone. This post covers what the receivers’ replies said, that failed messages never bounced, and how an ESP sorted the failures. The full data is in part two of the DMARKOFF study; where the messages landed is in our earlier post on the same test.

Disclosure: GlockApps and DMARKOFF are built by the same team. All domains, IPs, and accounts in the test were our own; the Mailgun account was an ordinary customer account.

Key takeaways

  • Most authentication refusals cited DMARC, not the SPF mistake. When SPF didn’t pass, and no aligned DKIM signature could pass DMARC instead, most large providers refused the message under p=reject. Gmail answered 550 5.7.26, Microsoft 550 5.7.509, and Yahoo 554 5.7.9. None of these replies named the SPF mistake itself.
  • On our own server, most refusals were about the sending IP. 1,692 of 2,147 refused messages hit a blocklist or a dynamic-IP policy, and several replies used 5.7.1, a code many authentication refusals also used. The SMTP step and the reply text told the two apart.
  • Some failed messages never produced a bounce. Seznam accepted failing messages with 250 OK and never delivered them to the seed mailbox, and Naver and Amazon WorkMail did the same with some messages sent through Mailgun. None of them sent anything back.
  • A message can show up as delivered and then as failed. Microsoft 365 accepted messages sent through Mailgun that failed DMARC and bounced them 2 to 17 seconds later.
  • Some soft bounces hid a permanent problem. ukr.net and Interia answered some broken records with 451 until the sender gave up.
  • The ESP’s category matched the wording of the reply. In our run, Mailgun filed refusals that cite DMARC as espblock and those that cite SPF as generic, and none of its 188 permanent failures added a recipient to the suppression list.

How we tested

Each configuration lived on its own subdomain, which served as both the From and the MAIL FROM domain. Besides the two controls, the cases covered a record that needs 11 DNS lookups, three void lookups, an include that points to a name without an SPF record, typos such as include= and includes:, a deprecated ptr, two SPF records, and no record at all.

We sent every case along two paths. Our own server, on a fresh AWS address, logged each SMTP reply together with the step it came at: the connection, the sender address (MAIL FROM), the recipient (RCPT TO), or the end of DATA, after the message body had been transmitted. A small bounce server on the same host, the MX of every test domain, waited for bounce messages. For the second path, we sent through Mailgun and read each receiver’s reply from Mailgun’s event log, along with Mailgun’s own reason, severity, and retries, which we downloaded through its API on 25 October. We used the GlockApps MCP server to start the seed tests and collect the results. An AI assistant matched the seed results with the sending logs for the same messages.

We count each sent message once per recipient, by its final outcome. Delivery retries are attempts, not additional messages, and where a number counts attempts, we say so. ESPs usually call every failed delivery a bounce. Below, a refusal is a rejection during the SMTP session, and a bounce message is one the receiver sends after it has accepted the mail.

These are observations from 21–23 October 2026, from one sending IP of our own and one Mailgun account, not a forecast for every sender. Our IP ended up on a blocklist, so most large providers refused it on the direct path before evaluating authentication. Their authentication replies come from the Mailgun run, where we had one or two seeds per mailbox type.

Four ways a failed message can end

In our test, every message that didn’t reach the seed mailbox ended in one of four ways. A seed test shows all four the same way, as Missing in Inbox Insight. The sending log is where they differ.

OutcomeWhat the sending side recordsExamples from our test
Refused during the SMTP sessionA permanent 5xx reply (a hard bounce)Gmail, Outlook.com, Yahoo, Apple, GMX, and most other large providers
Accepted, then bounced250 OK (delivered in an ESP’s log), then failed when the bounce message arrivesMicrosoft 365, through Mailgun
Accepted and dropped250 OK (delivered), and no bounce afterwardSeznam; Naver and Amazon WorkMail, through Mailgun
Deferred until the sender gave upRepeated 4xx replies, a soft bounce, then the sender’s own final failureukr.net, Interia

Dropped: accepted at SMTP, with no bounce received and no copy in the seed mailbox by 25 October, two days after the last run. The examples cover the failing cases.

These rows describe how the failure became visible, not whether it was permanent. A permanent failure, a hard bounce, can come back during the SMTP session or in a later bounce message, as Microsoft 365’s did. Temporary replies, soft bounces, lead to retries and can end in a final failure. A silent drop leaves no bounce to classify. Our guide to hard and soft bounces covers the general difference; the rest of this post looks at what the replies said when the problem was authentication.

What receivers said when SPF failed

These are the permanent refusals for the failing cases in the Mailgun run, abridged:

ReceiverReplyNames
Gmail, Google Workspace550 5.7.26 Unauthenticated email from … is not accepted due to domain’s DMARC policyDMARC
Outlook.com, Hotmail550 5.7.509 Access denied, sending domain … does not pass DMARC verification and has a DMARC policy of rejectDMARC
Yahoo, AOL, AT&T554 5.7.9 This mail has been blocked because it failed authentication checks against the sending domains DMARC policyDMARC
Apple iCloud554 5.7.1 Your message was rejected due to …’s DMARC policyDMARC
GMX, WEB.DE, mail.com554 Transaction failed Reject due to sender domain’s DMARC policyDMARC
Interia550 5.7.1 … Rejected due to SPF or 550 5.5.2 … Rejected due to SPF with invalid content, depending on the caseSPF
Naver550 5.7.1 Sender rejected because SPF check failed, for one case¹SPF
Onet550 5.7.0 DMARC policy violation, 550 5.7.23 … SPF fail – not authorized, or 554 5.7.1 Rejected, depending on the caseDMARC, SPF, or neither
mailo550 Security issue – see https://policy.mailo.com/…neither
Barracuda (filter)550 permanent failure for one or more recipients (…:blocked)neither

¹ Through Mailgun, Naver refused only the include= typo; it accepted the other failing messages and didn’t deliver them.

Most large providers named DMARC, and that’s accurate: the message failed DMARC because SPF didn’t pass and there was no aligned DKIM signature to pass it instead. But the reply doesn’t say what broke. A sender who gets 5.7.26 from Gmail learns that authentication failed, not that an include points to a name without an SPF record or that include: was mistyped as includes:. Interia, Naver, and Onet named SPF in at least some of their replies, and mailo and Barracuda gave no specific diagnosis.

The enhanced status codes don’t fill the gap. The standards define codes for exactly these failures: 5.7.23 for an SPF fail, 5.7.24 for an SPF error, and 5.7.26 when several authentication checks failed. Only Gmail (5.7.26) and Onet (5.7.23, for one case) used them. Microsoft’s 5.7.509 is its own code, and Yahoo’s 5.7.9 is registered for something else: SMTP AUTH, the login between a mail client and its server. So read the text along with the code. Our post on 550 SMTP errors covers the other reasons a server sends a 550.

Blocked IP or broken record?

On our own server, most refusals had nothing to do with SPF. Our brand-new AWS address was in the Spamhaus PBL, and 1,692 of the 2,147 refused messages hit a blocklist or a dynamic-IP policy. A few of those replies:

ReceiverStepReply (abridged)
Yahoo, AOL, AT&TMAIL FROM553 5.7.2 [TSS09] All messages from <our IP> will be permanently deferred; Retrying will NOT succeed
Outlook.com, HotmailMAIL FROM550 5.7.1 Service unavailable, Client host [<our IP>] blocked using Spamhaus
Apple iCloudRCPT TO550 5.7.1 Mail from IP <our IP> was rejected due to listing in Spamhaus PBL
ZohoRCPT TO550 5.7.1 Mail rejected by <Zoho Mail> for policy reasons. We generally do not accept email from dynamic IPs

Several of these replies use 5.7.1, which also appears in the authentication refusals above, and Yahoo calls a permanent refusal “permanently deferred”. Two things set them apart. They came early: 406 when we connected, 999 at MAIL FROM, and 287 at RCPT TO, all before the receiver had seen the message. And they hit the clean controls exactly like the broken records. Of the 455 refusals on SPF or DMARC, 425 came after the message body, and the other 30 came at RCPT TO, all from Interia and Onet.

If a reply explicitly cites an IP blocklist or a dynamic-IP restriction, investigate that restriction first: changing the SPF record alone won’t remove it. You can check the sending IP’s blocklist status.

Delivered, then failed

Bounce messages were rare. Our bounce server ran from before the pilot run until 25 October and received none: no bounce message for any of the 1,033 messages accepted on the direct path, including those that never reached a mailbox.

Through Mailgun, one receiver did send bounces. Microsoft 365 accepted 17 messages with 250 2.6.0 … Queued mail for delivery and returned each of them 2 to 17 seconds later with 550 5.7.509. Mailgun matches a bounce message to the original message, so its log shows the same message twice: first delivered, then failed. A day and a half later, Microsoft 365’s DMARC aggregate reports listed 14 of the 17 messages with the disposition reject.

Any report that counts a message as soon as the delivered event appears counts these as delivered. The 2 to 17 seconds is what we saw in this run, not a safe waiting period.

Seznam, Naver, and Amazon WorkMail sent nothing for the failing messages they accepted but didn’t deliver. The seed mailboxes showed that those copies never arrived, and Seznam’s DMARC aggregate reports listed its drops with the disposition reject. Our earlier post covers those drops in more detail.

Soft bounces that never cleared

A temporary error tells the sender to try again later, and both of our paths did. Some temporary errors in our logs cleared on a later attempt: Interia greylisted new senders with 451 4.7.1 … Greylisting in action, freenet answered 457 Greylisted, please come back later, and Gmail rate-limited our new domains with 421 4.7.28.

Two receivers used temporary errors for broken records, and those never cleared:

  • ukr.net answered the include that points to a name without an SPF record with 451 4.1.0 Temporary error during SPF verification. By the standard, that record is a permanent error.
  • Interia answered the mistyped mechanism with 451 4.4.3 … Deferred due to SPF with invalid content and the domain without a record with 451 4.4.0 … Deferred due to SPF unsafe.

Our server made five or six attempts in total over a little more than two hours and then stopped. Mailgun retried 10, 20, 35, 65, 125, and 245 minutes after the first attempt and gave up at the eight-hour mark with 602 Too old, a code of its own: the receivers only ever said 451.

Repeated SPF-related deferrals are a reason to inspect the record before the retry window runs out. In our test, the records were broken on purpose, and retries didn’t resolve those failures.

How the ESP sorted the failures

Mailgun files every failure under a reason. In our run, they fell under three:

Mailgun reasonSeverityWhat it covered in our runCount
espblockpermanentrefusals that cite DMARC, plus mailo’s Security issue170 messages
genericpermanentrefusals that cite SPF or give no specific reason15 messages
generictemporaryevery deferral, from greylisting to ukr.net’s SPF error24 attempts
oldpermanentMailgun giving up after eight hours of deferrals3 messages

In our run, every refusal that cited DMARC was filed as espblock, and every one that cited SPF as generic. Onet’s refusals landed under both reasons, and a team that watches only espblock would have missed all the refusals that cited SPF. Mailgun’s bounce classification report was narrower still: it listed 89 of the 170 espblock refusals, under six provider labels, and none of the generic ones.

None of these failures added a recipient to Mailgun’s suppression lists. We emptied the lists for all 13 domains right before the run, and two days later they were still empty. An invalid address did trigger suppression the day before, during warm-up: after a freenet address bounced with 550 unrouteable address from two of our domains, Mailgun refused to send to it from two others as well, with 605 Not delivering to previously bounced address.

Not suppressing recipients after an authentication failure is what you want once the record is fixed. These are the reasons and lists one Mailgun account showed for one run, so check how your own ESP classifies and suppresses before you rely on it.

What to check when mail bounces after an SPF change

  1. Read the whole reply. The basic code says whether the failure is temporary (4xx) or permanent (5xx). Use the text, the enhanced code, and the SMTP step together to investigate the cause.
  1. Rule out an IP block. If the reply explicitly cites an IP blocklist or a dynamic-IP restriction, investigate that restriction; changing the SPF record alone won’t remove it.
  1. When the reply reports a DMARC failure, check alignment. It means neither SPF nor DKIM passed with alignment to the From domain. Validate the SPF record, and check the d= domain of your DKIM signature.
  1. Investigate repeated SPF-related deferrals. If you find a configuration error, fix it while the sender is still retrying.
  1. Don’t treat delivered as final. Watch for failed events after delivery, and match each Missing seed with your sending log to tell a refusal from a later bounce or a drop.
  1. Watch every failure reason your ESP uses, not only the one named for blocks, and check the suppression lists after you fix a problem.
  1. Use DMARC aggregate reports for the failures that never bounce, for the providers that send them. DMARKOFF collects them and shows each receiver’s verdict.

Conclusion

A delivery-failure report can carry the receiver’s reply or the sending platform’s own explanation, like Mailgun’s 602 Too old. In our test, both often told only part of the story: most authentication refusals named DMARC rather than the SPF mistake, IP-policy refusals shared the 5.7.1 code with authentication refusals, and some failed messages produced no bounce at all. Part two of the DMARKOFF study has every reply, the counts, and the raw data.

FAQ

Why did my email bounce with a DMARC error when my domain has an SPF record?

A DMARC refusal means neither SPF nor DKIM passed with alignment to your From domain, and the domain’s policy asks receivers to reject such mail. A published SPF record can still fail. In our test, the messages carried no aligned DKIM signature, and most large providers refused them when the record included an SPF include without an SPF record, a typo, or a second record; Microsoft, Apple, and others refused a record over the 10-lookup limit. Their replies cited DMARC, not the SPF mistake.

Is a DMARC rejection a hard bounce or a soft bounce?

In our test, the DMARC refusals were hard bounces: permanent 5xx replies. Separately, two receivers answered some broken SPF records with temporary 451 replies that named SPF. Those soft bounces kept coming back until the sender gave up.

Why does my ESP show an email as delivered and then as bounced?

The receiver accepted the message and then sent a bounce message. In our test, Microsoft 365 did this with every message sent through Mailgun that failed DMARC, 2 to 17 seconds after accepting it.

Why didn’t I get a bounce when my email never arrived?

Some receivers accept a message and then don’t deliver it, without sending anything back. In our test, Seznam did this with every failing message, and Naver and Amazon WorkMail did it with some failing messages sent through Mailgun. A seed test shows which copies went missing, and DMARC aggregate reports from the providers that send them can show the rejection.

Related Posts

How to Fix Cold Email Deliverability Issues

Cold email campaigns can lose effectiveness surprisingly quickly. Messages that previously reached prospects start landing in spam, bounce rates increase, Read more

Best Digital Marketing Tools

An email campaign can fail before the first click: the message lands in spam, the mobile layout breaks, or a Read more

Broken SPF Record Send Your Email to Spam

Your ESP says the message was delivered, your SPF checker says the record has a problem, and nothing tells you Read more

How to Improve Email Deliverability for High-Volume Campaigns

A campaign can show a high delivery rate while thousands of messages sit in spam. The receiving servers accepted the Read more

AUTHOR BIO

Aliaksandr Markau
Co-founder & CTO

Co-founder & CTO at DMARKOFF and GlockApps, email security specialist with 20+ years of experience, Golang & ClickHouse expert. A happy father of two teenagers.