Skip to content

How to read email headers to debug delivery problems

Last updated: 26:10:2026

Wersja polska

What headers are, and which ones you can trust

Every email starts with a block of header lines before the body. Your mail app shows four or five of them (From, To, Subject, Date) and hides the rest, which is where the useful information is. The headers come from three different places:

  • The sender's software writes the message fields defined in RFC 5322: From, To, Subject, Date, Message-ID, and often List-Unsubscribe and the DKIM-Signature.
  • Every server that handles the message adds a Received line on top (RFC 5321). The server that finally delivers it into a mailbox adds Return-Path with the envelope sender.
  • The receiving provider adds its verdicts: Authentication-Results (RFC 8601), sometimes Received-SPF, ARC headers for forwarded mail, and its own spam headers.

Headers are plain text, so anyone can write anything into them before sending. The rule that keeps you from being misled: trust headers added by your own provider's servers, and treat everything beneath them as a claim by the sender. A fake Received line or a forged "spf=pass" at the bottom of a phishing message proves nothing; the Authentication-Results line your provider added at the top does.

How to see the full headers

Mail appWhere to find them
Gmail (web)Open the message, click the More (three dots) menu next to Reply and choose "Show original". Gmail lists the SPF, DKIM and DMARC results at the top.
Outlook for Windows (classic)Open the message in its own window (double-click), then File → Properties; the headers are in the "Internet headers" box.
New Outlook for Windows, Outlook on the web, Outlook.comIn the message, choose More actions → View → View message details.
Apple Mail (Mac)Select the message and choose View → Message → All Headers (or Raw Source for the complete message).
ThunderbirdView → Headers → All shows every header above the message; View → Message Source (Ctrl+U) shows the raw message.
Gmail (web)
Where to find them: Open the message, click the More (three dots) menu next to Reply and choose "Show original". Gmail lists the SPF, DKIM and DMARC results at the top.
Outlook for Windows (classic)
Where to find them: Open the message in its own window (double-click), then File → Properties; the headers are in the "Internet headers" box.
New Outlook for Windows, Outlook on the web, Outlook.com
Where to find them: In the message, choose More actions → View → View message details.
Apple Mail (Mac)
Where to find them: Select the message and choose View → Message → All Headers (or Raw Source for the complete message).
Thunderbird
Where to find them: View → Headers → All shows every header above the message; View → Message Source (Ctrl+U) shows the raw message.

Phone mail apps generally don't show full headers. Open the same message in webmail or a desktop app instead. When you ask someone for help, copy the whole header block as text - a screenshot cuts lines and can't be pasted into a header analyser.

One note for AnyMail users: AnyMail stores received mail as parsed messages, not as the original raw file, so the original headers of a message you received aren't kept. That rarely matters, because the usual question is how your outgoing mail arrives elsewhere: send a test message to a Gmail or Outlook.com address and read the headers there, where the receiving provider has recorded exactly what it saw.

An annotated example

Here is a shortened header block of a message from anna@example.com, sent through a provider at out.mailhost.example and received by mx1.example.net. Real headers are longer and in a slightly different order, but the important lines look like this:

Example headers (shortened)
Return-Path: <anna@example.com>
Delivered-To: jo@example.net
Received: from out.mailhost.example (out.mailhost.example [192.0.2.25])
        by mx1.example.net with ESMTPS id 4F2A9C0123
        for <jo@example.net>; Mon, 26 Oct 2026 10:15:04 +0100
Authentication-Results: mx1.example.net;
       spf=pass smtp.mailfrom=anna@example.com;
       dkim=pass header.d=example.com header.s=s1;
       dmarc=pass header.from=example.com
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=example.com; s=s1;
       h=from:to:subject:date:message-id; bh=2jUSOH9N…; b=dzdVyOfA…
Message-ID: <8c1f02a4-6e1b-4d1e-9a51-3f0c2e7d9b10@example.com>
Date: Mon, 26 Oct 2026 10:15:02 +0100
From: Anna Nowak <anna@example.com>
To: jo@example.net
Subject: Invoice 1042
List-Unsubscribe: <https://out.mailhost.example/unsubscribe/…>
List-Unsubscribe-Post: List-Unsubscribe=One-Click

The Received chain: read it from the bottom up

Each server prepends its Received line, so the newest is at the top and the first hop at the bottom. To follow the route, start at the lowest Received line and work upwards. Each line says which server it came from (with the name it announced, its reverse-DNS name and IP address in brackets), by which server received it, with which protocol (ESMTPS means SMTP over TLS) and when.

  • Finding a delay. Compare the timestamps of consecutive lines. A gap of minutes or hours between two hops shows exactly which server held the message - often greylisting, a busy queue or a retry after a temporary failure. Watch the time zones: +0100 and -0700 are hours apart even when the clocks look close.
  • Finding the real sending server. The trustworthy hop is the one where your provider's server (the first line written by a host you recognise as yours) records the connection from outside. The IP address in that line is the one SPF was checked against and the one blocklists are about.
  • Spotting TLS. ESMTPS or a TLS version and cipher in the line means that hop was encrypted; plain ESMTP or SMTP means it wasn't.

Authentication-Results: the verdict

This is the most useful single header when mail lands in spam. The receiving server records each check and its result, prefixed with its own name (the "authserv-id", mx1.example.net above) so you can tell its results from anything a sender tried to slip in.

FieldMeaningWhat to check
spf=Whether the sending IP is allowed by the SPF record of the envelope sender's domainsmtp.mailfrom
dkim=Whether a DKIM signature verified - one result per signatureheader.d / header.s
dmarc=Whether SPF or DKIM passed for a domain aligned with the From addressheader.from
arc=For forwarded mail: whether the chain of intermediaries could be verified (RFC 8617)only present on some messages
spf=
Meaning: Whether the sending IP is allowed by the SPF record of the envelope sender's domain
What to check: smtp.mailfrom
dkim=
Meaning: Whether a DKIM signature verified - one result per signature
What to check: header.d / header.s
dmarc=
Meaning: Whether SPF or DKIM passed for a domain aligned with the From address
What to check: header.from
arc=
Meaning: For forwarded mail: whether the chain of intermediaries could be verified (RFC 8617)
What to check: only present on some messages

Results are pass, fail, softfail (SPF ~all), neutral, none (no record or no signature), temperror (a DNS lookup failed temporarily) and permerror (the record itself is broken - for SPF, often more than 10 lookups or two SPF records). Some providers add their own compauth or reason codes; those are provider-specific.

A dmarc=fail with spf=pass and dkim=pass is not a contradiction: it means both passed for domains other than the one in From, typically a mail service's own domain. That is an alignment problem, covered below and in the DMARC guide.

DKIM-Signature: who signed, and with which key

The DKIM-Signature header is the signature itself (see DKIM explained). Two tags matter most when debugging:

  • d= - the signing domain. For DMARC to pass on DKIM, it must be your domain (or, with relaxed alignment, a subdomain of the same organisation as the From address).
  • s= - the selector. The receiver fetches the public key from s1._domainkey.example.com for s=s1; d=example.com. If dkim=fail says the key wasn't found, look up exactly that name.

h= lists the signed headers, bh= is the hash of the body and b= the signature. When DKIM fails with a body hash mismatch, something changed the message after it was signed: a mailing list adding a footer, a security gateway rewriting links, or a forwarder. A message can carry several signatures - for example yours and your mail service's - and each gets its own result.

Return-Path, From and alignment

Return-Path shows the envelope sender, the MAIL FROM address given during the SMTP conversation. It is where bounces go, and it is the domain SPF checks. From is the address people see. The two are often different: many sending services use their own bounce-handling domain in the envelope while From shows yours.

DMARC ties them together. It passes only if SPF passed for a Return-Path domain that matches the From domain, or DKIM passed with a d= that matches it. In the example above everything lines up: Return-Path, From and d= are all example.com. When you use AnyMail, that alignment is built in: outgoing mail uses your own address as the envelope sender and is DKIM-signed with your domain.

Message-ID: the message's fingerprint

Message-ID is a globally unique identifier the sending software assigns, written like an address in angle brackets. It is what replies refer to (In-Reply-To and References), which is how mail apps group conversations, and it is the best way to find one message in logs: give your provider the Message-ID rather than the subject and time. Bounce reports quote it too, which is how AnyMail links a bounce that arrives later back to the message it belongs to. A message missing a Message-ID, or with one that doesn't look like <something@domain>, often comes from a misconfigured script.

List-Unsubscribe

List-Unsubscribe (RFC 2369) gives mail apps a link or address for unsubscribing, and List-Unsubscribe-Post: List-Unsubscribe=One-Click (RFC 8058) says that link works with a single POST, without a confirmation page. Gmail's and Yahoo's sender requirements ask bulk senders of marketing and subscription mail to support one-click unsubscribe. If Gmail doesn't offer an "Unsubscribe" option for your newsletter, first check that both headers are present and that the link uses HTTPS. AnyMail adds both headers, backed by a working one-click link, to every message it delivers to addresses outside AnyMail.

A quick diagnosis table

SymptomLook atUsual cause
Lands in spamAuthentication-ResultsSPF/DKIM failing or not aligned with From; see the spam guide
Arrived hours lateReceivedA gap between two hops: greylisting, retries or a queue
dkim=failDKIM-SignatureKey not published under s=, or the body was modified on the way
spf=fail / softfailReturn-Path / ReceivedThe sending IP isn't in the envelope domain's SPF record
dmarc=failheader.from / header.d / smtp.mailfromPassing domains don't match the From domain
Replies don't threadMessage-ID / In-Reply-ToMissing or rewritten Message-ID
Lands in spam
Look at: Authentication-Results
Usual cause: SPF/DKIM failing or not aligned with From; see the spam guide
Arrived hours late
Look at: Received
Usual cause: A gap between two hops: greylisting, retries or a queue
dkim=fail
Look at: DKIM-Signature
Usual cause: Key not published under s=, or the body was modified on the way
spf=fail / softfail
Look at: Return-Path / Received
Usual cause: The sending IP isn't in the envelope domain's SPF record
dmarc=fail
Look at: header.from / header.d / smtp.mailfrom
Usual cause: Passing domains don't match the From domain
Replies don't thread
Look at: Message-ID / In-Reply-To
Usual cause: Missing or rewritten Message-ID

Headers tell you what happened to one message. To check your domain's records before sending anything, use the email authentication checker, and for the bigger picture of why mail is filtered, see why emails go to spam.

Sharing headers safely

Headers contain email addresses, IP addresses and sometimes internal hostnames, but never your password. Before posting them in a public forum, replace addresses with placeholders; when sending them to your provider's support, send them unedited - edited headers are much harder to debug.

Let AnyMail handle these records for you

AnyMail generates the MX, SPF, DKIM and DMARC records for your domain, checks every one of them automatically and tells you exactly which record to fix - then hosts your inboxes, operated from the EU.