Email header analysis

The headers on an email record its journey: which servers handled it, in what order, from what IP addresses, and at what exact times. Reading them traces the route from sender to recipient and often reveals the sender’s real location even when they tried to hide it.

The “From” field shows whoever the sender chose to display. The headers show what the servers actually recorded. Any recipient can read them. No special access is required.

Every relay signs the docket

Each SMTP server that accepts a message for further transmission adds a “Received” header to the top of it. Reading the Received headers from bottom to top reconstructs the journey in chronological order.

for each "Received" header (reading bottom to top):
    extract: originating server name, IP address, timestamp
    check: does the IP resolve to a claimed location?
    check: does the sequence of servers make sense geographically?
    check: does the sender's domain match the IP that first injected the message?

An analysis script opens the email file, walks every header and prints the chain. The oldest Received entry is usually the most revealing, because it records the earliest SMTP hop the recipient can see. That hop may be the sender’s own connection. It may equally be a submission server, a webmail service, a relay, a filtering gateway or a forwarding service, and the header does not announce which.

Where the sender’s own connection is visible, the address identifies the access provider holding it and may give a rough geographic indication. It does not establish where the sender was. Residential allocations, mobile networks, carrier-grade NAT and the accuracy of whichever geolocation database is consulted all sit between an address and a place.

The “Subject” and “Date” headers, decoded from MIME encoding, confirm the content and timing. A message claiming to originate in London that first appears on a server somewhere unexpected has already contradicted itself, and the chain is where that shows.

Three messages

greenhouse-attacks headers.py parses the chain against the grammar in RFC 5321 section 4.4 rather than against a sample of real mail, so the specification is what the parser answers to. The messages it reads are written from that grammar too. They are constructed, not captured.

The grammar leaves one thing to the relay. After from comes the name the client claimed in its HELO greeting, and then, in comments, whatever else the relay chose to record, including the address it actually saw. Implementations disagree about where in those comments the address goes, so the parser takes the last comment containing one, which is where the connection information sits in every shape the tests cover: square brackets, bare parentheses, an IPv6 literal, a link-local address with a zone, an ident prefix, and a HELO note written before the address.

A client can claim a private address in its greeting that the relay never saw, and the observed address wins over it. Where the relay recorded no address at all, the parser falls back to the greeting only when that was itself an address literal, and otherwise reports nothing. The webmail row is that case.

Three messages, the first two identical in author, text and number of relays, differing only in how they were sent:

Claimed sender

Where the chain starts

Address recorded

Sent from a mail client

joris@provider.example

thinkpad.fritz.box

93.104.22.18

Sent through webmail

joris@provider.example

nothing

none

Forged sender

no-reply@amsterdam.example

unknown

171.96.4.12

The first row gives up two things, not one. The address is the connection the submission server accepted in this configuration, and it resolves to a subscriber line. The hostname is a second piece of information supplied during the SMTP exchange, and it is supplied by the client. It can be useful evidence, and it proves nothing on its own: a client can present a name with no relation to the address the receiving server saw.

The second row has no client hop at all. The browser spoke to the provider over HTTP and the provider’s own server opened the chain, so there is no earlier address for it to record. Nothing was taken out of the message. There was never anything there to take.

The third row is the same trace read against the From field. The message asserts a municipality and the chain begins at a consumer broadband address. No part of SMTP compares the two. The trace records what the relays did; the From field records what the sender typed.

An address is not yet a person

Once an SMTP relay has added a Received header, the sender normally cannot alter that copy of the message. What the header holds is that relay’s account of what it received, including whichever connection information it chose to preserve. An investigator, an adversary, or anyone with basic technical literacy can read the chain, check whether the claimed sender domain is consistent with the earliest address, and follow the path through the intermediate relays.

In Breyer the Court of Justice held that a dynamic IP address constitutes personal data with respect to a service provider where that provider has the legal means enabling it to identify the person behind the address using additional information held by the access provider. The address is personal data because of what somebody else can be made to supply, and the recipient of a message holds it already.

The whole exercise has that shape. A header records a network event. The event points at a piece of infrastructure. The infrastructure points at a subscriber, if somebody can compel the records. The subscriber points at a person, if the subscriber and the person are the same. Every arrow in that chain can fail, and the header establishes only the first one.

So the address gives an investigator another system to ask. An access provider may know which subscriber held it at that moment. A mail provider may know which account submitted the message. A legal process may connect those records to each other. The header is the first link, and the chain is what identifies anybody. This is routine in forensic email analysis, in spam filtering and in phishing investigations.

Losing the first hop

Webmail does not depend on a provider removing the address. A message composed in a browser reaches the provider over HTTPS, and the provider’s own infrastructure then submits it by SMTP, so the sender’s connection can be absent from the chain the recipient sees.

The provider knows that address from the web session. What the provider holds and what travels with the message are different things, and the recipient only ever sees the second. Submitting over SMTP from a mail client puts the connection into the chain itself. The first two rows of the table differ by exactly that.

A separate X-Originating-IP header can still record it. The X- prefix marks it as a convention rather than anything the protocol requires, a practice RFC 6648 deprecates because such headers become de facto standards without ever being specified, so whether it appears is the provider’s decision.

A remailer or an anonymising mail service puts its own hops in front of the sender’s. Webmail, a remailer and an anonymising service can all keep the recipient-visible chain free of any address belonging to infrastructure the sender occupies. None of them guarantees it, and a provider’s own logs are outside the message either way.

Last reviewed: 2026-09-19.