# Email Header Analyzer

> Trace an email's route hop by hop, read SPF, DKIM and DMARC results and verify DKIM in your browser. Paste headers or drop an .eml/.msg. Nothing is uploaded.

- URL: https://bytescope.dev/en/email-header-analyzer/
- Locale: en · Also: [ja](https://bytescope.dev/ja/email-header-analyzer.md) · [zh-Hant](https://bytescope.dev/zh-Hant/email-header-analyzer.md)
- Runs: Your files never leave your browser — all processing is local.
- Requires: Any modern browser (Chrome, Edge, Firefox, Safari), desktop and mobile.
- Updated: 2026-09-08

## What it does

Email headers answer three questions people ask all the time: why did this message take two hours to arrive, is this really from my bank, and why did it land in spam? Reading them by hand is slow — a dozen `Received` lines in reverse order, timestamps in different time zones, and an `Authentication-Results` header full of abbreviations. This email header analyzer parses the headers in your browser and lays them out: the route the message took, the delay at each hop, what the receiving server concluded about SPF, DKIM and DMARC, and whether the DKIM signature still verifies today. Nothing is uploaded. The only network request the page ever makes is the DKIM public-key lookup, and only after you press Verify DKIM: the name `selector._domainkey.domain` is sent to a public DNS-over-HTTPS service (Cloudflare, with Google as fallback), which sees your IP address as any DNS query does. The message, its recipients and the headers themselves are never sent anywhere.

### Trace the route and find the delay

Every `Received` header is one hop. The page lists them oldest first and splits each into the claimed sending host, the reverse-lookup name and IP in brackets, the receiving host, the protocol (`SMTP`, `ESMTPS`, `ESMTPSA`, `LMTP`…) and the time. The protocol letters are decoded per RFC 3848 — an `S` means the connection used TLS, an `A` means the sender authenticated — so you can see whether the message was encrypted in transit. The delay of a hop is its timestamp minus the previous one, drawn as horizontal bars with the longest hop in red, which is usually where a delayed message spent its time. A negative delay is labelled clock skew rather than treated as an error, because mail servers' clocks disagree; a hop with no usable time is labelled cannot compute and does not break the chain. Private addresses (RFC 1918, `127.*`, `::1`) are marked internal. IP addresses are shown as text only — there is no geolocation lookup, which would mean sending them to a third-party API.

### Read Authentication-Results with the right amount of trust

`Authentication-Results` (RFC 8601) is where a receiving server writes down what it decided: `spf=pass`, `dkim=fail`, `dmarc=none`, plus `arc`, `iprev` and `bimi` where present. The page splits each header into its authserv-id and methods, and gives every result a plain-language sentence — what `softfail`, `temperror`, `permerror` and `neutral` actually mean and what commonly causes them. One warning sits above the whole list: anyone along the path, including the sender, can add an `Authentication-Results` header. Only the line written by your own receiving server is trustworthy; lines from intermediate hops, or from the sender itself, prove nothing. ARC headers (RFC 8617) are grouped by instance and shown for reference, but this version does not verify ARC seals.

### Verify DKIM in the browser, with today's key

The headline feature is a real DKIM verification (RFC 6376) rather than a readout of someone else's verdict. For each `DKIM-Signature` the page parses the tags, fetches the public key named by `s=` and `d=`, canonicalises the signed headers as `c=` says, and checks the signature with WebCrypto. Headers listed in `h=` but missing from the message count as empty strings, exactly as the standard requires, so a header added after signing cannot pass. `rsa-sha256` is verified with RSASSA-PKCS1-v1_5; `ed25519-sha256` (RFC 8463) is verified when the browser's WebCrypto supports Ed25519 and reported as cannot verify — not as a failure — when it does not; `rsa-sha1` is verified but flagged as deprecated by RFC 8301, and RSA keys shorter than 1024 bits are rejected as that RFC demands. The verdict is pass, fail with a reason (key not found, key revoked when `p=` is empty, expired `x=`, signature mismatch, body hash mismatch, key too short), cannot verify (DNS error, unsupported algorithm, no body) or malformed. A signature with `l=` gets a warning that only the first N bytes of the body are covered and anything appended afterwards is unsigned. Remember that the key you fetch is the key published now: if the sender has rotated keys since the message was sent, an old message fails verification without being forged.

### Headers only, .eml, or .msg

A full `.eml` file is the only input that lets the body hash `bh=` be checked, because the raw bytes of the body are needed. If you paste headers only, the page still verifies the header signature — which covers the `bh=` value — and reports that the headers are intact but the body could not be checked. Every `.msg` file is in this situation: a received message's `.msg` keeps the transport headers as a property but not the original MIME body (and a `.msg` saved before sending has no transport headers at all), so a `.msg` is always a headers-only verification. From the EML viewer and the MSG viewer, a one-click link hands the message to this page through session storage, never through the URL. The summary card shows the three sender identities side by side — the `From` domain, the `Return-Path` domain and the DKIM `d=` domain — with DMARC alignment judged on the organisational domain (relaxed mode, RFC 7489), and offers to check the `From` domain's SPF, DKIM and DMARC records on the email DNS check page; only that domain, which is public, goes into the link.

### What this page does not claim

It never says a message is safe or genuine — it says which checks passed and which failed, and a passing DKIM signature only proves that the `d=` domain signed the message, not that the domain belongs to who you think. SPF is not re-checked: SPF depends on the IP that delivered the message and the DNS of that moment, so re-running it later tells you nothing; the page shows what the receiving server recorded instead. DKIM failures on forwarded messages, mailing-list messages and messages rewritten by a corporate mail gateway are common and expected, and the failure text says so. Spam-filter headers such as `X-Spam-Status` or `X-Microsoft-Antispam` are shown verbatim without interpretation, because their formats are not public. The Markdown report and the JSON export mask recipient addresses by default so you can share them.

## Limits

Does not re-check SPF, look up IP locations or say whether a message is safe; it reads the headers and verifies DKIM signatures locally.

## FAQ

### Why did my email go to spam?

The headers show part of the answer. Look at the topmost `Authentication-Results` line written by your receiving server: a `dkim=fail`, `spf=softfail` or `dmarc=fail` there, or a `From` domain that does not align with the DKIM `d=` or `Return-Path` domain, is a strong reason for a spam folder. Spam-filter headers such as `X-Spam-Status` are listed verbatim too. What the headers cannot show is sender reputation, content and sending volume, which filters weigh heavily. If you are the sender, check the domain's SPF, DKIM and DMARC records on the email DNS check page — the summary card links straight to it.

### How can I tell whether an email claiming to be from my bank is real?

Compare the three identities on the summary card: the `From` domain people see, the `Return-Path` domain and the DKIM `d=` domain, then press Verify DKIM. A valid signature proves that whoever controls the `d=` domain signed the message and that the signed headers were not changed since — so check that `d=` really is the bank's domain and not a lookalike. Also read the `Authentication-Results` line from your own receiving server, not one added earlier in the path. The page deliberately never says a message is safe; it only reports which checks passed. When in doubt, contact the bank through a channel you already trust.

### Why does DKIM fail on a message I know is genuine?

Three common reasons. The message was forwarded, passed through a mailing list or rewritten by a company mail gateway — anything that changes a signed header or the body (a subject tag, a footer) breaks the signature, and this is normal. The sender has rotated its DKIM key since the message was sent — verification uses the key published in DNS today, so old messages fail without being forged. Or the message was damaged when it was copied: pasted text that lost line endings or trailing spaces will not match. A failure means the signature does not verify now; it does not by itself prove forgery.

### Why was my email delayed, and where did it get stuck?

Scroll to the route. Each `Received` hop shows the delay since the previous hop as a bar, and the longest bar is highlighted in red — that hop is where the message waited, typically in a queue at the receiving host named in its `by` clause. A negative delay means two servers' clocks disagree rather than that time went backwards, and a hop without a usable timestamp is marked cannot compute without affecting the hops after it.

### What does this page send over the network?

Nothing until you press Verify DKIM. Then, for each signature, the page sends one DNS query for `selector._domainkey.domain` to Cloudflare's DNS-over-HTTPS service, falling back to Google's if that fails. Those services see the name being queried and your IP address, as any DNS resolver does. The message, its headers, its recipients and the result are never sent to anyone, including this site. Without network access the route and the Authentication-Results still display, and DKIM shows a DNS error.

### Can I verify DKIM from headers alone, or from a .msg file?

Partly. The DKIM signature covers two things: the selected headers and a hash of the body stored in `bh=`. With headers only, the header signature can still be verified, so you learn that the headers — including the `bh=` value — are intact; the body itself cannot be checked because it is not there. Outlook `.msg` files keep the transport headers but not the original MIME body, so a `.msg` always gets this headers-only verdict. Drop the original `.eml` when you need the body checked as well.

### Why doesn't the page re-check SPF?

Because SPF cannot be re-run after the fact. SPF asks whether the IP address that handed the message to your server was allowed to send for the `Return-Path` domain, using the DNS records of that moment. A later check from your browser would use a different IP and possibly different records, so its answer would be meaningless. The page shows the SPF result your receiving server recorded in `Authentication-Results` instead. DKIM is different: the signature travels with the message and can be verified by anyone who fetches the key, which is why the page verifies that itself.

### Which Authentication-Results header should I believe?

Only the one written by your own receiving server, which is normally the topmost and carries your provider's authserv-id (for example your mail host's name). Any server along the path — and the sender — can insert an `Authentication-Results` header saying `dkim=pass`, and a forger has every reason to. The page shows the authserv-id of every line so you can tell them apart, and repeats this warning above the list. ARC headers are shown for reference but are not verified in this version.

## Related tools

- [Email DNS Check](https://bytescope.dev/en/email-dns-check.md) — Check a domain's SPF, DKIM, DMARC, MX and MTA-STS records →
- [EML Viewer](https://bytescope.dev/en/eml-viewer.md) — Open an .eml message: headers, body and attachments →
- [MSG Viewer](https://bytescope.dev/en/msg-viewer.md) — Open an Outlook .msg file without Outlook →
