HackBlue

Tools · Email security · 10 / 18

Reading raw email headers: tracing the Received chain hop by hop

Open the raw source of a message, read Received headers from bottom to top, identify the true originating server, and know which headers a sender can forge.

9 min read · practice only with authorization

Getting the raw source

Every client can show the original message: “Show original” in Gmail, “View message source” in Outlook on the web, and “View Source” in Thunderbird. Save it as a .eml file so you analyze an unmodified copy and keep it as evidence.

Reading Received headers

Each server that handles a message adds a Received header at the top, so the newest is first and the oldest is last. Read from the bottom up. The most trustworthy hop is the first one added by your own organization’s servers, because it records the IP that actually connected to you. Anything below that line was written by systems you do not control and may be forged.

Snippet
Received: from mx.example.org (10.0.0.5) by mbx01.example.org; Mon, 2 Nov 2026 10:02:11 +0000
Received: from mail-out.sender.example (198.51.100.40) by mx.example.org with ESMTPS; Mon, 2 Nov 2026 10:02:10 +0000
Received: from [192.0.2.17] (unknown) by mail-out.sender.example; Mon, 2 Nov 2026 10:02:08 +0000   <- written by the sender's side

Lab: trace a message you received

Save the raw source of a legitimate external message. Extract only the Received lines, number them from the bottom, and for each record the from host, by host, IP, and timestamp. Mark the first hop added by your provider and note the connecting IP there. Compare time gaps between hops; large gaps can indicate queueing or a header inserted out of order.

Snippet
grep -n '^Received:' -A2 message.eml
python3 - <<'EOF'
import email
m = email.message_from_file(open('message.eml'))
for i, h in enumerate(reversed(m.get_all('Received', [])), 1):
    print(i, ' '.join(h.split())[:160])
EOF

What can be forged

From, Reply-To, Date, Message-ID, and any Received lines added before the message reached your servers are written by the sender and can be anything. Authentication-Results added by your own provider, and the connecting IP in your first trusted hop, are the reliable anchors.

  • Forgeable: From, Reply-To, Date, Message-ID, early Received lines
  • Reliable: your provider’s Received line and Authentication-Results

Diagram

Reading Received headers

  1. Bottom

    Oldest hop; written by the sender side and untrusted.

  2. Middle

    Relays and the sender’s outbound gateway.

  3. Trusted boundary

    First hop added by your own servers; records the real connecting IP.

  4. Top

    Internal delivery to the mailbox.

Check yourself

1. Where is the newest Received header?

2. Which Received line gives the most reliable connecting IP?

3. Which header can the sender set to any value?