Skip to content
AdminKit

How do you read email headers to trace a message?

To trace an email, read its Received headers from the bottom up: each server prepends one, so the lowest is the origin and the top is your own server. Trust only hops your servers added. AdminKit's email header analyzer reorders the chain, computes hop delays and lists every Authentication-Results verdict, entirely in your browser.

By AdminKit team, Netbase JSC · Updated

Key takeaways

  • Every SMTP server that accepts a message must prepend a Received header and must not reorder the existing ones (RFC 5321 §4.4). Read the chain from the bottom up to follow the message from origin to inbox.
  • Only the hops added by servers you run or trust are evidence. Anything below the first trusted hop was written by the sender’s side and can be invented.
  • Authentication-Results records what a specific receiving server concluded about SPF, DKIM and DMARC (RFC 8601). Trust it only when its identifier belongs to your own mail system.
  • Return-Path is the envelope sender recorded at final delivery, From is the author address the reader sees, and Message-ID is the identifier the sending system generated. Each answers a different question.
  • AdminKit’s email header analyzer reorders the chain origin-first, computes hop delays and lists every Authentication-Results header. It reads; it does not verify anything live.

Where do you find the raw headers?

A mail client shows you a tidy From, To, Subject and Date. The full header block is hidden behind an option usually called “Show original”, “View source” or “View message source”. Copy everything from the first line down to the first blank line: that blank line separates the header section from the body.

Paste that block into the email header analyzer. It parses the text in your browser, so nothing you paste leaves the tab, and it never connects to a mail server or queries DNS. That matters for header analysis in particular, because headers routinely contain internal hostnames, private IP addresses and recipient addresses you would not want to send to a third party.

Get the headers from the copy of the message that reached the mailbox you care about. A forwarded copy has a new header block written by the forwarding step, and the original trace is either lost or buried inside an attachment. RFC 8601 §4.1 also says mail clients should ignore Authentication-Results headers found inside attached messages, because they “are likely to contain the results of authentication checks done in the past”.

How is the Received chain ordered?

RFC 5321 §4.4 is the rule that makes tracing possible. When an SMTP server accepts a message for delivery or relay, it “MUST insert trace (“time stamp” or “Received”) information at the beginning of the message content”. It also says servers “MUST prepend Received lines to messages; they MUST NOT change the order of existing lines or insert Received lines in any other location”, and that no mail program may change or delete a Received line that was already there.

The result is a stack. The newest hop sits at the top, the oldest at the bottom. To follow the message’s journey, start at the bottom and read upwards.

Here is a shortened example for an imaginary message. Domains are reserved example names and the addresses come from the documentation ranges, so none of it points at a real system:

Return-Path: <[email protected]>
Received: from mx-in.example.com (mx-in.example.com [192.0.2.10])
        by mailstore.example.com with LMTP id 4QxY2; Tue, 10 Nov 2026 09:14:07 +0000
Authentication-Results: mx-in.example.com;
        spf=pass smtp.mailfrom=mailer.example.net;
        dkim=pass header.d=example.org;
        dmarc=pass header.from=example.org
Received: from out-7.mailer.example.net (out-7.mailer.example.net [198.51.100.25])
        by mx-in.example.com with ESMTPS id 8KdP1 for <[email protected]>;
        Tue, 10 Nov 2026 09:14:05 +0000
Received: from app-host.internal (unknown [10.20.0.5])
        by out-7.mailer.example.net with ESMTP id Q91ZZ;
        Tue, 10 Nov 2026 09:13:58 +0000
From: "Example Org Billing" <[email protected]>
Message-ID: <[email protected]>

Read from the bottom, there are three hops. The table puts them in travel order, which is the order the header analyzer shows:

HopFrom (claimed name and connecting IP)By (server that wrote the line)TimestampDelayWho wrote it
1app-host.internal [10.20.0.5]out-7.mailer.example.net09:13:58—The sender’s mail service
2out-7.mailer.example.net [198.51.100.25]mx-in.example.com09:14:057 sYour inbound mail server
3mx-in.example.com [192.0.2.10]mailstore.example.com09:14:072 sYour internal mail store

The from clause carries two different things. RFC 5321 §4.4 says it should contain “the name of the source host as presented in the EHLO command” and “an address literal containing the IP address of the source, determined from the TCP connection”. The name is whatever the connecting host claimed about itself. The IP address in brackets is what the receiving server observed on the connection, which makes it the more useful of the two, but only when the receiving server is one you trust.

Which hops can you actually trust?

This is the part most header walkthroughs skip. The sender controls the entire message before it reaches the first server outside their control, including any header lines they choose to write. Nothing stops a spammer from adding three plausible-looking Received lines at the bottom of a message before sending it.

So the useful question is not “which line is lowest?” but “which line did my own infrastructure write?”. Work from the top down:

  1. Skip the hops between your own servers (in the example, hop 3: your mail store recording delivery from your inbound gateway).
  2. Find the first line whose by is your inbound mail server, or the mail provider you use (hop 2). That server saw the TCP connection itself.
  3. The IP address in that line’s from clause (198.51.100.25) is the most reliable fact in the whole header: the real address that handed the message to you.
  4. Everything below that line (hop 1) was written by systems on the sending side. It may be accurate, and for a reputable mail service it usually is, but you can’t verify it from the headers.

Once you have that address, you can look it up with AdminKit’s IP info, reverse DNS and blacklist check tools. The analyzer also shows the earliest public IP it can identify in the chain; treat that as a lead to investigate, not as proof of origin, for the reason above.

What does a forged hop look like?

A forged Received line is syntactically ordinary, so you spot it by inconsistency rather than by format. Signs worth checking:

SignWhy it matters
The by host of one hop does not match the from host of the hop above itReal relays hand the message on directly; a gap suggests a line was invented or a relay is missing
A hop below your trusted server names a well-known provider, but the trusted hop’s connecting IP does not belong to that providerThe claimed path and the observed connection disagree
Timestamps below the trusted hop are far in the past or out of sequenceForged lines are often copied from old messages
A Received line claims to come from your own domain but sits below your inbound serverYour own servers should only appear above the hop where the message entered
Several Authentication-Results headers carry your own identifierRFC 8601 §5 says your server must remove such copies when they arrive from outside

None of these is proof on its own. Clock errors and unusual relay setups produce some of the same symptoms, which is why the analyzer’s computed delays are labelled as approximate. RFC 5321 §4.4 asks servers to use “explicit offsets in the dates (e.g., -0800), rather than time zone names”, but a server with a wrong clock still writes a wrong time.

How do you read Authentication-Results?

RFC 8601 defines Authentication-Results as the header a receiving server adds to record the outcome of the authentication checks it ran. The first value is the authentication service identifier (authserv-id), naming the server or organization that did the checking. Then come one or more method=result pairs, each with properties showing what was checked:

Part of the headerExampleMeaning
authserv-idmx-in.example.comWho performed the checks
spf= + smtp.mailfrom=spf=pass smtp.mailfrom=mailer.example.netSPF result for the envelope sender’s domain
dkim= + header.d=dkim=pass header.d=example.orgA DKIM signature from that domain verified
dmarc= + header.from=dmarc=pass header.from=example.orgDMARC result for the visible From domain

Method names, result values and property types come from IANA’s Email Authentication Parameters registry. RFC 8601 §4.1 tells mail clients to ignore results using a result value or property type that is not in those registries.

Two rules from the RFC decide how much weight the header deserves:

  • Position. RFC 8601 §4.1 says the header “MUST be treated as though it were a trace header field” and “MUST be prepended to the message”, so its position relative to the Received lines shows where in the chain the checks were done. In the example, it sits just above hop 2 because mx-in.example.com added it when accepting the message.
  • Ownership. RFC 8601 §5 requires a receiving server to “delete any discovered instance of this header field that claims, by virtue of its authentication service identifier, to have been added within its trust boundary but that did not come directly from another trusted MTA”. In practice, the copy that carries your own server’s identifier is the one to read. A copy with an unfamiliar identifier is someone else’s statement.

RFC 8601 also gives a warning that applies to every reader of headers: a lookalike domain such as examp1e.com can carry a perfectly valid DKIM signature, so a verifier “would detect that the signature was valid and report a ‘pass’ even though it’s clear the DNS domain name was intended to mislead”. A pass tells you which domain authenticated, not whether that domain is the one you expected.

What do Return-Path, From and Message-ID tell you?

These three fields answer different questions, and confusing them is a common source of wrong conclusions:

  • Return-Path is added at final delivery. RFC 5321 §4.4 says it “preserves the information in the from the MAIL command” and is the address non-delivery reports go to. It is the domain SPF checks, which is why the example’s smtp.mailfrom matches it.
  • From is the author address defined by RFC 5322, the one the reader sees. DMARC checks this domain, and it often differs from Return-Path: mailing lists and bulk senders commonly use their own bounce domain.
  • Message-ID is the identifier the originating system generated. RFC 5322 §3.6.4 says every message “SHOULD have” one and that it “MUST be a globally unique identifier”, typically with the generating host’s domain on the right of the @. A Message-ID whose domain matches the sending service is consistent; a mismatch is not proof of anything but is worth noting alongside other signs.

When SPF fails only for forwarded mail, the cause is usually the forwarding hop rather than the original sender, as explained in why email forwarding breaks SPF. If a header block came back attached to a bounce, decode the SMTP reply and enhanced status code with the SMTP status code decoder, and see email bounces and backscatter explained for when a bounce itself is the problem.

What should you do after tracing a message?

The trace tells you where a message came from and what your server concluded about it. What you do next depends on what you found:

  1. Authentication failed for your own domain’s mail. Check the live records with AdminKit’s SPF check, DKIM check and DMARC check. The header shows the verdict at the time of delivery; the checks show what DNS publishes now.
  2. The trusted connecting IP is unexpected. Investigate that address with IP info, reverse DNS and the blacklist check, and compare it with the sending service’s published ranges.
  3. The message is a lookalike. If the domains passed authentication but look slightly wrong, paste them into the IDN homograph check to see the Punycode form and any mixed-script characters.
  4. Delivery was slow. Look for the hop with the largest delay, remembering that clock errors can move the gap to the wrong hop.

For how SPF, DKIM and DMARC fit together before you dig into individual failures, read SPF, DKIM and DMARC explained. This guide is part of AdminKit’s email authentication cluster.

This guide is general information, not a security audit of your specific network — see our disclaimer for what AdminKit's guidance does and does not commit to.

Frequently asked questions

Which Received header is the original sender?

Usually the lowest one in the raw header block, because RFC 5321 §4.4 requires every SMTP server to prepend its Received line at the top and never reorder existing ones. But the lowest line is only as trustworthy as whoever wrote it: a sender can insert fake Received lines before the message reaches the first server you trust. The first hop you can rely on is the one where your own receiving server records the connecting IP address.

Can I trust an Authentication-Results header that says spf=pass?

Only if your own mail system added it. RFC 8601 §5 requires a receiving server to delete any Authentication-Results header that claims its own authentication service identifier but did not come from a trusted server, and RFC 8601 §4.1 tells mail clients not to interpret the header unless the identifier is one used inside their own organization. A header with someone else's identifier is a claim, not a verdict you checked.

What is the difference between Return-Path and From?

Return-Path is written by the server that makes final delivery and records the envelope sender from the SMTP MAIL FROM command (RFC 5321 §4.4); it is where bounces go. From is the author address the message itself carries (RFC 5322) and is what the reader sees. They often differ legitimately, for example with mailing lists or bulk senders using a separate bounce address.

Why are the time gaps between hops sometimes negative?

Each Received timestamp comes from that server's own clock. RFC 5321 §4.4 asks servers to write an explicit numeric time zone offset, but a server with a wrong clock or a wrong offset still produces a timestamp that does not line up with its neighbours. Treat per-hop delay as a rough indication; a single negative gap usually means a clock problem, not tampering.

Does AdminKit's email header analyzer check SPF, DKIM or DMARC itself?

No. It parses the headers you paste, entirely in your browser, and shows the verdicts already written in Authentication-Results. It never queries DNS or re-runs any check. For a live check of a domain's current records, use AdminKit's SPF check, DKIM check or DMARC check.

Want AdminKit to watch this for you?

Free checks tell you the state today. Protective DNS and monitoring tell you when it changes.

Huy Nguyen (David), Founder and CEO of Netbase JSC

Talk to an expert

Huy Nguyen (David), Founder & CEO, Netbase JSC

Ask whether this fix applies to your setup, or get a second pair of eyes on your DNS and mail records.