How to read ARC headers (cv=none/pass/fail, i=, d=, s=) to debug forwarding issues

dmarctutorialspfdkimarc

If ARC headers still look like random noise during an incident, that is normal.

Most teams first care about ARC when a forwarded message is obviously legitimate, but DMARC still fails somewhere downstream. At that point, reading cv=, i=, d=, and s= quickly is what separates a five-minute diagnosis from a long guessing session.

This guide is intentionally practical: what each tag means, what a healthy chain looks like, and what to do when the chain is broken.

If ARC is still new, start with What is ARC in email and how does it work?, then come back here.

First, what you should look for in headers

For each ARC instance, you should see exactly one of each:

  1. ARC-Authentication-Results (AAR)
  2. ARC-Message-Signature (AMS)
  3. ARC-Seal (AS)

All three share the same i= value for that instance.

That is the first fast integrity check. If instance i=2 has AAR and AMS but no matching AS, or duplicates, treat that as chain trouble and keep digging.

RFC 8617 defines ARC set structure and validation logic in detail: https://www.rfc-editor.org/rfc/rfc8617.

What i= tells you (chain order)

i= is the ARC instance number.

  • i=1 is the first ARC-enabled hop.
  • i=2 is the next hop that sealed the message.
  • and so on, up to the protocol maximum.

In valid chains, instance values are continuous (1,2,3,...N) with no gaps.

If you see i=1 and i=3 but no i=2, validation should fail. That is not a subtle condition; RFC 8617 calls it out directly as invalid chain structure.

What cv= tells you (chain status at that hop)

cv= appears in ARC-Seal and carries chain validation status:

  • cv=none: no prior ARC chain existed when this sealer handled the message (typically first ARC set, i=1)
  • cv=pass: prior ARC chain validated successfully
  • cv=fail: prior ARC chain failed validation

One important pattern to memorize:

  • first ARC set should normally be i=1; cv=none
  • later ARC sets (i>1) should normally carry cv=pass

If you see i=1; cv=pass, that is a red flag. If you see cv=fail in the highest instance, downstream evaluators should treat the chain as failed.

Google's ARC overview also summarizes the cv meanings for administrators: https://support.google.com/a/answer/13198639.

What d= and s= tell you (who sealed)

d= is the signing domain and s= is the selector used by that signer.

For practical debugging, this pair answers: which system claims responsibility for this ARC set, and where is its public key in DNS?

Example:

ARC-Seal: i=2; cv=pass; a=rsa-sha256; d=forwarder.example.net; s=arc-2026;
 t=1772294400; b=...

That means the DNS key lookup target is:

arc-2026._domainkey.forwarder.example.net

If DNS for that selector/domain is broken or missing, ARC validation for that set will fail.

In receiver policy, d= is also what gets mapped to trust decisions. Microsoft 365 documents this clearly for trusted ARC sealers: the domain you configure must match the d value seen in ARC-Seal/ARC-Message-Signature headers.

Reference: https://learn.microsoft.com/en-us/defender-office-365/email-authentication-arc-configure.

A quick "healthy chain" example

ARC-Authentication-Results: i=1; mx.forwarder.example.net; spf=pass smtp.mailfrom=example.com; dkim=pass header.d=example.com
ARC-Message-Signature: i=1; a=rsa-sha256; d=forwarder.example.net; s=arc-a; ...
ARC-Seal: i=1; cv=none; a=rsa-sha256; d=forwarder.example.net; s=arc-a; ...

ARC-Authentication-Results: i=2; mx.gateway.example.org; dkim=fail header.d=example.com; spf=fail smtp.mailfrom=example.com
ARC-Message-Signature: i=2; a=rsa-sha256; d=gateway.example.org; s=arc-b; ...
ARC-Seal: i=2; cv=pass; a=rsa-sha256; d=gateway.example.org; s=arc-b; ...

How to read this fast:

  • instance sequence is continuous (1, 2)
  • first set starts with cv=none
  • second set has cv=pass, so previous chain validated
  • two distinct sealing domains are visible via d=

Even though direct SPF/DKIM later failed at i=2, preserved history can still be used as additional context by the receiver's local policy.

Common failure patterns (and what they usually mean)

  • Missing ARC header in a set (i= mismatch between AAR/AMS/AS) -> malformed chain
  • Instance gaps (i=1, i=3) -> invalid chain structure
  • Latest ARC-Seal has cv=fail -> chain already failed upstream
  • d= looks unfamiliar or unexpected for your flow -> likely untrusted intermediary, misrouting, or spoof attempt
  • Selector in s= does not resolve in DNS -> signature cannot validate

When forwarding is involved, this is why providers ask intermediaries to add ARC and preserve traceability. Google and Yahoo both call this out in sender guidance:

Incident workflow that works in practice

Use this order during real incidents:

  1. Collect all ARC-* headers and sort mentally by i=.
  2. Confirm each instance has exactly one AAR, AMS, and AS.
  3. Check cv progression (none at i=1, then pass for later valid sets).
  4. List each sealing identity from d= + s=.
  5. Validate whether those sealers are expected/trusted in your environment.
  6. Then correlate with current-hop Authentication-Results for SPF/DKIM/DMARC.

That order matters. Teams often jump directly to DMARC action and miss a broken ARC chain one screen above.

If you need a companion walkthrough for Authentication-Results, use DMARC troubleshooting: read Authentication-Results headers and fix alignment failures.

If you are deciding where ARC should be deployed at all, use Should you deploy ARC as a domain owner, a forwarder, or both?.

Bottom line

When you read ARC headers as a sequence instead of isolated lines, most confusion disappears quickly.

i= gives order, cv= tells chain health at each step, and d=/s= tell you who sealed and where to verify keys. That is enough to identify most forwarding-path failures without guesswork.

Previous PostNext Post