Introduction
Every deliverability ticket eventually lands on the same artefact: the raw headers of the failing message. The client forwards a bounce; the analyst opens the original; somewhere in the next two minutes, the verdict comes out. That two minutes is the analyst's most valuable skill. With the headers in hand, the root cause is almost always knowable; without confidence reading them, every ticket becomes a research project.
This article is the working-analyst companion to the DMARC for MSPs pillar and the conceptual reference for the Email Header Analyzer tool. It walks the structure of a header block from the bottom up, explains what each section is telling you, and shares the mental model experienced analysts use to triage fast.
Why this topic matters
Reading headers fluently is the single highest-leverage skill in a DMARC practice. Every other diagnostic step — checking the SPF record, validating the DKIM key, querying DMARC at the apex — is downstream of the question "what did the receiver actually see when this message arrived." The headers answer that question. Without them, you're guessing; with them, you're working from evidence.
The compounding effect across a team matters too. An analyst who reads headers in two minutes can close three tickets while a less-fluent colleague is still puzzling through one. Multiply that across a portfolio of fifty clients and a team of six, and the practice's effective capacity changes by a factor of two or three. Investing in this skill at the team level is a force multiplier.
Headers are stored in reverse order
The first thing to internalize: email headers are prepended at every hop. The receiving server adds its Received: line at the top; the next-most-recent hop is one line below; the originating server's Received: is at the bottom. Reading top-down is reading time backwards.
Almost every misreading of an email header starts here. An analyst sees a familiar hostname at the top and assumes it's the sender; in fact it's the analyst's own receiving server. The first hop chronologically — the line at the bottom of the Received block — is where the message actually originated.
The Email Header Analyzer tool presents the chain top-to-bottom in chronological order so this trap is removed from the workflow. But when you're reading raw headers in a text editor (which you will, eventually), keep the reversal in mind every time.
The skeleton of a header block
Every well-formed email header block contains six structural pieces:
The Received chain. One Received: line per server that handled the message. The chain tells you the message's path from origin to inbox. Each line carries the timestamp of when that hop processed the message, so the chain doubles as a timeline.
Authentication-Results. Added by the receiving server. Reports the SPF, DKIM, DMARC, ARC, and optionally BIMI verdicts the receiver computed. This is the line your DMARC aggregate reports are summarizing.
The identity headers. From:, Return-Path:, Reply-To:, To:, Cc:, Bcc: (rarely visible to recipients). These define who the message claims to be from, who handles bounces, and where replies should go.
The signing headers. DKIM-Signature: (often multiple, one per signer), ARC-Seal:, ARC-Message-Signature:, ARC-Authentication-Results:. These are the cryptographic artefacts that let receivers verify the message hasn't been tampered with.
The metadata headers. Message-ID:, Date:, Subject:, MIME-Version:, Content-Type:. The plumbing of the message itself.
The platform-specific headers. X-Mailer:, X-Originating-IP:, List-Unsubscribe:, etc. Vary by platform. Mostly informational but occasionally diagnostic.
Knowing the skeleton lets you skim a 4KB header block for the parts that matter instead of reading every line.
Reading the Received chain bottom-up
The Received chain is the spine of header analysis. Walk it from the bottom (the origin) to the top (your inbox).
Each Received: line follows a roughly standard shape:
“ Received: from <sender-host> ([sender-IP]) by <receiver-host> with <protocol> for <recipient>; <timestamp> “
The from clause identifies who the previous hop says they are. The by clause identifies who recorded this hop (the receiver of this leg). The with clause is the protocol used (usually ESMTPS for modern TLS-encrypted SMTP). The timestamp is when this hop happened.
The patterns that matter:
The bottom-most hop is the origin. This is the IP that first injected the message into the mail system. Cross-reference this with the claimed SPF policy — the IP should be authorized by the sender's SPF record.
Gaps between hops are timing data. Long gaps (>30 seconds) suggest greylisting (a deliberate first-time-sender delay) or queue congestion at one of the hops. Not necessarily a problem but worth flagging for time-sensitive transactional mail.
Negative gaps are forgery. Timestamps that go backwards in time can't happen in a legitimate chain. Found in spoofed messages where the attacker forged Received lines below their actual entry point and didn't get the clock arithmetic right.
Unfamiliar hostnames matter. If you expect a message from Acme Corp via M365 and you see a hop through relay-12.unknown-provider.example, that's a lead. Either Acme Corp is now using a third-party relay you don't know about, or the message didn't originate where it claims.
Reverse-DNS mismatch is a soft tell. Legitimate mail servers usually have matching forward and reverse DNS. When the from clause shows a hostname that doesn't match the reverse-DNS of the claimed IP, treat as suspicious but not conclusive.
Authentication-Results: the bottom line
The single most important header in the whole block is Authentication-Results:. It's added by the receiving server and reports the verdicts of every authentication check performed.
A typical line looks like:
“ Authentication-Results: mx.your-domain.com; spf=pass smtp.mailfrom=acme-corp.com; dkim=pass header.d=acme-corp.com; dmarc=pass action=none “
This is the receiver telling you: SPF passed against the envelope-sender domain, DKIM verified cryptographically with d=acme-corp.com, DMARC passed because at least one of SPF or DKIM aligned with the From: domain.
When there are multiple Authentication-Results: headers, trust the topmost one — that's the one added by your own final receiver. The lines below it were added by upstream hops and may have been added by the attacker if the message went through hostile infrastructure.
The vocabulary the receiver uses:
- pass — authentication succeeded
- fail — authentication explicitly failed
- softfail — SPF-specific, the IP isn't authorized but the policy is soft (~all)
- neutral — SPF-specific, policy is ?all (explicit "no opinion")
- none — no record was found to evaluate
- temperror — transient error, usually DNS timeout
- permerror — permanent error, usually malformed record
Each verdict has a different next-step. The Email Header Analyzer tool maps each one to a recommended action; the discipline of always knowing what action a verdict implies is what separates analysts who close tickets fast from analysts who escalate.
DMARC alignment is where it gets subtle
The most common confusion: SPF passes, DKIM passes, DMARC fails. This pattern surprises analysts the first time they see it, and the source of confusion is alignment.
DMARC doesn't pass just because SPF or DKIM passes. It requires at least one of them to align with the From: header domain.
SPF alignment. The SPF check authenticates the Return-Path (envelope-sender) domain. DMARC requires the Return-Path domain to match the From: domain (or share an organizational domain, with default relaxed alignment). When you relay through a third party that bounces to their own domain, the Return-Path becomes the relay's domain and SPF alignment breaks even though SPF itself passes.
DKIM alignment. The DKIM signature is authenticated against the d= tag in the signature. DMARC requires d= to match (or align organizationally with) the From: domain. When a sender's DKIM is configured for a different domain than From: (common after a brand acquisition where the email platform wasn't reconfigured), DKIM alignment fails.
The shape of a "SPF pass, DKIM pass, DMARC fail" finding is usually: SPF authenticated mailer.relay-provider.com; DKIM signed d=brand-x.com; From: showed [email protected]. Neither authenticated identity matches From:, so DMARC fails despite both individual checks passing.
The DMARC alignment article walks the rule in depth. For practical triage: when you see DMARC fail with SPF and DKIM passing, the next step is always to compare From: domain to Return-Path domain and to every DKIM-Signature's d= tag.
DKIM signatures: reading the tags
Each DKIM-Signature: header is a string of tag=value pairs separated by semicolons. The ones you actually need:
- v=1 — DKIM version. Always 1; if it's anything else, the signature is invalid.
- a= — signing algorithm. Usually
rsa-sha256.rsa-sha1is deprecated. - d= — signing domain. Match this against From: domain for alignment.
- s= — selector. The DNS lookup is
s._domainkey.d. - h= — list of headers covered by the signature. If From: isn't in h=, the message body is signed but the visible sender isn't authenticated.
- bh= — body hash. The hash of the message body. Changes if any relay modified the body.
- b= — signature itself. Verified against the public key at
s._domainkey.d. - l= — optional body-length limit. If present, only the first N bytes of the body are signed; anything appended (footer, advertising) doesn't break the signature.
The most common DKIM finding in real triage: the signature is present, the d= and s= look correct, but the receiver reports dkim=fail. This almost always means the body was modified in transit (a mailing list added a footer, a security gateway rewrote URLs) and the body hash no longer matches. The fix is rarely on the sender side; it's recognizing that the modifying middlebox needs to be replaced or moved into the ARC-aware part of the chain.
ARC: the chain across forwarders
ARC-* headers solve a specific problem: messages that traverse mailing lists or forwarders get modified in ways that break the original DKIM signature, and receivers downstream lose the ability to trust the original authentication verdict.
ARC adds a sealed authentication chain. Each hop that participates in ARC adds three headers — ARC-Authentication-Results:, ARC-Message-Signature:, ARC-Seal: — that record what the previous hop's authentication state was. The chain is cryptographically sealed so downstream receivers can verify it.
The single tag that matters when reading ARC is cv= on the most recent ARC-Seal:. It reports:
- cv=pass — the chain is intact from the originating signer through every intermediate hop. Receivers can trust the chain.
- cv=fail — the chain is broken. Some hop didn't seal properly. Receivers will fall back to evaluating the message as if it came directly from the last hop.
- cv=none — no chain exists. The message hasn't been ARC-sealed at all.
When you see DMARC fail on a message that obviously came through a mailing list, check the ARC chain — if it's intact (cv=pass), the receiver may still be applying the original DMARC verdict and that's the source of the problem. The fix in that case is at the list server, not at the original sender.
A six-step triage runbook
The mental sequence experienced analysts run through, every time:
Step 1: Read the topmost Authentication-Results. Three pass verdicts means the message authenticated; any fail tells you what to investigate next.
Step 2: Compare From: to Return-Path:. If they differ, alignment depends on DKIM. Note both.
Step 3: Walk the Received chain bottom-to-top. Look for the originating hop, suspicious infrastructure, impossible timestamps, and unusual hop counts.
Step 4: Inspect each DKIM-Signature. Check d= against From: domain. Confirm h= includes From:. If multiple signatures, prefer the one whose d= aligns with From:.
Step 5: Check ARC if present. cv=pass means the chain survived forwarding; cv=fail means it broke somewhere.
Step 6: Form the verdict and write the ticket. Document the verdict (legitimate / spoofed / broken-but-legitimate) and the specific failing check.
The Email Header Analyzer tool compresses this six-step flow into a single click. But the mental sequence still matters — the tool surfaces the data; the analyst's understanding turns the data into a verdict.
Common patterns in real headers
Three patterns that show up constantly in MSP triage:
The forwarder pattern. From: a corporate domain. Return-Path: a user's personal Gmail. SPF passes (Gmail is in its own SPF record). DKIM signed by Gmail. DMARC fails because neither aligns with From:. Verdict: legitimate, but a user has set up an email forwarder that breaks DMARC. Fix: configure the forwarder to send-as the original domain, or work with the recipient to add ARC-aware processing.
The third-party platform pattern. From: a brand domain. Return-Path: bounce.sendgrid.net (or similar). SPF passes against SendGrid's SPF. DKIM signed by SendGrid with d=brand-domain. DMARC passes because DKIM aligns. Verdict: legitimate, platform is correctly configured for DMARC alignment. Common shape for transactional mail that's working as designed.
The spoof pattern. From: a recognizable brand. Return-Path: an unrelated domain (often newly-registered). No DKIM signature, or DKIM signed for an unrelated d=. SPF either fails or passes against the unrelated domain. DMARC fails. Verdict: spoofed, the From: domain's DMARC policy is doing its job. Fix: confirm DMARC is at p=reject so receivers are blocking; report the attempt as a phishing artefact if useful.
Recognizing these three patterns covers maybe 60% of the deliverability tickets a working MSP DMARC practice sees. The remaining 40% reward the same six-step discipline.
Tools mentioned
- Email Header Analyzer — paste raw headers, get the parsed Received chain, auth verdicts, alignment, ARC chain status, DKIM signature inspection
- DMARC Validator — check the published DMARC policy
- DNS Lookup — verify SPF, DKIM, DMARC records across resolvers
- DMARC Record Generator — compose a compliant DMARC TXT record
Next steps
If you're building header-reading fluency on a new team, run the six-step runbook on a different real header block every morning for two weeks. After ten or fifteen reps, the sequence becomes muscle memory and the per-ticket time drops below two minutes. After thirty or forty reps, you'll start recognizing the three common patterns by shape alone, and most tickets become verdict-then-write-up rather than investigation.
Author: DMARC AI editorial team Last updated: June 2026