Ahosting Logo
Knowledge Base

How to Read Email Headers and Trace a Message

Which header line answers which questionRead the Received lines from the bottom upwardsReceivedevery server the message passedthrough, newest at the topWhere the delay wasthe timestamps betweenconsecutive Received linesAuthentication-Resultswhat SPF, DKIM and DMARCactually returnedReturn-Pathwhere bounces go, which is notalways the From addressMessage-IDthe handle support will ask youforX-Spam headersthe score and which rulescontributedEvery message carries a full record of its journey, and it answers both of the usual questions: where it went andwhere it stopped.

Every message carries a record of where it has been, written by each server that handled it. It answers the two questions that otherwise become guesswork: where the delay happened, and whether the sender was genuine.

Finding them

In Roundcube, open the message and choose to view the source. In Outlook, message properties. In Gmail, "show original".

If you are asking someone else to send you a message for analysis, ask them to forward it as an attachment. Ordinary forwarding rewrites the headers and destroys exactly what you needed.

Received: read from the bottom

Each server adds its line at the top, so the oldest entry is at the bottom. The bottom-most line is where the message originated; the top is your own server.

Two things come out of these lines.

Where a delay happened. Compare timestamps between consecutive lines. A four-hour gap between two hops names the server that held it. If the gap is at the far end, the delay was not yours, which is a useful thing to be able to state with evidence.

Where it actually came from. The bottom entry shows the originating address, which is frequently nothing like what the visible sender suggests.

Authentication-Results: the honest answer

Authentication-Results: mx.example.com;
 spf=pass smtp.mailfrom=sender.com;
 dkim=pass header.d=sender.com;
 dmarc=pass

This is the line that says whether the message really came from the domain it claims.

spf=pass means the sending address was authorised by that domain. dkim=pass means the signature validated and the content was not altered. dmarc=pass means the domain's own policy was satisfied.

A message claiming to be from a bank with spf=fail is forged, and this is where you can say so definitively rather than by impression. Understanding SPF, DKIM and DMARC deals with what those checks actually test.

From: proves nothing

The visible sender is written by whoever composed the message. It can say anything.

This is the whole mechanism behind messages that appear to come from a colleague or a supplier. The address is displayed; nothing about displaying it verifies it.

Return-Path is the address bounces go to, and it frequently differs from the visible sender in forged mail. A mismatch between the two is a useful early signal, though legitimate mailing services also differ here.

Message-ID: what to search the log for

A unique reference for the message. When tracing on your own server:

grep 'the-message-id' /var/log/exim_mainlog

That shows what your server did with it: accepted, rejected, queued, delivered, which distinguishes "we never received it" from "we received it and the recipient's system discarded it". Those are entirely different problems with entirely different fixes.

Exim configuration and mail routing deals with reading the log.

Spam scores

Filtering systems add their own headers with a score and the rules that contributed.

When your own mail is being filtered, this is the most direct diagnosis available: it lists exactly which checks counted against the message. Frequently it is a missing authentication record rather than anything about the content, which is a fixable configuration problem instead of a writing problem.

Ask a recipient whose system filtered your message to send you the headers. It is faster than any amount of guessing. Understanding bounces and delivery codes walks through the case where it was rejected outright instead.

Two habits worth having

When someone reports a suspicious message, ask for it as an attachment and read the authentication line before anything else. It settles most cases in seconds.

When someone reports a delay, read the received lines before assuming the server is at fault. A large share of "your mail server is slow" reports turn out to be a delay at the other end, and the timestamps say so plainly. The email troubleshooting guide sets out working through the rest.

Read the delivery path for timing

The received lines carry timestamps, and the gaps between them are where a delay actually happened.

grep -i '^Received:' message.eml | tac | head -10
grep -iE '^(Date|Received):' message.eml | head -12

Read from the bottom upwards. Each line was added by a server as the message passed through, so the earliest is at the bottom and the most recent at the top.

A large gap between two consecutive lines names the system that held the message. That is the answer to the most common question about mail, which is why something took four hours, and it is visible in the headers rather than requiring anybody's logs.

Match the message to your own logs

The identifier in the headers is what connects a customer's complaint to a record on your server.

grep -i '^Message-ID:' message.eml
grep -F "$(grep -i '^Message-ID:' message.eml | cut -d' ' -f2 | tr -d '<>')" /var/log/exim_mainlog | head
exim -Mvl "$(grep -oE '[0-9A-Za-z]{6}-[0-9A-Za-z]{6}-[0-9A-Za-z]{2}' /var/log/exim_mainlog | head -1)" 2>/dev/null

Searching the mail log for the identifier finds every line about that specific message, including the acceptance, the delivery attempt and the response from the receiving server.

That response is the useful part. It is the receiving side's own words about why the message was refused or deferred, which is more precise than any bounce message the sender sees.

Recognise the headers that indicate forgery

The visible sender is decoration, and a small number of fields tell you whether it was really sent by whom it claims.

grep -iE '^(Authentication-Results|Received-SPF|DKIM-Signature|Return-Path|Reply-To|From):' message.eml

Three mismatches are worth recognising. A return path on a different domain from the visible sender. A reply address that differs from the sender. And an authentication result showing a pass for a domain that is not the one displayed.

The last is the subtle one, because a check can pass legitimately for the sending infrastructure while the displayed name is fabricated. Reading which domain passed, rather than that something passed, is the whole distinction. Stopping your domain being used for spoofing covers the protection.