Skip to content
correct.email
For developers

How to read email headers, from Received to ARC

Read full email headers step by step: Received lines bottom-up, Return-Path, Authentication-Results, DKIM-Signature, ARC, spam verdicts and safe sharing.

By Exmoor Software7 min read

Your mail app shows four header fields — From, To, Subject, Date — and hides the rest. The hidden ones record which servers handled the message, whether it passed SPF, DKIM and DMARC, and sometimes why it was filtered as spam. This guide explains how to read them, which ones to trust, and how to export and share them safely.

The quick route: export the full headers (instructions near the end) and paste them into the email header analyzer, which parses them in your browser without uploading anything.

Headers are a stack: read them bottom-up

Every server that accepts a message adds its trace lines at the top. RFC 5321 requires each SMTP server to insert its Received line at the beginning and forbids changing, deleting or reordering existing ones. So the newest lines are at the top, and the fields written by the sender’s mail program — From, To, Subject, Date, Message-ID — are further down. To follow the journey, read the Received headers from the bottom up.

A simplified message as it arrived for anna@example.net:

Return-Path: <bounces+7f3a@mail.example.com>
Delivered-To: anna@example.net
Authentication-Results: mx.example.net;
       spf=pass smtp.mailfrom=mail.example.com;
       dkim=pass header.d=example.com header.s=s2026;
       dmarc=pass header.from=example.com
Received: from out1.mail.example.com (out1.mail.example.com [192.0.2.25])
        by mx.example.net with ESMTPS id 4Q8fKx2
        for <anna@example.net>; Fri, 23 Oct 2026 09:14:05 +0000
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=example.com; s=s2026;
        h=from:to:subject:date:message-id; bh=…; b=…
Received: from app1.example.com (app1.example.com [198.51.100.10])
        by out1.mail.example.com with ESMTPSA id 91c2d0;
        Fri, 23 Oct 2026 09:14:03 +0000
From: Example Shop <orders@example.com>
To: anna@example.net
Subject: Your order 1042
Date: Fri, 23 Oct 2026 09:14:02 +0000
Message-ID: <20261023091402.7f3a@example.com>

Bottom-up: the shop’s server app1 submitted the message to its outgoing server out1, which signed it with DKIM and delivered it to mx.example.net, which checked authentication and stored it.

Received: one line per hop

PartMeaning
from out1.mail.example.comname the sending server gave in EHLO
(… [192.0.2.25])what the receiver saw: usually reverse-DNS name and IP of the connection
by mx.example.netserver that accepted the message and wrote the line
with ESMTPSESMTPS = STARTTLS used, ESMTPA = authenticated, ESMTPSA = both (RFC 3848); plain ESMTP or SMTP = no TLS
id 4Q8fKx2queue ID — quote it when asking that server’s operator
for <…>optional: the recipient of this copy
date after ;when that server accepted the message

What to look for:

  • Delays. Subtract consecutive timestamps. A long gap on one hop points to that server: queueing, greylisting, retries. A small negative delay usually means a server clock is off.
  • The hand-over. Find the lowest Received line written by your own mail provider. Its from part is the server that handed the message over — the true origin as far as you can verify it.
  • The rest are claims. Lines below the hand-over were written by servers you don’t control, and a sender can invent hops to mislead you.

Return-Path: where bounces go

The server making the final delivery adds Return-Path with the envelope sender — the MAIL FROM address of the SMTP session (RFC 5321). Bounces go there, and it is the domain SPF checks. It often differs from From, which is fine as long as DMARC is satisfied through DKIM or an aligned bounce domain (DMARC alignment). Return-Path: <> is an empty envelope sender, used by bounces themselves so they can’t cause further bounces; SPF then checks the HELO name.

Authentication-Results: the verdict

Authentication-Results (RFC 8601) records what a receiving server checked and the outcome (see the example above):

  • The first item, mx.example.net, is the authserv-id: it identifies the service that did the checks.
  • Each result is method=result plus properties: smtp.mailfrom (envelope domain checked by SPF), header.d and header.s (DKIM signing domain and selector), header.i (DKIM identity), header.from (From domain evaluated by DMARC).
  • Results: pass, fail, softfail (SPF), neutral, none, temperror (temporary, often DNS), permerror (permanent, such as a broken record) and policy (the check passed, but local policy didn’t accept it). Parentheses hold free-text comments.

You may also see arc= (below), iprev= (reverse DNS of the connecting IP) and auth= (SMTP authentication). Microsoft 365 adds compauth=, its composite verdict for the From domain, with a reason= code documented by Microsoft.

Which one to trust

A message can carry several of these headers: your provider’s, those of servers it passed earlier, and possibly fakes added by the sender. RFC 8601 resolves this with the authserv-id: border servers must remove existing headers that claim their own organization’s identifier, and software should use only results whose authserv-id belongs to its own organization. In practice:

  1. Find the Received line where your provider accepted the message from outside.
  2. Use the Authentication-Results your provider wrote — normally just above it, at or near the top.
  3. Treat the others as history: what an earlier hop saw, not what your provider decided.

The header analyzer groups results by the reporting authserv-id. It reads the recorded verdicts; it doesn’t re-verify signatures or query DNS.

DKIM-Signature: who signed what

TagMeaning
d=signing domain — compare with the From domain for alignment
s=selector; the key is at s2026._domainkey.example.com (DKIM checker)
a=rsa-sha256 or ed25519-sha256; verifiers must not accept rsa-sha1
c=header/body canonicalization: relaxed tolerates whitespace changes, simple almost none
h=signed header fields; from must be among them
bh=, b=body hash, signature
i=, t=, x=optional identity, signing time, expiry
l=optional body length; content appended beyond it isn’t covered — a known weakness

Two signatures — your domain’s and the sending service’s — are common; DMARC needs one that passes and aligns. The signature only claims who signed; whether it verified is in Authentication-Results. More in how DKIM works.

ARC: results that survive forwarding

When a mailing list adds a footer or a service forwards a message, DKIM can break and SPF fails, so DMARC fails although the original was fine. ARC, the Authenticated Received Chain (RFC 8617, an Experimental RFC), lets each intermediary record what it saw before changing anything. It adds an ARC set of three headers sharing the instance number i=:

ARC-Seal: i=1; a=rsa-sha256; cv=none; d=lists.example.org; s=arc1; t=…; b=…
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=lists.example.org;
        s=arc1; h=from:to:subject:date; bh=…; b=…
ARC-Authentication-Results: i=1; mx.lists.example.org;
        spf=pass smtp.mailfrom=mail.example.com;
        dkim=pass header.d=example.com; dmarc=pass header.from=example.com
  • ARC-Authentication-Results: the results the intermediary got on arrival — Authentication-Results syntax plus i=.
  • ARC-Message-Signature: a DKIM-like signature of the message as passed on.
  • ARC-Seal: a signature over the ARC headers; cv= records the chain state the sealer received: none (no earlier sets), pass or fail.

The next intermediary adds i=2, and so on, up to 50 sets. The final receiver records the outcome, such as arc=pass, in its own Authentication-Results.

ARC proves which intermediaries handled a message, not that they are honest. Each receiver decides which sealers it trusts, and only then may it accept their results despite a DMARC failure. Senders can’t add ARC to other people’s forwarding; signing everything with DKIM limits the damage.

Spam verdict headers

Some filters write a verdict into the message, in non-standard X- headers:

  • SpamAssassin, common at hosting providers: X-Spam-Status: Yes, score=7.4 required=5.0 tests=… and X-Spam-Flag: YES. The test names explain the score.
  • Microsoft 365: X-Forefront-Antispam-Report with SFV:SPM (spam) or SFV:NSPM (not spam), CAT: (policy applied, such as SPM, PHSH, BULK) and SCL: (spam confidence level); X-Microsoft-Antispam carries BCL: (bulk complaint level). Microsoft notes that in cloud organizations the SCL value doesn’t determine whether a message is treated as spam or what happens to it; to see how a message was filtered, it points to CAT and DIR (the message direction) instead.

Not every provider exposes a verdict, and the copy in the sender’s Sent folder never shows what the recipient’s server decided — ask the recipient for their headers. Common causes are covered in why emails go to spam.

How to get the full headers

  • Gmail (web): open the message, ⋮ (More) next to Reply → Show original, then Copy to clipboard or Download original.
  • Outlook on the web, Outlook.com, new Outlook for Windows: More actions (⋯) → View → View message details.
  • Classic Outlook for Windows: open the message in its own window, File → Properties; see the Internet headers box.
  • Apple Mail on Mac: View → Message → All Headers, or Raw Source in the same menu for the complete message.
  • Thunderbird: View → Message Source (Ctrl+U, ⌘U on Mac).

Most phone apps don’t show headers; use webmail or a desktop client. Headers end at the first empty line; the analyzer accepts the headers alone or the whole source.

Sharing headers safely

Headers reveal more than they seem: names and addresses of the sender and all recipients; IP addresses and internal host names of servers and, with some providers, of the sender’s device; the subject and Message-ID; and personal tokens such as the List-Unsubscribe link — which works for anyone who opens it.

Before posting headers in a forum or a ticket:

  1. Share the headers only, not the source — the body may hold personal data, tokens and attachments.
  2. Replace addresses consistently (anna@example.net → user@example.net) so the path still makes sense.
  3. Remove List-Unsubscribe URLs and other links with tokens.
  4. Keep Received, Authentication-Results, DKIM-Signature and ARC-* intact; long b= values can be shortened.

References