Email Header Analyzer
Developer Tools · Added
Every server that handles a message adds its own Received line to the top, so a raw header block reads backwards. This reverses it into travel order, puts the delay beside each hop, decodes the subject if it was encoded, reads the SPF, DKIM and DMARC verdicts — and says who asserted them, which is the part that decides whether they mean anything.
Result
Subject
Invoice for August
Decoded from an RFC 2047 encoded word — the form any non-ASCII subject travels in.
- Hops
- 2
- Total transit
- 2m 42s
- Headers
- 11
Authentication
smtp.mailfrom=bounces.sender.example
header.d=sender.example
header.from=sender.example
SPF says the sending server was allowed to send for the envelope domain. DKIM says the message carries an intact signature from a domain. DMARC says the visible From domain lines up with one of those. Only the third is about what the reader actually sees.
What stands out
- Longest hop: 2m 42s at step 2. The message waited at inbound.mailhost.test before moving on. A delay of minutes usually means greylisting or a queue; hours normally means a retry after a temporary failure.
- Results asserted by inbound.mailhost.test. These verdicts are only worth what the server that wrote them is worth. If that hostname is not your own mail infrastructure, the header could have been written by anyone, including the sender.
- Reply-To points somewhere other than From. Replies would go to accounts-payable@unrelated-domain.test, not billing@sender.example. When the two domains are unrelated this is the standard shape of a business email compromise attempt: a real-looking sender with the conversation quietly redirected.
- This is bulk mail. A List-Unsubscribe header means the sender is a mailing platform. Legitimate marketing carries it; so does anything trying to look like legitimate marketing.
Summary
- Subject
- Invoice for August
- From
- "Billing" <billing@sender.example>
- To
- you@mailhost.test
- Date
- Tue, 12 Aug 2026 09:12:08 +0000
- Return-Path
- bounce-9921@bounces.sender.example
- Message-ID
- <20260812091208.9921@sender.example>
- Hops
- 2
- Total transit
- 2m 42s
Delivery path, in travel order
| # | From | To | Protocol | Time | Delay |
|---|---|---|---|---|---|
| 1 | smtp.sender.example (smtp.sender.example [198.51.100.9]) | mx.example.net | ESMTP | 2026-08-12 09:12:10 | — |
| 2 | mx.example.net (mx.example.net [203.0.113.24]) | inbound.mailhost.test | ESMTPS | 2026-08-12 09:14:52 | 2m 42s |
Each server prepends its own Received line, so the raw block reads backwards — the bottom line is the first hop. This table has been reversed into travel order. Times come from each server's own clock, so a small negative gap means a clock is off rather than that anything is wrong.
Every header, as parsed
| Header | Value |
|---|---|
| Received | from mx.example.net (mx.example.net [203.0.113.24]) by inbound.mailhost.test with ESMTPS id 4Xk2p1 for <you@mailhost.test>; Tue, 12 Aug 2026 09:14:52 +0000 |
| Received | from smtp.sender.example (smtp.sender.example [198.51.100.9]) by mx.example.net with ESMTP id 9Qa77b for <you@mailhost.test>; Tue, 12 Aug 2026 09:12:10 +0000 |
| Authentication-Results | inbound.mailhost.test; spf=pass smtp.mailfrom=bounces.sender.example; dkim=pass header.d=sender.example; dmarc=pass header.from=sender.example |
| Return-Path | <bounce-9921@bounces.sender.example> |
| From | "Billing" <billing@sender.example> |
| Reply-To | accounts-payable@unrelated-domain.test |
| To | you@mailhost.test |
| Subject | =?UTF-8?B?SW52b2ljZSBmb3IgQXVndXN0?= |
| Date | Tue, 12 Aug 2026 09:12:08 +0000 |
| Message-ID | <20260812091208.9921@sender.example> |
| List-Unsubscribe | <https://sender.example/unsubscribe/9921> |
Everything above the first server you control can be fabricated, and on a phishing message it usually is — a forged header block is written to look consistent. What resists forgery is the Authentication-Results line your own receiving server added, which is why this shows who asserted each verdict rather than only the verdict.
Parsing happens entirely in this tab. Headers carry addresses, internal hostnames and internal IP addresses, and none of it is uploaded, logged or stored.
How to use the email header analyzer
- 1Open the original message in your mail client: "Show original" in Gmail, "View message details" in Outlook, View › Message › All Headers in Apple Mail.
- 2Copy the whole header block, from the first line down to the blank line before the body, and paste it in.
- 3Read the delivery path for where a message was delayed, and the authentication panel for whether it is who it says it is.
- 4Check the findings list — mismatches between From, Return-Path and Reply-To show up there.
Examples
Finding where a message was held up
- Input
- A chain of four Received lines
- Result
- Each hop with the gap since the previous one, longest highlighted
Minutes usually means greylisting or a queue; hours means a retry after a temporary failure.
A subject that looks like line noise
- Input
- =?UTF-8?B?SW52b2ljZSBmb3IgQXVndXN0?=
- Result
- Invoice for August
RFC 2047 encoded words are how any non-ASCII subject travels. Undecoded they are unreadable.
The shape of a redirect attempt
- Input
- From at one domain, Reply-To at an unrelated one
- Result
- Flagged, because it is the standard pattern of a business email compromise
The message looks right and the conversation quietly goes somewhere else.
About the email header analyzer
What a header block is
RFC 5322 defines a message as a header block, a blank line, and a body. Each header is a name, a colon and a value, and a long value may be folded across several lines by starting the continuation with a space or a tab. Unfolding has to happen before anything else is parsed — a wrapped Received line otherwise looks like two hops, and a wrapped Authentication-Results header loses half its verdicts.
Beyond a handful of required fields, anything can be a header. Filtering products, mailing platforms and mail servers all add their own, which is why a real message has forty or fifty of them and most begin with X-. Those carry spam scores, campaign identifiers, tenant names and routing decisions, in formats that are specific to each vendor and standardised nowhere, so they are shown raw.
The three addresses a message has
A message carries at least three sender identities and they do not have to agree. The envelope sender, recorded as Return-Path, is where bounces go and is what SPF checks. The From header is what the reader sees. Reply-To, if present, is where a reply is addressed. Every bulk mail platform separates the first two legitimately — bounces go to their infrastructure while the From shows the client's domain — and so does every spoofing attempt.
What distinguishes them is DKIM alignment. A legitimate platform signs with a key for the From domain, or one the From domain has authorised, so DMARC passes despite the mismatch. A spoof cannot do that without the domain's cooperation. This is why a Return-Path mismatch on its own is only worth a note, while a DMARC failure is worth an alert.
Reply-To pointing at an unrelated domain is the sharpest single signal in an ordinary header block. It is the mechanism of business email compromise: the message looks like it came from a colleague or a supplier, and the reply — with the changed bank details in it — goes to the attacker.
Reading the timings
Each Received line ends with a timestamp written by the server that added it, from that server's own clock. Subtracting consecutive timestamps gives the delay at each hop, and that is what turns a header block into an answer to "why did this take four hours".
A gap of seconds is normal. A gap of a few minutes at one hop is usually greylisting, where a receiving server deliberately defers a first delivery attempt from an unknown sender and accepts the retry. A gap of hours is a queue after a temporary failure, and it is generally the receiving side that was unavailable rather than the sender being slow.
Because the clocks are independent, small negative gaps appear routinely and mean a clock is off rather than that anything is wrong. A large negative gap is different: it is also what a fabricated Received chain looks like, so it is worth a second look rather than a shrug.
Frequently asked questions
Why does the Received chain read backwards?
What is the difference between SPF, DKIM and DMARC?
Can I trust what the headers say?
Why does SPF fail on a message that was forwarded?
Are the headers I paste uploaded anywhere?
Related tools
URL Parser
Developer Tools
Splits a URL into its components with the query string decoded into a table, and flags the encoding and credential problems in it.
Network Port Lookup
Developer Tools
What service conventionally runs on a TCP or UDP port, whether it encrypts, and whether exposing it to the internet is a bad idea.
HTTP Status Code Lookup
Developer Tools
Search every HTTP status code — what it means, when to return it, and whether it caches.
ASCII Table
Developer Tools
Searchable ASCII reference with decimal, hex, octal, binary and escapes.