SPF, DKIM, DMARC and ARC
ARC explained
How the Authenticated Received Chain records authentication results across intermediaries, how to read ARC-Seal, ARC-Message-Signature and ARC-Authentication-Results, and why a valid chain only matters if the receiver trusts the sealer.
ARC (Authenticated Received Chain, RFC 8617) is a way for a server that forwards or modifies a message, such as a mailing list or a security gateway, to record what authentication looked like when the message reached it, and sign that record. A later receiver that finds SPF and DKIM broken can read the chain and decide whether to believe it. ARC never makes a message pass DMARC by itself. It only gives the final receiver evidence it may use if it trusts whoever added it.
RFC 8617 is an Experimental RFC (2019). Large mailbox providers do add and read ARC headers, but how much weight each gives them is not public.
The problem it addresses
Forwarding breaks SPF because the forwarder's IP is not in the original sender's record. Mailing lists that add a subject tag or footer break DKIM. With both gone, a message from a domain with a strict DMARC policy fails at the final receiver even though it was perfectly legitimate when it left. ARC lets the list say: "when this reached me, DKIM passed for example.com and DMARC passed; here is my signature on that statement."
The three headers
Each intermediary that takes part adds one ARC set: three header fields sharing the same instance number.
ARC-Authentication-Results (AAR), RFC 8617 §4.1.1. A copy of the authentication results that hop saw on arrival, in the same format as Authentication-Results, with an i= tag added:
ARC-Authentication-Results: i=1; lists.example.org;
spf=pass smtp.mailfrom=example.com;
dkim=pass header.d=example.com;
dmarc=pass header.from=example.com
ARC-Message-Signature (AMS), §4.1.2. A DKIM-style signature over the message as it left that hop, including any changes the hop made. The i= tag replaces DKIM's user identifier:
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed;
d=example.org; s=arc-2026; h=from:to:subject:date:message-id;
bh=...; b=...
ARC-Seal (AS), §4.1.3. A signature over the ARC headers themselves, all sets so far in order, which binds the chain together. It carries cv=, the chain status this hop found, and does not cover the body:
ARC-Seal: i=1; a=rsa-sha256; cv=none; d=example.org; s=arc-2026; t=1793001700; b=...
The signing domain in d= is the sealer. That is the name to look at when deciding how much the chain is worth.
Instance numbers: i=
Instances start at 1 and go up by one with each ARC set added; the maximum is 50 (RFC 8617 §4.2.1). A message that went from a sender to a mailing list to a forwarding service to your mailbox might carry i=1 from the list and i=2 from the forwarder. As with Received headers, the newest set is usually at the top, but the numbers, not the position, tell you the order.
Chain validation: cv=
The chain status has three values (RFC 8617 §4.4):
cv=none: there was no chain when this hop received the message. The first set,i=1, must always saynone.cv=pass: there was a chain and it validated. Every set abovei=1must saypassfor the chain to be valid.cv=fail: the chain was broken or invalid. Once a hop records fail, the chain is finished; later hops do not continue it (§5.1, §5.1.3).
The final receiver validates the chain itself (§5.2): checks the structure and numbering, verifies the newest AMS, then verifies every seal. The result appears in its own Authentication-Results as arc=pass, arc=fail or arc=none, sometimes with the sealer noted:
Authentication-Results: mx.example.net;
dkim=fail (body hash did not verify) header.d=example.com;
spf=pass smtp.mailfrom=lists.example.org;
arc=pass (i=1 spf=pass dkim=pass dmarc=pass) smtp.remote-ip=198.51.100.7;
dmarc=fail (p=REJECT dis=NONE) header.from=example.com
The format of the parenthetical varies by provider. That example shows the case ARC was built for. The list's own SPF passed but does not align with example.com, and the list's footer broke the original DKIM signature, so DMARC failed. The policy was reject, and the receiver delivered anyway (dis=NONE), likely because it trusted the list's ARC record. See the result pages for arc=pass, arc=fail and arc=none.
How a receiver uses it
RFC 8617 §7.2.1 allows a DMARC receiver, as a matter of local policy, to accept the results recorded in a valid chain when deciding a message's fate. DMARC itself permits that kind of override: RFC 9989 §5.4 leaves final handling to the receiver and asks it to report such deviations to the domain owner.
The crucial words are local policy. A valid chain only proves that the sealer signed those results; it does not prove the sealer told the truth. RFC 8617 §9.4 tells receivers to treat every sealer with suspicion, since anyone can seal a message, including spammers who seal their own mail with dmarc=pass written inside. In practice, receivers keep lists or reputation for sealers they trust (large mailbox providers, well-known list hosts, security gateways their customers use) and ignore the rest.
So for a reader:
- arc=pass from a sealer you recognize, together with a DMARC fail, usually means legitimate mail that was modified in transit. The AAR at
i=1tells you what authentication looked like before the change. - arc=pass from an unknown sealer means very little. Weigh the message on the other evidence.
- arc=fail is treated the same as no chain at all (§5.2). It is not a sign of forgery on its own; many intermediaries modify mail without sealing.
- arc=none is normal for direct mail that never passed through an intermediary.
Reading it yourself
Paste the headers into the analyser. It lists each ARC set by instance, shows the sealer domain, cv= and recorded results for each, so you can compare "authentication at the first hop" with what your provider saw at the end. It cannot fetch the sealers' keys, so whether the chain verifies is taken from your provider's arc= result.
Got a suspicious email?
Paste its headers into the analyser. It runs on your device and explains every result on this page.
Open the analyser