Email Headers Explained: A Postmaster's Reference
An email message has two halves: the body the user reads and the headers the rest of the system reads. Every deliverability decision becomes visible in those headers. Learning to read them turns "the email went to spam" from a mystery into an ordinary debugging problem.
How to view raw headers
Each major mail client exposes raw headers differently:
- Gmail (web): open the message, three-dot menu, "Show original".
- Outlook (web): open the message, three-dot menu, "View → View message source".
- Apple Mail: View → Message → Raw Source (Cmd+Opt+U).
- Thunderbird: View → Message Source (Ctrl+U).
You will 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.
Headers grouped by purpose
Routing: who handled the message and when
Received: from mail.example.com (mail.example.com [198.51.100.20])
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 sits 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 carries a timestamp; compare neighbours.
- An unexpected hop — especially a smarthost or relay you did not authorise — deserves investigation.
Authentication: did SPF, DKIM and DMARC pass?
Authentication-Results: mx.google.com;
dkim=pass header.i=@example.com header.s=k1
spf=pass (google.com: domain of bounce@example.com designates 198.51.100.20 as permitted sender) smtp.mailfrom=bounce@example.com
dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=example.com
This is the single most useful header in the message. Each verdict tells you the outcome and the domain or IP it applies to. Common failure modes:
spf=fail— the connecting IP is not in your SPF record.spf=softfail— the IP is not listed and your record uses~all. Treat as a fail in practice.dkim=fail (body hash did not verify)— something rewrote the body after signing.dkim=neutral (no key)— the published DKIM record is missing or malformed.dmarc=fail— SPF and DKIM did not align with the visible From domain.
The DKIM signature itself
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple;
d=example.com; s=k1; t=1714500000;
h=from:to:subject:date:message-id:mime-version;
bh=eY4cR2qz7y0wDxRpQH5cD6kK6BYP+vAVhI4MVJqKn3JE=;
b=Vd9pCJrOtN...
Tag by tag:
v=1— DKIM version, always 1.a=rsa-sha256— signing algorithm.c=relaxed/simple— canonicalisation for headers/body. Relaxed normalises whitespace; simple does not.d=example.com— the domain that owns the signing key. This is the field DMARC alignment compares.s=k1— selector. The public key lives atk1._domainkey.example.com.h=...— the headers that were signed. Anything not listed is unprotected.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 responsible for an embarrassing share of deliverability bugs.
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 are sent. SPF authenticates against this.
For the Return-Path to align with From under DMARC, the domains must match (relaxed alignment) or the full addresses must match (strict). For DKIM alignment, the From domain must match the signing domain (d=).
Identification: Message-ID
Message-ID: <a8d3f742-1c9b-4e21-8e0d-9b4c1a5d3e21@mail.example.com>
A globally unique identifier generated by the sending MTA. 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 placeholder 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 pushing more than 5,000 messages a day to Gmail since February 2024. The List-Unsubscribe header gives the receiver a one-click opt-out, and List-Unsubscribe-Post confirms support for 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
These tell 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; 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 in headers. SpamAssassin uses a numeric score with named tests. Reading the test list shows you exactly which signals tipped the message towards spam.
Diagnosing a single message
When a message lands in spam, the diagnostic flow is:
- Read
Authentication-Results. If SPF, DKIM or DMARC failed, you have a fixable problem. - Check
X-Spam-Scoreif present. A high score with named tests tells you exactly which signals fired. - Confirm 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.
About eight times in ten the answer is in the headers and the fix is straightforward. The remaining cases are reputation problems — for those, see our deliverability guide for the wider 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 returns a complete header analysis plus a deliverability score.
- Microsoft Message Analyzer — deprecated but still works for parsing Office 365 trace headers.