Received headers are prepended by each mail server in reverse chronological order, so read them bottom-to-top to see the true path an email actually traveled — the bottom-most Received header is the oldest, closest to the original sender, and the top-most header is the newest, added last by the server closest to your own infrastructure. That top-most header is also the most trustworthy one in the stack, because it's the header a server you control or recognize wrote down from what it directly observed on the network connection — everything below it is, to some degree, a claim the sender's own systems made about themselves, and claims can be forged. The rest of this guide breaks down exactly what each field in a Received header means, how to verify it, and how to spot the specific patterns that indicate spoofing.
How a Received header is built
Every time a message hops from one mail server to the next, the receiving server writes a new Received header and stacks it on top of whatever headers were already there. Nothing is ever edited or removed — only added — which is what makes the stack a reliable (if occasionally forgeable) audit log of the message's journey.
Basic Received header
Received: from mail.example.com ([192.0.2.1]) by mx.company.com with SMTP id abc123def for <john@company.com>; Wed, 15 Jan 2025 14:32:10 -0500
Here's that same header broken into its six parts, with the level of trust you should place in each one:
<rect x="392" y="150" width="304" height="34" rx="8" fill="#ffffff" stroke="#f59e0b" stroke-width="1.5"/>
<text x="408" y="163" font-size="12" font-weight="bold" fill="#b45309">IP ADDRESS — what the server saw</text>
<text x="408" y="177" font-size="10" fill="#64748b">Logged by the receiving server itself</text>
<circle cx="680" cy="167" r="4" fill="#16a34a"/>
<text x="672" y="170" text-anchor="end" font-size="9" fill="#15803d">trust</text>
<rect x="392" y="200" width="304" height="34" rx="8" fill="#ffffff" stroke="#0d9488" stroke-width="1.5"/>
<text x="408" y="213" font-size="12" font-weight="bold" fill="#0d9488">BY — this hop's own hostname</text>
<text x="408" y="227" font-size="10" fill="#64748b">Trustworthy if you recognize this server</text>
<circle cx="680" cy="217" r="4" fill="#16a34a"/>
<text x="672" y="220" text-anchor="end" font-size="9" fill="#15803d">trust</text>
<rect x="392" y="250" width="304" height="34" rx="8" fill="#ffffff" stroke="#7c3aed" stroke-width="1.5"/>
<text x="408" y="263" font-size="12" font-weight="bold" fill="#7c3aed">WITH — protocol used</text>
<text x="408" y="277" font-size="10" fill="#64748b">SMTP / ESMTP / ESMTPS</text>
<circle cx="680" cy="267" r="4" fill="#64748b"/>
<text x="672" y="270" text-anchor="end" font-size="9" fill="#475569">info</text>
<rect x="392" y="300" width="304" height="34" rx="8" fill="#ffffff" stroke="#c026d3" stroke-width="1.5"/>
<text x="408" y="313" font-size="12" font-weight="bold" fill="#c026d3">ID — transaction ID</text>
<text x="408" y="327" font-size="10" fill="#64748b">Server's internal tracking number</text>
<circle cx="680" cy="317" r="4" fill="#64748b"/>
<text x="672" y="320" text-anchor="end" font-size="9" fill="#475569">info</text>
<rect x="392" y="350" width="304" height="34" rx="8" fill="#ffffff" stroke="#e11d48" stroke-width="1.5"/>
<text x="408" y="363" font-size="12" font-weight="bold" fill="#e11d48">FOR — recipient at this hop</text>
<text x="408" y="377" font-size="10" fill="#64748b">Can mislead with lists / BCC</text>
<circle cx="680" cy="367" r="4" fill="#f59e0b"/>
<text x="672" y="370" text-anchor="end" font-size="9" fill="#b45309">verify</text>
<rect x="392" y="400" width="304" height="34" rx="8" fill="#ffffff" stroke="#475569" stroke-width="1.5"/>
<text x="408" y="413" font-size="12" font-weight="bold" fill="#475569">TIMESTAMP — when it was logged</text>
<text x="408" y="427" font-size="10" fill="#64748b">Trustworthy, but check the timezone</text>
<circle cx="680" cy="417" r="4" fill="#16a34a"/>
<text x="672" y="420" text-anchor="end" font-size="9" fill="#15803d">trust</text>
The rule of thumb: anything the receiving server measured directly (the connecting IP, its own hostname, its own clock) is hard to fake. Anything the connecting client simply announced about itself (the "from" hostname, the "for" recipient) is a claim, not a measurement — verify it before you trust it.
Reading the email's path: why bottom-to-top matters
Each server prepends — it never edits or replaces — so the header stack is a literal, append-only log of the message's journey. The oldest entry (added first, by the sender's own server) ends up at the bottom; the newest entry (added last, by the server closest to you) ends up on top. Read bottom to top and you're reading the message's actual chronological path.
<rect x="210" y="220" width="220" height="64" rx="10" fill="#0d9488"/>
<text x="320" y="246" font-size="13" font-weight="bold" fill="#ffffff">Relay 2</text>
<text x="320" y="264" font-size="10" fill="#ccfbf1">e.g. destination spam filter</text>
<rect x="210" y="350" width="220" height="64" rx="10" fill="#7c3aed"/>
<text x="320" y="376" font-size="13" font-weight="bold" fill="#ffffff">Relay 1</text>
<text x="320" y="394" font-size="10" fill="#ede9fe">e.g. sender's outbound relay</text>
<rect x="210" y="480" width="220" height="64" rx="10" fill="#b45309"/>
<text x="320" y="506" font-size="13" font-weight="bold" fill="#ffffff">Original sender's server</text>
<text x="320" y="524" font-size="10" fill="#fde68a">adds this header FIRST</text>
<text x="450" y="498" font-size="12" font-weight="bold" fill="#b45309">Bottom = oldest</text>
<text x="450" y="514" font-size="11" fill="#475569">Self-reported by the</text>
<text x="450" y="528" font-size="11" fill="#475569">sender's own system —</text>
<text x="450" y="542" font-size="11" fill="#475569">verify before trusting.</text>
Worked example
Email from: john.doe@example.com
To: alice@company.com
Headers as they appear (TOP TO BOTTOM in the raw source):
3. (TOP — newest, added last)
Received: from mail.company.com by mx.company.com
with SMTP id abc123; Wed, 15 Jan 14:32:20 -0500
Analysis: Company's own mail server received it — final hop.
2. (MIDDLE)
Received: from mail.gmail.com by mail.company.com
with ESMTPS id def456; Wed, 15 Jan 14:32:15 -0500
Analysis: Gmail relayed it to the company's server.
1. (BOTTOM — oldest, added first)
Received: from smtp.example.com ([192.0.2.1])
by mail.gmail.com with ESMTP id ghi789
for <alice@company.com>; Wed, 15 Jan 14:32:05 -0500
Analysis: John's own server made first contact — origin of the message.
Path traced bottom to top: example.com (sent) → gmail.com (relayed) → company.com (received)
Which fields can you trust?
Not every field in a Received header carries the same evidentiary weight. Use this as a quick reference before you draw conclusions from a header chain:
| Field | Who wrote it down | Trust level |
|---|---|---|
from hostname | The connecting client announces this about itself | Verify — trivial to fake |
IP address in (...) | The receiving server observed this on the actual connection | Trustworthy — hard to fake |
by (receiving server) | The server writing this line, about itself | Trustworthy, if you recognize it as legitimate infrastructure |
with (protocol: SMTP/ESMTP/ESMTPS) | The receiving server | Informational only |
id (transaction ID) | The receiving server's internal system | Informational only |
for (recipient) | The receiving server, based on envelope data | Verify — can look odd on lists or BCC |
| Timestamp | The receiving server's own clock | Trustworthy, but check the timezone offset |
Interpreting each component in detail
From (sending server)
Received: from smtp.gmail.com
What it shows: the hostname the connecting server announced, as an FQDN or IP, possibly via reverse DNS.
Verify: is this a legitimate server for the claimed sender? Does the hostname match the sender's domain? Confirm with a WHOIS or DNS lookup rather than taking it at face value.
IP address in brackets
Received: from smtp.gmail.com ([142.250.185.46])
What it shows: the actual IP address of the sending server — more reliable than the hostname because it's logged by the receiving server, not self-reported.
Verify: look up the IP's geolocation and ownership, check it against the sender's known ranges, and run it through an IP reputation tool.
By (receiving server)
Received: by mx.company.com
What it shows: the hostname of the server that received the message at this hop.
Verify: is this the expected next hop? Does the server actually belong to the company named in the message?
With (protocol and ID)
Received: with SMTP id 47h8ai23skd
What it shows: SMTP (unencrypted, older), ESMTP (extended features), ESMTPS (ESMTP over TLS — encrypted), or LMTP (local delivery) — plus a unique transaction ID for that hop.
For (recipient at this hop)
Received: for <john@company.com>
What it shows: who the server believed the intended recipient was at that point. This can legitimately differ across hops when a mailing list is involved — the last "for" is the final recipient.
Timestamp
Wed, 15 Jan 2025 14:32:10 -0500
What it shows: when this server received the message, plus its timezone offset (-0500 = EST).
Verify: does the sequence make sense — should each Received header have an earlier timestamp than the one above it? Large or backwards gaps are worth a second look.
Symptom, cause, and fix: common Received-header red flags
| Symptom | Likely cause | What to do |
|---|---|---|
| Only one Received header on a message that claims to be external | Headers stripped, or the message was injected directly rather than relayed | Treat as suspicious; check the Authentication-Results header for SPF/DKIM/DMARC |
from hostname names a trusted brand, but the IP isn't in that brand's published ranges | Spoofed sender / hostname-IP mismatch | Look up the IP's real owner and compare against the brand's documented sending ranges |
Hostname shows unknown | Reverse DNS (PTR) lookup failed for that IP | Investigate the IP directly with WHOIS and a reputation lookup |
| A private IP (127.0.0.1, 192.168.x.x, 10.x.x.x) appears in an externally-received header | Forged header — private IPs should never traverse the public internet | Treat the message as spoofed |
| Timestamps decrease as you read up the stack | Manipulated or manually inserted headers | Re-verify the entire chain; don't trust the claimed path |
The from server has no relationship to the sender's claimed domain | An attacker-controlled relay, not the real sender | Confirm SPF/DKIM/DMARC results and verify with the sender out-of-band |
Detail: the six patterns worth knowing by name
Missing Received headers. A message with only a single, top-level Received header is either an internal forward, stripped headers, or a forged/injected message. Ask whether that's expected for this type of email.
Hostname/IP mismatch. Received: from gmail.com ([192.0.2.99]) — Gmail's real sending IPs live in ranges like 2607:f8b0::/32 and 142.250.0.0/15. An address like 192.0.2.99 isn't Google's. Treat as spoofed.
Reverse DNS failure. Received: from unknown ([192.0.2.50]) — the hostname "unknown" means the IP has no PTR record. Not proof of malice by itself, but worth an IP reputation check.
Private IP addresses. Received: from localhost ([127.0.0.1]) or a 192.168.* / 10.* address should never legitimately appear in the path of an externally-delivered message. Treat as forged.
Time sequence issues. If timestamps go backwards as you read up the stack (later hop shows an earlier time than the hop below it), the chain has likely been manipulated.
Server chain doesn't match the sender. From claims john@example.com, but the Received chain shows attacker.net. The email came from attacker.net — not example.com — regardless of what the From address says.
Reading multiple Received headers together
Email from: john.doe@example.com
To: alice@company.com
Subject: Important update
Headers (read BOTTOM TO TOP):
3. (TOP)
Received: from mail.company.com by mx.company.com
with SMTP id abc123; Wed, 15 Jan 14:32:20 -0500
Analysis: Company's mail server received it
2. (MIDDLE)
Received: from mail.gmail.com by mail.company.com
with ESMTPS id def456; Wed, 15 Jan 14:32:15 -0500
Analysis: Gmail relayed it to company server
1. (BOTTOM - ORIGINAL)
Received: from smtp.example.com ([192.0.2.1])
by mail.gmail.com with ESMTP id ghi789
for <alice@company.com>; Wed, 15 Jan 14:32:05 -0500
Analysis: John's company's server sent it
Path traced: example.com (john sends) → gmail.com (relayed) → company.com (alice receives)
Checking server legitimacy
Verifying Gmail emails
Legitimate Gmail sending IPs live in ranges including 2607:f8b0::/32 (IPv6), 142.250.0.0/15 (IPv4), and other Google-owned blocks.
Check: is the server gmail.com? Is the IP inside Google's range? Does the hostname match Gmail? If all three line up, it's likely legitimate. If the hostname says "gmail.com" but the IP is something like 192.0.2.1, that's spoofed.
Verifying Office 365 emails
Legitimate Microsoft mail infrastructure typically routes through outlook.office365.com, mail.outlook.com, or protection.outlook.com. Check that the server name and IP both fall within Microsoft's documented ranges before trusting the message.
Unknown companies
- Extract the IP from the Received header.
- Look up IP ownership with
whois. - Check whether the IP matches the claimed company.
- Verify against the company's actual published mail servers.
- Check email reputation databases for the IP.
Tools for header analysis
Online tools
Inventive HQ Email Header Analyzer — paste raw headers and get visual parsing, a path diagram, and automatic red-flag detection:
Google Admin Toolbox — free header analysis that shows the path clearly and surfaces SPF/DKIM/DMARC results.
MXToolbox — header analyzer with built-in IP reputation checks and reverse DNS lookups.
Command line
# Extract all Received headers
grep "^Received:" email.eml | tac # tac reverses order (bottom to top)
# Check specific IP
whois 192.0.2.1
# Reverse DNS lookup
nslookup -x 192.0.2.1
# IP geolocation
curl -s "http://ip-api.com/json/192.0.2.1"
Step-by-step header reading process
Step 1: Get the headers. View full headers in your email client and copy the raw text.
Step 2: Read from the bottom up. Find the original Received header at the bottom and note the "from" server and IP.
Step 3: Verify the IP. Look up ownership and check whether it belongs to the claimed sender's company. A mismatch is suspicious.
Step 4: Check authentication. Look for the Authentication-Results header and check the SPF, DKIM, and DMARC results (pass/fail).
Step 5: Verify the path. Read each Received header bottom to top and confirm each hop makes sense — no anomalies, no breaks in the chain.
Step 6: Make a decision. All checks pass → likely legitimate. Red flags found → likely spoofed. Uncertain → verify with the sender through a separate channel.
Common legitimate variations
Forwarded emails
A forward adds a new Received header from the forwarder on top of the original — having multiple Received headers is completely normal for a forwarded message.
Mailing lists
A mailing list server receives the original message and then re-sends it to subscribers, so both the list server's Received header and the original sender's Received header will legitimately appear.
BCC recipients
BCC doesn't change the Received headers at all — every recipient sees the same header chain regardless of whether they were BCC'd.
Real-world scenarios
Scenario 1: legitimate corporate email
From: ceo@company.com
Claims: Urgent wire transfer needed
Received: from mail.company.com ([203.0.113.10])
Step 1: Is 203.0.113.10 the company's IP? ✓ Yes, matches company website
Step 2: Reverse DNS: 203.0.113.10 → mail.company.com ✓
Step 3: Authentication: spf=pass, dkim=pass, dmarc=pass ✓
Step 4: Pattern matches a legitimate internal send ✓
Verdict: LIKELY LEGITIMATE — but always verify urgent financial requests through a second channel.
Scenario 2: phishing attempt
From: support@amazon.com
Claims: Verify your account
Received: from attacker.com ([192.0.2.99])
Step 1: Is 192.0.2.99 Amazon's server? ✗ No, doesn't match Amazon's ranges
Step 2: Reverse DNS: 192.0.2.99 → unknown/attacker.com ✗
Step 3: Authentication: spf=fail, dkim=fail, dmarc=fail ✗
Step 4: Pattern matches phishing ✗
Verdict: PHISHING — do not click any links.
Conclusion
The From address is what an attacker wants you to see; the Received chain is what actually happened. Read it bottom to top, trust the fields your own infrastructure measured directly over the fields the sender merely announced, and always cross-check the result against SPF, DKIM, and DMARC before you make a call. Master those two habits and you'll catch the great majority of spoofed and phished email before it does any damage.