22 March 2026 · 14 min read
A message leaves your domain, passes SPF and DKIM cleanly, and would sail through DMARC at p=reject. Then it hits a mailing list, or an account that auto-forwards to a different mailbox, or a security gateway that rewrites the body to add a banner. The forwarder changes the envelope sender or touches a signed header, and by the time the message reaches its final destination the SPF check is for the forwarder's IP, the DKIM signature no longer verifies, and DMARC fails. The receiver, following your p=reject policy to the letter, rejects a message you legitimately sent.
This is the forwarding problem, and it is the single biggest reason organisations hesitate to move to enforcement. ARC, the Authenticated Received Chain, defined in RFC 8617 (published July 2019 as Experimental), is the standard built specifically to address it. ARC does not replace SPF, DKIM or DMARC, and it does not change a single thing about how you publish your records. It is a mechanism that lets an honest intermediary vouch for what the authentication results looked like before it touched the message, in a way the next hop can cryptographically verify and choose to trust.
This article walks through RFC 8617 in detail: the three header fields ARC defines, how an intermediary seals a message, how the chain validation works hop by hop, and crucially what a final receiver does (and does not) do with an ARC result after forwarding. It is written for people who already understand DMARC alignment and want to know exactly what ARC adds. If you need the alignment concept first, DMARC alignment explained covers it; here we assume it.
Why DMARC breaks on forwarding in the first place
To see what ARC fixes, you have to be precise about what each authentication method binds to.
- SPF authorises an IP address to send for the Return-Path (envelope
MAIL FROM) domain. A forwarder typically resends from its own IP and often rewrites the envelope sender, so SPF either fails for your domain or passes for the forwarder's domain. Either way it does not align with yourFrom:. - DKIM signs a chosen set of headers plus the body and binds them to a
d=domain. As long as the signed content is untouched, a DKIM signature survives forwarding: the signature does not care which IP relays the message. But the moment an intermediary modifies a signed header, adds a footer to the body, or rewraps MIME parts, the hash no longer matches and the signature breaks. - DMARC passes if SPF or DKIM passes and aligns with the
From:domain. After a typical forwarding hop, SPF has stopped aligning and DKIM has broken, so neither leg holds and DMARC fails.
The result is a structurally honest message that fails authentication through no fault of the original sender. Classic triggers:
- Mailing lists (Mailman, Google Groups, listservs) that prepend
[list-name]to the Subject, add an unsubscribe footer to the body, and resend from the list's own infrastructure. Subject and body are usually both DKIM-signed, so the signature breaks. - Account-level forwarding ("send a copy of everything to my other address"), where the forwarding server adds
Receivedheaders and sometimes resigns or rewrites parts. - Security gateways that insert a
[EXTERNAL]banner or a "scanned safe" footer into the body.
For a deeper look at the forwarding failure mode on its own, see DMARC and forwarding and DKIM alignment and forwarding. The point for ARC is this: at the moment your message arrived at the intermediary, it very likely passed DMARC. ARC is a way for that intermediary to record that fact and pass it forward.
The core idea: preserving the original authentication verdict
ARC's premise is simple to state. Each intermediary that handles a message can, before it forwards it on, capture the authentication results it observed and attach them to the message in a tamper-evident way. The next intermediary does the same, building an ordered chain. The final receiver can then look back along the chain and reason: "DMARC fails for me right now, but a chain of intermediaries I trust attests that the message passed DMARC when it first entered the path, and the chain has not been broken since."
ARC does not assert that the original message was good. It asserts something narrower and more honest: here is what authentication looked like at each hop, and here is cryptographic proof that these statements were made by the parties claiming to make them and have not been altered since. Whether to act on that attestation is entirely the receiver's decision, and it hinges on whether the receiver trusts the intermediaries that signed the chain. ARC provides verifiable provenance, not trust. Trust is a local policy choice layered on top.
Two consequences fall out of this immediately:
- ARC is only useful between parties where the receiver has some basis to trust the sealer. A chain sealed by a reputable, well-behaved forwarder is worth acting on; a chain sealed by an unknown host is just data.
- ARC is built on the same cryptographic machinery as DKIM (the DomainKeys Identified Mail signing model), which is why the records, the key publication, and the canonicalisation all feel familiar if you know DKIM.
The three ARC header fields
RFC 8617 defines exactly three new header fields. Every intermediary that participates adds one of each, all tagged with the same instance number (i=), which is what orders the chain. The instance number starts at 1 for the first intermediary and increments by one at each subsequent hop, up to a maximum of 50.
ARC-Authentication-Results (AAR)
The ARC-Authentication-Results header is, in content, almost identical to the ordinary Authentication-Results header defined by RFC 8601, with one addition: it carries an i= instance tag. It records the SPF, DKIM and DMARC results that this intermediary observed when the message arrived at it.
ARC-Authentication-Results: i=1; mx.listserver.example;
spf=pass smtp.mailfrom=you@yourdomain.com;
dkim=pass header.d=yourdomain.com;
dmarc=pass header.from=yourdomain.com
This is the substantive payload of an ARC hop. It is the intermediary saying, on the record, "when this message reached me, it passed SPF for your domain, carried a valid DKIM signature for d=yourdomain.com, and passed DMARC aligned to your From." The AAR is a frozen snapshot of the verdict at that hop, taken before the intermediary made any modifications that might break it downstream.
ARC-Message-Signature (AMS)
The ARC-Message-Signature is a DKIM-style signature over the message, taken by the intermediary at the moment it handles the message. Syntactically it looks like a DKIM-Signature header with an added i= instance tag.
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed;
d=listserver.example; s=arc2024; t=1718900000;
bh=2jUSOH9NhtVG...base64...;
h=from:to:subject:date:message-id:mime-version:content-type;
b=Xq9kP...base64signature...
The critical difference from a normal DKIM signature: the AMS signs the message as it leaves this intermediary, including the modifications the intermediary made. So a mailing list that rewrote the Subject and appended a footer signs the modified version with its AMS. This is exactly what makes ARC work across a body-mangling list. The list cannot save the original sender's DKIM signature (it broke it), but it can attest with its own fresh signature that the message it is forwarding is the one whose authentication it described in the AAR.
The AMS covers the message body and headers, but by convention and per the spec it does not include the ARC-Seal headers in its scope. It signs the message content, not the seal layer.
ARC-Seal (AS)
The ARC-Seal is what binds the whole chain together and makes it tamper-evident across multiple hops. It is also a DKIM-style signature, but its scope is different and very deliberate. The AS at instance i=N signs:
- all the
ARC-Authentication-Results,ARC-Message-SignatureandARC-Sealheaders from instances1throughN-1, and - the
ARC-Authentication-ResultsandARC-Message-Signatureof its own instanceN,
but it does not sign the message body at all. The seal's job is to protect the chain, not the content.
ARC-Seal: i=1; a=rsa-sha256; t=1718900000; cv=none;
d=listserver.example; s=arc2024;
b=hHdL2...base64sealsignature...
Note the cv= tag, the chain validation status. This appears only on the ARC-Seal. It records what the sealer concluded about the chain as received:
cv=nonemeans there were no prior ARC headers; this is the first hop sealing a fresh chain.cv=passmeans the existing chain validated successfully before this intermediary added its own seal.cv=failmeans the existing chain was present but did not validate.
The very first seal in a chain must carry cv=none. Every subsequent seal carries cv=pass or cv=fail reflecting what the sealer found. Once any hop sets cv=fail, the chain is permanently failed: a broken chain cannot be repaired by a later, honest intermediary. This one-way property is central to ARC's integrity model and we return to it below.
Sealing: what an intermediary actually does
Putting the three headers together, here is the precise sequence an ARC-aware intermediary performs when it receives and forwards a message. Suppose it is the first intermediary, so it will write instance i=1.
- Evaluate authentication on arrival. Run SPF, DKIM and DMARC against the message exactly as received. Record the outcome.
- Validate any existing chain. Look for prior ARC sets. If none exist, the chain validation status is
none. If they exist, validate them (described in the next section) and computecv=passorcv=fail. - Write the ARC-Authentication-Results header for
i=1, recording the SPF/DKIM/DMARC results from step 1. - Apply its own modifications to the message (rewrite Subject, append footer, add banner, whatever this intermediary does).
- Compute and add the ARC-Message-Signature for
i=1over the now-modified message. - Compute and add the ARC-Seal for
i=1, signing the AAR and AMS of this instance plus all prior ARC headers (none, in the first-hop case), and stamping thecv=value from step 2. - Forward the message.
The ordering matters. The AAR is recorded against the message as received (step 1), but the AMS signs the message as modified (steps 4 to 5). That gap, the verdict captured before modification but the signature taken after, is the whole trick. It lets the receiver reconstruct: "this intermediary saw a passing message, then changed it like so, and here is its signature over the changed version."
Each header is published and verified using DKIM-style DNS key records. The selector and domain in the AMS and AS (s=arc2024; d=listserver.example above) point at a TXT record holding the public key, exactly as DKIM does:
arc2024._domainkey.listserver.example. IN TXT
"v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GN...base64pubkey..."
If you understand how DKIM keys are published and selected, you already understand ARC key publication; the mechanics are the same. For a refresher on selectors see DKIM selectors explained, and you can inspect any DKIM-style key with the DKIM checker.
Chain validation: how the next hop checks the work
When an intermediary or a final receiver wants to validate an inbound ARC chain, RFC 8617 lays out a specific algorithm. The chain is the set of ARC sets numbered 1..N, where each set is one AAR, one AMS and one AS sharing an instance number. Validation proceeds roughly as follows:
- Find the highest instance number,
N. That set's ARC-Seal is the most recent. Confirm the instances are a contiguous run1, 2, ..., Nwith no gaps and no duplicates. Any structural anomaly (a missing instance, a duplicate, more than one of a header at the same instance) fails the chain. - Check the seal chaining rule on
cv. The seal ati=1must becv=none. Every seal ati>1must becv=pass(acv=failanywhere means a prior hop already declared the chain dead, and it stays dead). - Verify the most recent ARC-Message-Signature (
i=N). This confirms the message body and headers, as they currently stand, match what the most recent intermediary signed. If the AMS ati=Nfails, the chain fails. - Verify every ARC-Seal, from
i=1toi=N. Each seal signs all the ARC headers up to and including its own instance, so verifying them in order proves no ARC header in the chain has been altered or reordered since it was sealed.
If all of that holds, the chain is cv=pass: structurally sound, every seal intact, and the latest message signature valid. If any step fails, the chain is cv=fail.
A subtle but important point: only the most recent AMS is verified for content. The earlier AMS headers are not re-verified against the body (they could not be; later intermediaries changed the body). They are still protected by the seals, so their text cannot be tampered with, but the body assertion that matters for "is this the message that was forwarded" is the latest one. The earlier AARs remain meaningful because the seals guarantee they have not been edited, and because a downstream party that trusts those intermediaries can read the verdict each one recorded.
This is why a single broken hop poisons everything after it. If intermediary 2 produces an invalid seal, then when intermediary 3 validates the chain it computes cv=fail, stamps cv=fail into its own seal, and the failure propagates. There is no mechanism to "skip" a bad hop and trust the rest. The chain is only as trustworthy as its weakest seal.
What a final receiver does with ARC after forwarding
Here is the part that is most often misunderstood, so let us be exact about it. ARC does not override DMARC. A receiver that honours your p=reject policy still runs DMARC normally and still gets a DMARC failure on a forwarded message. ARC enters only as a local policy override input: a reason the receiver might choose, of its own accord, not to apply the failing DMARC disposition.
The decision flow at a DMARC-aware final receiver looks like this:
- Run SPF, DKIM and DMARC as usual. Suppose DMARC fails because of forwarding.
- Before applying the published policy (
quarantineorreject), validate the inbound ARC chain. - If the chain is
cv=pass, look at the authentication results recorded in the earliest AAR (the verdict at the message's entry into the path). If that AAR shows the message passed DMARC when it first arrived, and the receiver trusts the sealers in the chain, the receiver may choose to deliver the message anyway, overriding the localreject. - If the chain is
cv=fail, or the receiver does not trust the sealers, or the original AAR did not show a DMARC pass, ARC provides no basis for an override and the published DMARC policy applies unchanged.
Three things deserve emphasis here.
It is permissive, never punitive. A passing ARC chain can only ever rescue a message that DMARC would otherwise have failed. ARC cannot cause a message to be rejected that DMARC would have passed. It is a one-directional safety valve for forwarding, not an additional gate.
It is discretionary, never mandatory. RFC 8617 does not require any receiver to honour ARC, and it deliberately does not define a trust model. Whether to act on a chain, and which sealers to trust, is left entirely to the receiver. In practice the large mailbox providers (Google, Microsoft, Yahoo) generate and consume ARC, and they weigh it together with reputation and other signals rather than treating a single cv=pass as an automatic delivery ticket. A chain sealed by a sender with poor reputation buys little.
The original sender does nothing and configures nothing. This is the crucial operational fact. You, as the domain owner publishing DMARC, do not opt in to ARC, do not publish an ARC record, and cannot make receivers honour it. ARC is implemented and trusted by the intermediaries and receivers, not by you. There is no arc= tag in your DMARC record. The best you can do is keep your own authentication clean so that the AAR at the first honest hop records a genuine dmarc=pass, which is the input ARC needs to be worth anything downstream.
How ARC shows up in your DMARC reports
Because ARC operates between mailbox providers, the place a domain owner actually observes it is in DMARC aggregate (RUA) reports. When a forwarded message fails DMARC at the final receiver but the receiver applied an ARC-based local override, the report typically records the DMARC result as fail together with a policy override reason of local_policy and a comment naming ARC. In the raw aggregate XML this looks like a <policy_evaluated> block whose <reason> has <type>local_policy</type> and a comment such as arc=pass.
Seeing that pattern is the signal that forwarding is happening and that a downstream receiver chose to trust the chain rather than enforce your reject. It tells you two useful things: the failures are forwarding-related rather than a genuine spoofing or misconfiguration problem, and at least some receivers are protecting that legitimate flow for you. Distinguishing forwarding noise from real alignment failures is exactly what report analysis is for; the DMARC report analyzer groups failures by source so you can tell a forwarder applying ARC apart from an unauthenticated source that genuinely needs fixing, and reading your first DMARC report walks through the override reasons in detail.
What ARC does not do, and where its limits are
ARC is narrow by design, and it is worth being honest about the edges.
- ARC is not a substitute for fixing alignment. If your legitimate mail fails DMARC for a source you control, the answer is to align SPF or DKIM properly, not to hope a forwarder seals it. ARC only helps where modification by a trusted intermediary is the cause. Direct-from-source failures still need SPF and DKIM put right.
- ARC does not establish trust; it only preserves provenance. A chain can be perfectly valid (
cv=pass) and still be ignored, because the receiver does not trust the entity that sealed it. Validity and trustworthiness are separate questions. - ARC cannot repair a broken chain. Once
cv=failis set, no honest downstream hop can undo it. A single misbehaving or buggy intermediary in the path can poison the chain for everyone after it. - ARC remains Experimental. RFC 8617 is on the Experimental track, not a full Internet Standard. Adoption among the largest providers is real and meaningful, but it is not universal, and you cannot assume any given receiver honours it.
- ARC does not change what you publish. No new DNS record on your side, no DMARC tag, no SPF or DKIM change. If you went looking for "how do I enable ARC for my domain", the honest answer is that there is nothing to enable as a sender.
The practical takeaway
ARC, as specified in RFC 8617, is a quietly elegant fix for one specific and stubborn problem: legitimate mail that fails DMARC because a trusted intermediary modified it in transit. It works by having each honest hop record the authentication verdict it saw (the ARC-Authentication-Results header), sign the message as it forwards it (the ARC-Message-Signature), and bind the whole sequence into a tamper-evident chain (the ARC-Seal, carrying the cv= chain status). A final receiver validates that chain, and if it both passes and is sealed by parties the receiver trusts, the receiver may choose to deliver a message its own DMARC check would have rejected. Permissive, discretionary, and entirely on the receiver's and intermediaries' side of the fence.
For you as a domain owner, the operational lesson is short. There is nothing to configure for ARC, and there never will be. What you control is the verdict at the first honest hop: keep SPF, DKIM and DMARC alignment clean so that the earliest ARC-Authentication-Results records a real dmarc=pass, which is the only thing that makes the chain worth honouring downstream. Then watch your aggregate reports for local_policy overrides citing ARC, so you can tell forwarding noise apart from sources that genuinely need attention.
The way to do both is to be at enforcement with healthy authentication and to actually read the reports. Confirm your published policy and alignment with the DMARC checker, keep an eye on forwarding-driven failures through the DMARC report analyzer, and if you would rather have the whole path from p=none to p=reject handled for you, with continuous monitoring and change alerts that flag exactly this kind of behaviour, our done-for-you DMARC service and ongoing monitoring do it without risking an email outage.