Email Header Integrity Analysis: Do Forwarded Messages Preserve Original Headers in SMTP?


3 views

When examining email header preservation during forwarding, we need to consider both RFC standards and real-world implementations. The original headers typically remain intact, but new headers are prepended to the message by each forwarding agent.

Let's examine how to inspect headers programmatically using Python's email library:

import email
from email import policy

def analyze_forwarded_message(raw_email):
    msg = email.message_from_string(raw_email, policy=policy.default)
    
    print("Original Headers:")
    print(msg.get_all('Received', []))
    print("\nForwarded Headers:")
    print(msg.get_all('X-Forwarded-By', []))
    
    return {
        'original_headers_present': bool(msg.get_all('Received')),
        'forwarding_metadata': msg.get_all('X-Forwarded-By', [])
    }

Different email clients handle forwarding differently:

  • Gmail: Preserves original headers but adds "Forwarded by" headers
  • Outlook: Typically maintains original headers while adding new routing information
  • Apple Mail: May restructure headers but keeps essential origin data

For developers needing to verify header integrity:

# Bash command to view full headers
curl -v smtp://mail.example.com -T message.eml

# Alternative using openssl
openssl s_client -connect mail.example.com:25 -starttls smtp -crlf

When building email analysis tools, consider these key header fields:

Header Field Preservation in Forwarding
Received Usually preserved, new entries added
Return-Path Often modified by forwarding server
DKIM-Signature May break during forwarding

For enterprise applications, implement header verification logic like:

def verify_header_integrity(msg):
    original_received = [h for h in msg.get_all('Received', []) 
                        if 'original-domain.com' in h]
    return len(original_received) > 0

When analyzing email headers during forwarding operations, we need to understand the fundamental architecture. The original email headers remain intact but get embedded within the new message structure. Modern email clients typically preserve the complete header chain while adding new routing information.

Received: from mailserver.example.com (mailserver.example.com [192.0.2.1])
    by mx.google.com with ESMTPS id abc123def456
    for ; Tue, 1 Jan 2023 12:00:00 -0800 (PST)
Received: from sender@origin.com
    by mailserver.example.com with SMTP id xyz789
    for ; Tue, 1 Jan 2023 11:30:00 -0800

Major email clients handle header preservation differently:

  • Gmail: Maintains complete original headers in the "Original Message" section
  • Outlook: Embeds headers but may reformat them for display
  • Thunderbird: Shows full headers in source view with clear demarcation

When processing forwarded emails programmatically, developers should use proper parsing libraries. Here's a Python example using the email module:

import email
from email import policy
from email.parser import BytesParser

# Parse the raw email
with open('forwarded_email.eml', 'rb') as fp:
    msg = BytesParser(policy=policy.default).parse(fp)

# Access all headers including original
all_headers = msg.items()
print("Current headers:", all_headers)

# Find the original message if embedded
original_msg = None
for part in msg.walk():
    if part.get_content_type() == 'message/rfc822':
        original_msg = part.get_payload()[0]
        break

if original_msg:
    print("Original headers:", original_msg.items())

When building email processing systems, consider these key points:

  1. Always check for embedded messages (content-type: message/rfc822)
  2. Trace the "Received" headers chronologically from bottom to top
  3. Be aware that some forwarding services might modify headers
  4. Use proper MIME parsing libraries rather than regex for reliability

Create test cases with different forwarding scenarios. Here's how to generate test emails using Python's email package:

from email.message import EmailMessage
from email.mime.multipart import MIMEMultipart
from email.mime.message import MIMEMessage

# Create original message
original = EmailMessage()
original['From'] = 'sender@example.com'
original['To'] = 'forwarder@example.com'
original['Subject'] = 'Original Subject'
original.set_content('Test body')

# Create forwarded message
forwarded = MIMEMultipart()
forwarded['From'] = 'forwarder@example.com'
forwarded['To'] = 'final@example.com'
forwarded['Subject'] = 'Fwd: Original Subject'

# Embed original message
forwarded.attach(MIMEMessage(original))

# Now 'forwarded' contains complete original headers

Remember that DKIM signatures and other security headers might break during forwarding, which is a separate consideration for email security implementations.