A few years ago, I spent three days debugging why a client's transactional emails were landing in spam. The content was fine. SPF and DKIM were configured correctly. DMARC was passing. Everything looked perfect—until I actually read the raw headers.
Buried in the message was a header that said "X-Spam-Status: Yes, score=8.2". The client's own mail server was flagging the messages as spam before they even left the building. A misconfigured spam filter was adding that header, and downstream servers were trusting it.
Email headers tell a story. They record every server that touched a message, every authentication check that ran, every spam score that was calculated. Learning to read them is like learning to read a medical chart—suddenly you can diagnose problems that seemed mysterious.
The anatomy of email headers
Email headers appear at the top of every message, though most email clients hide them by default. They're a series of key-value pairs, each on its own line, recording metadata about the message and its journey.
Headers are added in reverse chronological order. The most recent header is at the top; the original headers from the sender are at the bottom. This matters when you're tracing a message's path—you read from bottom to top to follow the chronological journey.
Some headers are set by the sender: From, To, Subject, Date. Others are added by servers along the way: Received headers from each mail server, authentication results, spam scores. Understanding which headers come from where helps you interpret what you're seeing.
Received headers: tracing the path
Every mail server that handles a message adds a Received header. These create a breadcrumb trail showing exactly how the message traveled from sender to recipient.
A typical Received header includes the server that received the message, the server it received it from, the protocol used, and a timestamp. Reading these from bottom to top shows you the complete journey.
This is invaluable for debugging. If a message is delayed, Received headers show you where it got stuck. If it's being rejected, you can see which server rejected it. If it's being modified in transit, you can identify which server made changes.
Watch for suspicious patterns. A message claiming to be from a major corporation but with Received headers showing it originated from a residential IP address is almost certainly fraudulent. Legitimate corporate email doesn't come from someone's home internet connection.
Authentication-Results: the verdict
The Authentication-Results header is where receiving servers record the outcome of authentication checks. This single header tells you whether SPF, DKIM, and DMARC passed or failed, and often includes details about why.
A typical Authentication-Results header might show SPF passing with the IP address that was checked, DKIM passing with the domain that signed the message, and DMARC passing with the policy that was applied. Or it might show failures, with reason codes explaining what went wrong.
When debugging deliverability, this is often the first header to check. If authentication is failing, the reason is usually right here. "SPF softfail" tells you your SPF record isn't quite right. "DKIM signature verification failed" suggests the message was modified in transit or the signature is malformed.
Different receiving servers format this header slightly differently, but the information is similar. Gmail, Microsoft, Yahoo—they all record authentication results, just with minor variations in syntax.
DKIM-Signature: the cryptographic proof
The DKIM-Signature header contains the cryptographic signature that proves a message hasn't been tampered with since it left the signing server. It's complex-looking but follows a consistent structure.
The header specifies which algorithm was used, which domain signed the message, which selector to use for the public key lookup, which headers are covered by the signature, a hash of the body, and the signature itself.
For debugging, the most useful parts are the domain (d=) and selector (s=). These tell you where to look up the public key. If DKIM is failing, you can manually check whether the DNS record exists and contains a valid key.
The headers covered by the signature (h=) matter too. If a header listed there was modified in transit, the signature breaks. Common culprits include Subject lines modified by mailing lists or From headers rewritten by forwarding services.
X-Spam headers: the reputation signals
Many mail servers add headers indicating their spam assessment. These aren't standardized—different servers use different header names and formats—but they're incredibly useful for understanding why messages are being filtered.
SpamAssassin, one of the most common spam filters, adds X-Spam-Status and X-Spam-Score headers. The status shows whether the message was classified as spam, and the score shows the numerical rating. Higher scores mean more spam-like.
X-Spam-Flag is a simple yes/no indicator. X-Spam-Report often contains a detailed breakdown of which rules triggered and how many points each contributed. This breakdown is gold for debugging—it tells you exactly what the filter didn't like.
If you're seeing spam classification problems, look for these headers. They often reveal specific issues: "MISSING_DATE" means you forgot the Date header, "HTML_IMAGE_ONLY" means your message is just images with no text, "RCVD_IN_BRBL" means your sending IP is on a blacklist.
List-Unsubscribe: the compliance header
The List-Unsubscribe header isn't about security in the traditional sense, but it's crucial for deliverability and compliance. It tells email clients how recipients can unsubscribe from your messages.
Modern email clients—Gmail, Apple Mail, Outlook—display an unsubscribe link prominently when this header is present. This is good for recipients and good for you: easy unsubscription means fewer spam complaints, which means better deliverability.
The header can contain a mailto link, an HTTPS URL, or both. Best practice is to include both, giving email clients options. The newer List-Unsubscribe-Post header enables one-click unsubscription without requiring the user to visit a webpage or send an email.
For marketing and bulk email, this header is essentially required. Gmail and other providers penalize messages without it. For transactional email, it's less critical but still good practice for any recurring notifications.
Message-ID: the unique identifier
Every email should have a unique Message-ID header. This identifier lets mail systems track messages, detect duplicates, and thread conversations correctly.
A proper Message-ID looks like a random string followed by @ and a domain name. The domain should be one you control—using your sending domain is standard practice. The random part should be truly unique; UUIDs work well.
Missing or malformed Message-IDs cause problems. Some spam filters flag messages without them. Threading breaks in email clients. Duplicate detection fails, potentially causing the same message to be delivered multiple times.
If you're building email sending systems, generate proper Message-IDs. It's a small detail that prevents annoying problems down the line.
Reply-To vs From: the response routing
The From header shows who sent the message. The Reply-To header, when present, tells email clients where to send replies. These can be different, and understanding when to use Reply-To matters.
A common pattern: marketing emails come From [email protected] but have Reply-To set to [email protected]. This lets you send from a dedicated marketing address while routing responses to your support team.
Be careful with Reply-To. Some spam filters view mismatched From and Reply-To addresses with suspicion, especially if the domains are different. It's a technique used by phishers to make fraudulent emails look legitimate while capturing responses.
For transactional email, keeping From and Reply-To the same (or omitting Reply-To entirely) is usually best. For marketing email, using Reply-To to route responses to a monitored inbox makes sense.
Reading headers in practice
When you're debugging an email problem, here's a systematic approach to reading headers.
Start with Authentication-Results. Did SPF, DKIM, and DMARC pass? If not, you've likely found your problem. The details in this header usually explain what went wrong.
Next, check the Received headers. Trace the message path from bottom to top. Look for unexpected servers, long delays between hops, or servers that might have modified the message.
Look for spam-related headers. X-Spam-Status, X-Spam-Score, X-Spam-Flag—any of these might reveal why a message was filtered. The detailed reports often point to specific fixable issues.
Finally, check the basics. Is there a valid Message-ID? Is the Date header present and reasonable? Is From set correctly? Missing or malformed basic headers trigger spam filters.
Frequently asked questions
How do I view email headers?
In Gmail, open the message and click the three dots menu, then 'Show original'. In Outlook, open the message, click File, then Properties. Most email clients have a similar 'view source' or 'show headers' option.
Can email headers be forged?
Headers set by the sender (From, Subject, etc.) can be forged. Headers added by receiving servers (Received, Authentication-Results) are harder to forge because they're added after the message arrives. This is why authentication results from the receiving server are trustworthy.
Why do I see multiple Authentication-Results headers?
Each server that performs authentication checks may add its own header. You might see one from your email provider's incoming server and another from an internal spam filter. The most relevant one is usually from the final receiving server.
What's the difference between Return-Path and From?
From is the address displayed to recipients. Return-Path (also called envelope sender) is where bounces are sent. They're often the same but can differ. SPF checks the Return-Path domain, not the From domain—this is why DMARC exists to align them.