Skip to content
← BlogDeliverability6 min read

How to read email headers like a postmaster

Received chains read bottom-to-top, Authentication-Results don't lie, and a five-minute header read explains most delivery mysteries. A field guide.

By David Lara, Founder

Founder-reviewed ·How we research and correct articles

Every email carries its own flight recorder. Hidden above the message you read is the full forensic record: every server it passed through, when, what each one thought of the sender, and which security checks passed or failed. When something goes wrong — delays, spam placement, a suspicious message — the headers usually contain the entire answer.

Most people never look, because raw headers are genuinely ugly. Five concepts fix that.

Getting the headers

  • Gmail: open the message → three-dot menu → Show original.
  • Outlook: open the message → ViewView message source.

You’ll get a wall of text. Copy all of it — and either read on, or paste it into our free Email Header Analyzer, which renders the verdicts and the route as a table, in your browser, nothing uploaded.

1. The Received chain reads bottom-to-top

Each server that handles a message stamps a Received: header on top of the existing ones. So the bottom Received is the origin — the server closest to the sender — and the top is the final delivery. Read it bottom-up and you have the route.

Two things to extract:

  • The origin. Does the first hop make sense for the claimed sender? An invoice “from your bank” that originates at a residential ISP in another country has already told you everything.
  • The timestamps. Subtract each hop from the next. The route should take seconds. A gap of minutes or hours at one hop is where your “email was slow” mystery lives — typically greylisting (a deliberate first-attempt rejection forcing a retry), rate limiting, or an overloaded queue.

2. Authentication-Results is the verdict line

Near the top you’ll find the receiving server’s own scorecard:

Authentication-Results: mx.google.com;
  spf=pass smtp.mailfrom=example.com;
  dkim=pass header.d=example.com;
  dmarc=pass header.from=example.com

This is the receiver telling you, in one line, how SPF, DKIM and DMARC scored the message. For your own mail, this line is the ground truth of your setup — send yourself a test and read it. The classic find: dkim=pass but on header.d=yoursendingtool.com instead of your domain — a valid signature that does nothing for your alignment.

3. From vs Return-Path: the two-sender trick

From: is what the recipient sees; Return-Path is the envelope address the SMTP conversation actually used. They legitimately differ (most sending platforms route bounces through their own domain) — but the combination of a mismatched Return-Path, a Reply-To pointing at a third, unrelated domain, and failing authentication is the standard anatomy of a phish.

4. The minor headers that talk

  • Message-ID — its domain should roughly match the sending org.
  • X-Mailer / User-Agent — what software sent it; bulk tools announce themselves here.
  • Received-SPF — SPF’s working notes, useful when the verdict line is terse.
  • A hop with tls or ESMTPS in its Received line was encrypted in transit; whether your own domain enforces that is a separate check — our MTA-STS & TLS-RPT Checker reads the policy in one pass.

A worked example: reading a real chain

Here’s a trimmed, representative Received chain — three hops, oldest at the bottom the way it actually appears in a raw header dump:

Received: by mx.google.com with SMTP id abc123
    for <you@example.com>; Tue, 14 Jul 2026 09:14:02 -0700 (PDT)
Received: from mail-relay-03.senderdomain.com (mail-relay-03.senderdomain.com [198.51.100.44])
    by mx.google.com with ESMTPS id xyz789
    for <you@example.com>; Tue, 14 Jul 2026 09:13:58 -0700 (PDT)
Received: from localhost (unknown [203.0.113.9])
    by mail-relay-03.senderdomain.com with ESMTP id def456
    for <you@example.com>; Tue, 14 Jul 2026 08:47:11 -0700 (PDT)

Reading bottom to top: the message originated at 203.0.113.9 at 08:47:11, handed off to the sender’s own relay (mail-relay-03.senderdomain.com), which then delivered to Google at 09:13:58 — roughly 26 minutes later. That gap is the tell. A healthy hop takes seconds; 26 minutes between the first and second hop, with nothing unusual at the third, points to the relay itself queuing or retrying, not a network problem downstream. If this were a live delivery complaint, that’s exactly where you’d start looking — not at content, not at the recipient’s filter settings, but at whatever the sending relay was doing for those 26 minutes (commonly a temporary rate limit or a queue backup on the sender’s side).

Notice, too, that the origin IP (203.0.113.9) and the relay’s own IP (198.51.100.44) are different machines — normal for any setup where outbound mail routes through a dedicated sending service rather than the originating server talking directly to Gmail. What would be a red flag is that same origin IP resolving to a residential ISP block or a country with no plausible connection to the claimed sender; that mismatch, on its own, is often enough to explain a delivery or spam-placement mystery without reading another header.

What a suspicious set of headers looks like

Contrast that ordinary chain with the anatomy of a typical phishing attempt: the origin hop resolves to a residential or hosting-provider IP with no relationship to the claimed sender, Authentication-Results shows spf=fail or dkim=none rather than a clean pass, the Return-Path domain has nothing to do with the From: domain, and a Reply-To header quietly redirects replies to a third domain entirely different from both. Any one of those alone can have an innocent explanation — legitimate services frequently set a different Reply-To on purpose. It’s the combination, arriving together on one message, that’s the reliable signal: a real sender rarely fails authentication, originates somewhere implausible, and redirects replies elsewhere, all at once.

The five-minute diagnostic, assembled

Delivery mystery? Pull headers and ask, in order: where did it originate (bottom Received) → where did it stall (timestamp gaps) → what did the receiver verify (Authentication-Results) → do the sender identities agree (From / Return-Path / Reply-To / Message-ID)? To identify any mystery server along the way, our DNS Lookup resolves it both directions.

Frequently asked questions

Why do the timestamps in different Received headers sometimes look out of order? Each server stamps its own local clock, and clocks drift — usually by seconds, occasionally by more on a misconfigured server. Compare the UTC offsets, not just the raw times, and treat a few seconds of apparent disagreement as normal rather than a sign of tampering.

Is a dkim=pass always good news? Only if the signing domain (header.d=) matches the domain you actually care about. A message can show a perfectly valid dkim=pass signed by a sending platform’s own shared domain — technically true, but doing nothing for your own domain’s alignment or reputation, which is the distinction that trips up most people the first time they read this line closely.

Can headers be faked? The visible ones a client shows you by default — From, Subject, Reply-To — are trivially easy to set to anything. That’s exactly why Received and Authentication-Results matter more: they’re written by servers along the delivery path, not by the sender, so forging them convincingly requires actually controlling infrastructure along that path rather than just editing a compose window.

That’s the whole skill. The flight recorder was always on — postmasters just know where the panel is.