Email Headers Explained: A Postmaster's Complete Guide
Every email message has two parts: the body, which the recipient reads, and the headers, which the rest of the system reads. The headers are where every deliverability decision becomes visible. Knowing how to read them turns "the email went to spam" from a mystery into a debug problem.
How to view raw headers
Each major mail client has a different way to expose headers:
- Gmail (web): open the message, click the three-dot menu, choose "Show original".
- Outlook (web): open the message, click the three-dot menu, choose "View → View message source".
- Apple Mail: View → Message → Raw Source (Cmd+Opt+U).
- Thunderbird: View → Message Source (Ctrl+U).
You'll see a block of Header-Name: value lines, then a blank line, then the body. Long values are folded across multiple lines — a continuation line begins with whitespace.
The headers grouped by purpose
Routing: who handled this message and when
Received: from mail.example.com (mail.example.com [192.0.2.10])
by mx.recipient.com with ESMTPS id abc123
for <user@recipient.com>;
Mon, 04 May 2026 14:23:01 +0000 (UTC)
Each MTA the message passes through prepends a Received: line. The newest hop is at the top, the oldest at the bottom. To trace the path, read from bottom to top.
What to look for:
- The first hop should be your sending MTA, with the source IP in square brackets matching what you expect.
- Long delays between hops point to network or queue issues. Each Received line includes a timestamp; compare adjacent ones.
- An unexpected hop — particularly a smarthost or relay you didn't authorise — is worth investigating.
Authentication: did SPF, DKIM and DMARC pass?
Authentication-Results: mx.google.com;
dkim=pass header.i=@example.com header.s=s1
spf=pass (google.com: domain of bounce@example.com designates 192.0.2.10 as permitted sender) smtp.mailfrom=bounce@example.com
dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=example.com
This single header is the most important diagnostic in the message. Each result tells you the verdict and which domain or IP it applies to. Common failure modes:
spf=fail— the connecting IP is not in your SPF record.spf=softfail— not in the record, and your record uses~all. Treat as a fail in practice.dkim=failwith(body hash did not verify)— something modified the body after signing.dkim=neutral (no key)— the published DKIM record is missing or malformed.dmarc=fail— SPF and DKIM didn't align with the visible From domain.
The DKIM signature itself
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple;
d=example.com; s=s1; t=1714500000;
h=from:to:subject:date:message-id:mime-version;
bh=2YfHK5Vqj9wDxRpQH5cD6kK6BYP+vAVhI4MVJqKn3JE=;
b=H8Lkz6bN...
Tag-by-tag:
v=1— DKIM version, always 1.a=rsa-sha256— signing algorithm.ed25519exists but is rarely deployed.c=relaxed/simple— canonicalization for headers/body. Relaxed allows whitespace normalisation; simple does not.d=example.com— the domain that owns the signing key. This is what DMARC checks against.s=s1— selector. The public key is ats1._domainkey.example.com.h=...— the headers that were signed. Anything not listed here is not protected.bh=...— hash of the canonicalised body.b=...— the actual signature.
Identity: From, Reply-To, Return-Path
These three headers carry three different addresses, and confusing them is the source of many problems.
From:— what the user sees. Authenticated by DMARC alignment.Reply-To:— where replies go if the user clicks Reply. Not authenticated by anything.Return-Path:— the envelope-from. Where bounces go. This is what SPF checks against.
For the Return-Path to align with From under DMARC, the domains have to match (relaxed alignment) or the full addresses have to match (strict). For DKIM alignment the From domain has to match the signing domain (d=).
Identification: Message-ID
Message-ID: <a8d3f742-1c9b-4e21-8e0d-9b4c1a5d3e21@mail.example.com>
A globally unique identifier for the message, generated by the sending MTA. It's used by clients for threading, by deliverability tools for tracking, and by abuse desks for correlation. The hostname after the @ should be a domain you actually operate — using "localhost" or a generic string is a small but real spam signal.
List management headers
List-Unsubscribe: <https://example.com/unsub?id=12345>, <mailto:unsubscribe+12345@example.com>
List-Unsubscribe-Post: List-Unsubscribe=One-Click
Required for any sender doing more than 5,000 messages a day to Gmail since February 2024. The List-Unsubscribe header gives the receiver a one-click way to opt out, and the List-Unsubscribe-Post header confirms it supports the RFC 8058 one-click POST flow. Missing these on bulk mail will land you in spam.
MIME headers
MIME-Version: 1.0
Content-Type: multipart/alternative; boundary="abc123"
Content-Transfer-Encoding: 8bit
Tells the client how to render the message. multipart/alternative with both text/plain and text/html parts is the deliverability default — always include both. HTML-only messages are a (mild) spam signal, and plain-text-only messages render badly to most users.
Anti-spam scoring
X-Spam-Score: 1.2
X-Spam-Status: No, score=1.2 required=5.0 tests=DKIM_VALID,SPF_PASS
Some receivers expose their spam-filter scores. SpamAssassin uses a numeric score with named tests. Reading the test list shows you exactly which signals tipped the message towards spam.
What you can learn from a single message
Given a message that landed in spam, the diagnostic flow is:
- Check
Authentication-Results. If SPF, DKIM or DMARC failed, you have a fixable problem. - Check
X-Spam-Scoreif present. If the score is high, look at which tests fired. - Check the
Fromdomain matches theReturn-Pathdomain (alignment). - Check the
Receivedchain — did the message take the route you expected? - Check for missing
List-Unsubscribeon bulk mail. - Check the
Message-IDhostname looks legitimate.
Eight times out of ten the answer is in the headers and a fix is straightforward. The remaining cases are reputation problems — for those, see our deliverability guide for the bigger picture.
Tools that parse headers for you
- MXToolbox Email Header Analyzer — paste headers, get a parsed summary with each hop's delay highlighted.
- Google Admin Toolbox — Messageheader — same idea, slightly different layout.
- mail-tester.com — sends a test and gives you a complete header analysis plus a deliverability score.
- Microsoft Message Analyzer (deprecated but still works) — parses Office 365 trace headers in detail.