MailDingo

Read the fields

How to read Received headers

Received headers are the message's travel log, newest on top. Read them from the bottom, and trust only the hops added by servers you trust.

6 min read · updated 2026-10-26 · 4 RFC sections cited

Every mail server that accepts a message adds one Received: line to the top of the header. So the newest hop is first and the oldest hop is last: to follow the message from sender to you, start at the bottom Received: line and read upward. Only the top few lines, the ones your own provider added, are guaranteed to be real. Anything below the first hop that came in from the outside world could have been written by the sender, including a forger.

Why they stack upward

SMTP servers are required to prepend their trace line and must never edit, delete or reorder the ones already there (RFC 5321 §4.4). The message format spec calls Received: and Return-Path: the "trace fields" and leaves their detailed meaning to SMTP (RFC 5322 §3.6.7). The upshot: the header behaves like a stack of stamps, and each server can only add to the top of it.

The parts of one Received line

RFC 5321 §4.4 defines the structure. A typical line, unfolded:

Received: from mail.example.net (mail.example.net [198.51.100.23])
        by mx1.example.com (Postfix) with ESMTPS id 4Xb7Qm2zLp
        for <alex@example.com>; Mon, 26 Oct 2026 09:14:07 -0400
Clause Meaning Who wrote it
from mail.example.net The name the connecting server gave in its HELO/EHLO greeting Claimed by the sender
(mail.example.net [198.51.100.23]) Reverse-DNS name and IP address of the connection Observed by the receiving server
by mx1.example.com The server that accepted the message and wrote this line Receiving server
with ESMTPS The protocol used for this hop (see protocol keywords) Receiving server
id 4Xb7Qm2zLp The receiving server's internal queue ID, useful for searching its logs Receiving server
for <alex@example.com> The recipient this copy was for (optional) Receiving server
after ; When the receiving server accepted the message Receiving server's clock

There is also an optional via clause, which names the link type; you will rarely see it on modern internet mail. Software often adds its own name in parentheses ((Postfix), (Exim 4.98)), plus TLS details. Those comments are free-form and vary by product.

The for clause can leak who else got a message, so the RFC says it should hold only one recipient and be used with care when there are several (RFC 5321 §4.4, §7.6). Many servers omit it.

Claimed versus verified: the most useful distinction

The from clause mixes two kinds of information, and telling them apart is the core skill.

  • The first name (from mail.example.net) is whatever the connecting server said in its EHLO command. A spammer's machine can say anything there, including mail.example.com or localhost. Receiving servers may check it but are not allowed to reject mail just because it doesn't match the IP (RFC 5321 §4.1.4).
  • The part in parentheses is what the receiving server saw on the TCP connection: the IP address in square brackets and, usually, the name it found by reverse DNS for that IP. The spec says this part comes from the connection, not from the client's greeting (RFC 5321 §4.4).

So the IP in brackets is the hard fact. If the greeting name and the reverse-DNS name disagree wildly, for example a greeting of mail.examplebank.example from an IP whose reverse DNS is a home broadband pool, that tells you something. A mismatch alone is not proof of abuse, though: plenty of legitimate servers have sloppy greetings.

Formats differ. Some servers write from [198.51.100.23] (helo=mail.example.net), Microsoft writes the name and IP without the nested parentheses, and some omit reverse DNS entirely. Look for the bracketed IP; that is the observed address.

Which hops can you trust?

A Received: line is only as trustworthy as the server that wrote it. Your mail provider's servers are honest about what they saw. Everything below the point where the message entered your provider was written by servers you know nothing about, and a forger can prepend any number of fake Received: lines before sending.

The practical method:

  1. Start at the top and walk down through the lines your own provider added (they will all have by names in your provider's domain).
  2. Stop at the first line whose from clause is a server outside your provider. That line was written by your provider, so its bracketed IP is the real address that handed the message over. This is the most important single fact in the header.
  3. Lines below that were supplied by the sending side. Treat them as claims. They are often accurate and useful (they show the sender's internal routing), but they prove nothing.

The Authentication-Results header your provider adds near the top is what tells you whether that connecting IP was allowed to send for the domain.

Watch out: A forged message can contain a perfect-looking chain of Received: lines through a big provider's servers. If those lines sit below your provider's first inbound hop, they were part of the message the attacker submitted, not something that actually happened.

Internal hops

Large providers pass mail through many servers internally: a border server, filters, then mailbox storage. You might see five or more lines with private addresses such as 10.x.x.x, IPv6 addresses, or names in the provider's own domain, and protocols like LMTP or HTTP. These are normal. Sending organizations do the same: the bottom lines often show a laptop or app handing mail to the company's submission server (look for with ESMTPSA, meaning an authenticated submission). Some organizations strip or anonymize these internal lines for privacy, which RFC 5321 §7.6 acknowledges as a reasonable concern.

Timestamps and delays

Each line's date is set by the clock of the server that wrote it. Subtracting adjacent timestamps (after converting offsets to UTC; see the Date header guide) shows how long each hop took. A gap of hours usually means a queue, a greylisting retry or a slow filter. Small negative gaps usually mean one server's clock is a little off. For a full troubleshooting walk-through, see why is my email delayed.

A fully annotated example

Here is a synthetic message from a company sending through its own server to a recipient at another provider. Read it from the bottom up.

Received: from mx-in-3.mail.example.org (2001:db8:10::15)
        by store-7.mail.example.org with LMTP; Mon, 26 Oct 2026 13:14:09 +0000
Received: from out.example.net (out.example.net [203.0.113.40])
        by mx-in-3.mail.example.org (Postfix) with ESMTPS id 7Hq2Xc
        for <sam@example.org>; Mon, 26 Oct 2026 13:14:08 +0000
Received: from [192.0.2.77] (unknown [192.0.2.77])
        by out.example.net (Postfix) with ESMTPSA id 3Kd9Zr
        for <sam@example.org>; Mon, 26 Oct 2026 09:14:05 -0400
  • Bottom line (oldest): A device at 192.0.2.77 logged in to out.example.net (ESMTPSA: TLS plus authentication) and submitted the message at 09:14:05 local time (offset -0400), which is 13:14:05 UTC. The device didn't send a proper hostname, so the server shows the literal IP and unknown. Written by the sender's server: a claim from your point of view.
  • Middle line: The recipient's provider (mx-in-3.mail.example.org) accepted a connection from 203.0.113.40, which reverse-resolves to out.example.net, over TLS, three seconds later. This is the first hop written by the recipient's provider, so 203.0.113.40 is the trustworthy origin IP.
  • Top line (newest): An internal LMTP delivery to mailbox storage over the provider's internal network. Normal.

Paste a real header into the analyser and it lays these hops out as a timeline with the delay between each one.

In the RFC: Servers are told to write times with numeric offsets such as -0400 rather than zone names, and to use local time where they can (RFC 5321 §4.4). That is why one chain can mix -0400 and +0000.

Got a suspicious email?

Paste its headers into the analyser. It runs on your device and explains every result on this page.

Open the analyser

Next in Read the fields: SMTP protocol keywords in Received headers →