How to Read Email Headers: A Field-by-Field Guide
Every email carries a hidden delivery record above the visible message. Here's how to get at it and what each line actually means.
Getting the Raw Headers
The headers you see in a mail client — From, Subject, the sender's name — are a curated subset. The full header block includes a dozen or more fields the interface hides by default, and each provider exposes them through a different menu:
- Gmail (web): open the message, click the three-dot menu in the top right of the message pane, and choose Show original. This opens a new tab with the complete header block above the decoded body, plus a link to run Google's own authentication summary.
- Outlook (web and desktop): open the message, then File > Properties on desktop, or the three-dot menu > View > View message details on the web. The headers appear in a scrollable "Internet headers" text box you can select and copy in full.
- Apple Mail (macOS): select the message and choose View > Message > All Headers, or use the keyboard shortcut Shift-Command-H. The client switches the message pane to a raw text view.
- .eml files: if you've saved or received an
.emlattachment, open it in a text editor — it's already plain text, headers followed by a blank line followed by the body.
Whichever route you take, copy everything from the first header field down through the last one before the blank line that starts the message body. You can paste the whole thing — headers and body together — into the tool below; it stops reading at the first blank line automatically.
Anatomy of a Header Block
A header block is a sequence of Name: value lines, one field per line, defined by RFC 5322 §2.2. Two details trip people up when reading one for the first time:
- Folding. A value can wrap across multiple physical lines by starting each continuation line with a space or tab. A folded
Received:header spanning three indented lines is one logical header with one value — the indentation is purely cosmetic, added by the mail server to keep lines under roughly 78 characters. Readers unfold these back into a single line before doing anything else with them. - Repetition. Field names are not unique. Every server that relays a message prepends its own
Received:header above the ones already there, so a message that passed through four hops carries four separateReceived:lines, oldest at the bottom, newest at the top. Some messages also carry more than oneAuthentication-Results:header, one per hop that performed checks.
Order matters and is never alphabetical: headers appear in the order they were added, which for Received: specifically means newest-first, exactly backwards from the order the message actually traveled.
Tracing Delivery: Read Received Headers From the Bottom Up
This is the single most important rule for reading headers by hand. Each server that accepts a message for relay adds a new Received: header above whatever is already there — it never appends to the bottom. That means the header closest to the top of the block was written by the server closest to you, the recipient, and the header at the very bottom was written by the first server the message touched, closest to the original sender. To reconstruct the actual path the message took, read from the bottom header upward.
Each Received: value follows a loose grammar defined in RFC 5322 §3.6.7: an optional from clause naming the sending server, an optional by clause naming the receiving server, an optional with clause naming the protocol, and a trailing date-time after the final semicolon. A single hop typically looks like this:
Received: from relay1.example.org (relay1.example.org [198.51.100.22]) by mail.example.com (Postfix) with ESMTPS id 4T1abc1Ghi9 for <alice@example.com>; Tue, 21 Jan 2026 10:15:23 +0000 (UTC)
Read as: relay1.example.org handed this message to mail.example.com over ESMTPS at 10:15:23 UTC. Subtract each hop's timestamp from the next hop's to see how long the message sat at each server — a single hop that took several seconds while the rest took milliseconds is often where to look first when a delivery delay is being investigated. Because the trailing timestamp is a full RFC 5322 date-time and not a Unix timestamp, converting one by hand to compare against application logs is exactly the kind of job the Epoch Converter is built for.
Two things routinely make this harder in practice. First, the from clause names whatever the connecting server claimed to be — on the hop closest to the true sender, that claim usually isn't verified yet, so treat it as a hint rather than a fact. Second, some servers write malformed or unusually shaped Received: headers that don't match the common grammar; the analyzer below still surfaces those hops (marked as unparsed) so you know they exist even when it can't extract structured fields from them.
What Each Core Header Means
- Return-Path: the address bounces and delivery failures go to, set by the final delivering server from the SMTP envelope's
MAIL FROM. This is the address SPF actually checks — not the visible From address — which is why the two can legitimately differ for mailing lists and forwarders, and why a mismatch between them is one of the flags the spoofing detector below looks for. - From: the visible sender identity shown in the mail client. It can contain a display name and address that belong to different people entirely — the header format doesn't require them to match, which is exactly what display-name spoofing exploits.
- Reply-To: where a reply actually goes, if present. Absent by default, in which case replies go to the From address. A Reply-To domain that differs from From is common in legitimate marketing mail but is also a classic business-email-compromise technique — the visible sender looks right, but replies route to the attacker.
- To: the primary recipient(s) as declared by the sender. Notably, this is not where a copy of the message was actually delivered — that's the
forclause in the finalReceived:hop, and the two can differ (e.g. when Bcc'd). - Date: the RFC 5322 date-time the sending client attached to the message. It reflects the sender's claimed clock, not necessarily when any server actually processed it — compare it against the first
Received:timestamp for a sanity check. - Message-ID: a supposedly globally unique identifier assigned by the originating client, in the form
local-part@domain. Useful for cross-referencing the same message across multiple recipients' header dumps, or for correlating with server logs. - Authentication-Results: the outcome of SPF, DKIM, and DMARC checks performed by a receiving server, formatted per RFC 8601. See SPF, DKIM & DMARC: Reading the Verdicts for a full field-by-field walkthrough of this one.
Analyze Your Own Headers
Paste a full header block below to see all of the above applied automatically: the Received chain reordered chronologically with per-hop delay, every Authentication-Results verdict, and any spoofing red flags. Everything runs locally in your browser — header content routinely contains real names, addresses, and internal hostnames, so nothing is written to the URL, localStorage, or any network request.
Paste the raw headers of an email to reconstruct its delivery path, check SPF/DKIM/DMARC results, and look for signs of a spoofed sender.
Once you can read a normal header block comfortably, the next step is knowing which anomalies actually matter — see how to detect a spoofed email from its headers.
Further Reading
- RFC 5322 — Internet Message Format
The IETF standard defining header syntax, folding, and the Received header grammar.
- RFC 8601 — Message Header Field for Indicating Message Authentication Status
Defines the Authentication-Results header format referenced throughout this guide.
- Google: Check the headers of an email in Gmail
Gmail's official steps for opening the Show original view.
- Microsoft: View internet message headers in Outlook
Outlook's official steps across web and desktop clients.