Most people picture email as one thing: type, click Send, it appears. In reality every message is a small parcel handed through a chain of at least six independent systems, each with its own job. If any link fails or refuses, the message never arrives — and the failure always happens at one specific stage. Learning to find the broken link fast is most of the skill.
This walkthrough is built around a real troubleshooting case (anonymized). The setup: a finance user was emailing a client's CFO. Some messages arrived normally; others bounced. And here's the twist that makes the case worth studying — both the Exchange Online message trace and the outbound gateway logs showed every message as Delivered. On paper, nothing was wrong. Yet the bounces kept coming.
01The journey every email takes
Six stages, six chances to fail.
Between stages 2 and 3, two mail servers actually talk using SMTP — a plain back-and-forth, like a polite phone call. It matters because the responses in that conversation are exactly what later show up in a bounce:
Two things trip everyone up here. First, the envelope (MAIL FROM / RCPT TO — what servers route on) is a different layer from the headers (From / To / Subject — what humans see); they can legitimately differ. Second, every SMTP response is a numbered code whose first digit tells you the whole story: 2xx success, 3xx intermediate, 4xx temporary (will retry), 5xx permanent (bounces). That single digit tells you instantly whether a problem is fatal or will clear on its own.
The key insight
"Delivered" in a message trace usually means "successfully handed off to the next stage," not "the recipient is reading it." This is the single most common source of confusion when troubleshooting — and it's the exact trap in this case.
02Reading the NDR — the most honest document you'll get
The bounce isn't bad news to delete. It's a machine-readable confession.
When a server gives up, it generates a Non-Delivery Report — a bounce, addressed back to the sender, stating exactly what failed. People delete these unread. That's backwards: the NDR is the best diagnostic you have. Here's the one that cracked this case:
550 5.1.2 <cfo@contoso.com>... Host unknown (Name server: contoso-com.mail.protection.outlook.com: host not found)
The enhanced status codes (the dotted number) are worth memorizing — they point straight at the stage that failed:
| 5.1.1 | Recipient mailbox doesn't exist (bad username). |
| 5.1.2 | Destination host can't be resolved — a DNS problem on the recipient side. |
| 5.4.1 | No answer from the destination host (timeout / network). |
| 5.7.1 | Policy rejection — the receiver refused (blocklist, compliance). |
| 5.7.26 | Authentication failure (SPF/DKIM/DMARC) — a sender-side problem. |
03The three locks: SPF, DKIM, DMARC
SMTP has no built-in way to verify who anyone is. These three layers, all riding on DNS, fix that.
fabrikam.com TXT "v=spf1 include:spf.protection.outlook.com -all" _dmarc.fabrikam.com TXT "v=DMARC1; p=reject; rua=mailto:dmarc@fabrikam.com"
When a message you send is rejected with a code in the 5.7.x family (especially 5.7.26), that's an authentication problem on your side — check that SPF, DKIM, and DMARC all pass in the sent message's headers. In this case, they did. Our authentication was clean. The failure was somewhere else entirely.
04The case: a bounce that outran its trace
Clean handoffs on our side, bounces from our own gateway. Follow the chain.
Our outbound path was spotless: Outlook → Exchange Online → outbound gateway, logged successfully at every hop, SPF/DKIM/DMARC all passing. So why the bounce? The clue was who sent the NDR — it came from our own outbound gateway, not the recipient's server. That single fact means the message never reached the recipient's network. The gateway looked up where to deliver, and couldn't.
Three independent tools confirmed it, which matters enormously for what comes next — you never escalate to a third party on your word alone:
A public MX lookup returned the recipient's MX target with no A record. A global DNS propagation check, querying resolvers around the world, agreed. And a native Resolve-DnsName from a workstation confirmed the MX existed and its target did not. Three separate sources, one unambiguous finding: a recipient-side DNS misconfiguration.
05Why some mail still got through
The most counterintuitive part — and the fingerprint that named the cause.
If the recipient's DNS was broken, why did older messages deliver fine? The answer is DNS caching. At some earlier point the MX target did resolve, and our gateway cached that IP. While the cache was warm, deliveries succeeded — even after the underlying record broke. As cache entries aged out, the gateway re-queried authoritative DNS, got NXDOMAIN, and started bouncing. The pattern "older messages delivered, newer ones bounce" is a textbook cache-aging-out signature.
TTL is why the failure was intermittent
Every DNS record has a Time To Live — how long resolvers may cache it. A short TTL means changes (and breakages) propagate fast; a long TTL can hide a problem for a day. Intermittent, "sometimes it works" delivery failures are very often a caching or propagation artifact hiding a hard underlying fault.
06The workflow that catches most of these
Once you've seen one, you see the pattern everywhere.
The communication principle is the part people skip, and it's what separates a diagnosis from a hunch: never escalate to a third party without external, reproducible evidence. "Our trace shows Delivered" is not external — it's the very thing that misled us here. A public DNS lookup the other party can run themselves is external. Build the case from independently verifiable facts, then hand it off.
The one habit
When a trace says Delivered but bounces keep coming, don't trust the trace — read the NDR. Find the server that generated it, read the code, and verify the recipient's DNS from outside. The truth is in the bounce, not the trace.
Further reading
- RFC 5321 — Simple Mail Transfer Protocolthe SMTP conversation and reply codes
- RFC 7489 — DMARCalignment and policy
- RFC 3463 — Enhanced Mail System Status Codesthe 5.x.x status codes
- MXToolboxpublic MX / DNS health checks
Comments
Questions or corrections welcome. Sign in with GitHub to join the thread.