When examining email headers, the Received: from
line contains crucial routing information. The IP address in this field typically represents the last MTA (Mail Transfer Agent) that handled the message before it reached the current server. This could be:
- The sender's SMTP server (when using email clients)
- The webmail server's outbound interface (when using webmail)
- An intermediate relay server
Consider this sample header chain:
Received: from mail.example.com (192.0.2.1) by mx.google.com with ESMTPS Received: from [198.51.100.25] (user-pool-198-51-100-25.example.net) by mail.example.com with ESMTP
The most recent (top) Received
header shows the immediate sender as mail.example.com (192.0.2.1), while the earlier one reveals the originating IP as 198.51.100.25.
When processing emails programmatically, you might extract this information using regular expressions:
import re header = """Received: from mail.example.com (192.0.2.1) by mx.google.com with ESMTPS Received: from [198.51.100.25]""" ips = re.findall(r'Received: from.*?(\d+\.\d+\.\d+\.\d+)', header) print(ips) # Output: ['192.0.2.1', '198.51.100.25']
The IP address interpretation varies:
Scenario | "Received: from" IP Meaning |
---|---|
Webmail (Gmail/Outlook) | Webmail server's outbound IP |
Corporate SMTP | Company mail server IP |
Direct send | Sender's public IP (if not behind NAT) |
While useful for tracing, these headers can be spoofed. Always verify with authentication results headers:
Authentication-Results: mx.google.com; dkim=pass header.i=@example.com; spf=pass (google.com: domain of sender@example.com)
When examining raw email headers, you'll often encounter multiple Received:
fields forming a delivery chain. The most relevant one for sender identification is typically the first Received: from
entry, which follows this general format:
Received: from [hostname] ([IP address])
by receiving.mailserver.com with ESMTP id xyz123
for ; Wed, 15 Feb 2023 09:45:22 +0000 (UTC)
The IP address in the Received: from
field can represent either:
- Direct SMTP connection: The actual sender's IP when they use a mail client (Thunderbird, Outlook, etc.)
- Webmail proxy: The mail server's IP when sent via web interface (Gmail, Outlook Web Access)
- Forwarding service: An intermediate server's IP when mail is forwarded
Here's a Python snippet to parse and analyze Received headers:
import re
from email.parser import HeaderParser
def analyze_received_headers(raw_email):
headers = HeaderParser().parsestr(raw_email)
received_chain = headers.get_all('Received', [])
if not received_chain:
return None
first_received = received_chain[-1] # First hop is last in list
ip_pattern = r'$$?(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})$$?'
ip_match = re.search(ip_pattern, first_received)
return ip_match.group(1) if ip_match else None
# Example usage:
raw_email = "Received: from mx.google.com ([209.85.220.41])\nReceived: from [192.168.1.100]"
print(analyze_received_headers(raw_email)) # Output: 209.85.220.41
Consider these two scenarios:
# Scenario 1: Direct SMTP submission
Received: from [87.156.129.25] (user-pool.example.net)
by mail.provider.com with ESMTPS
# Scenario 2: Webmail submission
Received: from mail-sor-f41.google.com ([209.85.220.41])
by mx.example.org with SMTP
The first shows the user's public IP, while the second shows Google's server IP despite originating from Gmail's web interface.
Be aware that:
- IPs can be spoofed in poorly configured mail servers
- Some providers add X-Originating-IP headers for internal tracking
- VPNs and proxies will mask the true origin IP
For forensic analysis, examine these additional headers:
X-Originating-IP: 192.0.2.45
X-Forwarded-For: 203.0.113.22, 198.51.100.33
Authentication-Results: mx.google.com;
dkim=pass header.i=@senderdomain.com;
spf=pass (google.com: domain of sender@domain.com) smtp.mailfrom=sender@domain.com
Cross-reference these with the Received headers for more accurate sender identification.