Email was designed in an era when trust was assumed. The SMTP protocol lets anyone claim to send a message from any address. No verification, no challenge — just an assertion. I could send you an email right now claiming to be from ceo@yourbank.com and the protocol itself would shrug and deliver it.
a
The four protocols covered here — SPF, DKIM, DMARC, and ARC — are the industry’s accumulated answer to that original design flaw. They work together to prove that a message actually came from who it says it came from, that the message wasn’t tampered with in transit, and that receiving servers know what to do when those checks fail. Major providers like Gmail, Microsoft, and Yahoo now require proper authentication for reliable delivery. If you’re running your own mail server or sending on behalf of a domain you control, understanding these isn’t optional.
If you’ve already got messages flowing and want to verify what your headers are actually saying, the companion post How to Read Email Headers covers that in detail. This post is about understanding what these protocols are, how they work mechanically, and how to configure and troubleshoot them.
By the end of this, you’ll understand:
- What SPF, DKIM, DMARC, and ARC each do and why all four exist
- How to check your current DNS records for each protocol
- How to read authentication results in email headers
- How to implement authentication from scratch, in the right order
- What to look for when something breaks
Prerequisites:
- Basic familiarity with DNS records (TXT records, digging records from the command line)
- Access to your domain’s DNS management
- Some understanding of how email flows from sender to recipient
The Core Problem
Think of SMTP like a postcard. Anyone can write any return address on a postcard. The postal service delivers it without verifying the return address is real. The recipient has no way to know if it’s genuine without additional context.
SPF, DKIM, and DMARC are how the email world adds that context — but they do it at different layers, which is why you need all three.
SPF (Sender Policy Framework)
SPF is the simplest of the four. It’s a DNS TXT record published by a domain owner that says: “Here are the mail servers authorized to send email on my behalf. If a message claims to be from my domain but didn’t come from one of these servers, something is wrong.”
How SPF Works
- You publish a TXT record at your root domain listing authorized sending sources (IP addresses, hostnames, other domains’ SPF records).
- When a receiving mail server gets a message claiming to be from your domain, it checks the IP address that actually delivered the message against your SPF record.
- If the IP is listed, SPF passes. If not, the check fails.
Checking Your SPF Record
dig +short yourdomain.com TXT | grep spfWhat this does: Queries DNS for all TXT records at your domain and filters for the one containing “spf”. There should be exactly one SPF record — multiple SPF records on a single domain will cause authentication failures.
Example SPF record:
"v=spf1 include:_spf.google.com include:mailgun.org ip4:192.0.2.1 -all"
What each part means:
v=spf1— Version identifier. Required, always first.include:_spf.google.com— Trust every IP in Google’s SPF record. Used when Google Workspace sends on your behalf.include:mailgun.org— Trust Mailgun’s sending infrastructure. Same idea.ip4:192.0.2.1— Trust this specific IP address directly.-all— Any IP not covered by the above should be treated as a hard fail. Reject it.
The ending mechanism matters more than people realize:
-all(hard fail): Unauthorized sources are rejected. Use this once you’ve identified all your senders.~all(soft fail): Unauthorized sources are flagged but not rejected. Good during initial rollout.?all(neutral): No policy statement. Effectively meaningless — don’t use it.
Verifying SPF in Headers
After a message is received, look for the Received-SPF header or the spf= entry in Authentication-Results:
Authentication-Results: mx.google.com;
spf=pass (google.com: domain of jake@forthright.engineer designates 192.0.2.1 as permitted sender)
SPF’s Limitation
SPF only validates the envelope sender — the address used in the SMTP MAIL FROM command during delivery. This is not always the same as the From: address the recipient sees in their email client. That gap is what DMARC closes.
SPF also has a hard limit of 10 DNS lookups. Every include: statement that itself contains include: statements counts toward that limit. Exceed 10 and SPF fails, even if your IPs are legitimate.
DKIM (DomainKeys Identified Mail)
DKIM solves a different problem. SPF proves the message was sent from an authorized server. DKIM proves the message wasn’t modified after it left that server. It does this with cryptographic signatures.
Your mail server generates a public/private key pair. The private key stays on your server and signs each outgoing message. The public key gets published in DNS. When a receiving server gets your message, it fetches your public key from DNS and verifies the signature. If the signature checks out, the message arrived intact.
How DKIM Works
- Your mail server signs the message headers and body with its private key, producing a
DKIM-Signatureheader. - That header includes a reference to the DNS record where the public key lives.
- Receiving servers fetch your public key from DNS and cryptographically verify the signature.
- If the signature is valid, DKIM passes. If the message was modified in transit — even a single byte changed — the signature won’t verify.
Checking Your DKIM Record
DKIM records live at selector._domainkey.yourdomain.com. The selector is a label chosen by your mail server administrator, often something like default, google, selector1, or s1.
dig +short selector1._domainkey.yourdomain.com TXTWhat this does: Queries the DNS TXT record where your DKIM public key is published. You’ll need to know your selector to look this up — it’s visible in the DKIM-Signature header of any outbound message as the s= field.
Example DKIM DNS record:
"v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQ..."
What each part means:
v=DKIM1— Version identifier.k=rsa— Key type. RSA is still most common; Ed25519 is increasingly supported and produces shorter records.p=...— The public key itself, base64 encoded. This is what receiving servers use to verify signatures.
Verifying DKIM in Headers
The DKIM-Signature header in the original message:
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=forthright.engineer; s=selector1;
h=from:to:subject:date:message-id;
bh=base64hashofbody;
b=base64signaturevalue
Key fields:
d=— The signing domain. This must match (or align with) theFrom:domain for DMARC to pass.s=— The selector. Tells you where to find the public key:selector1._domainkey.forthright.engineer.h=— The list of headers that were signed.bh=— A hash of the message body.b=— The actual signature over the headers.
The Authentication-Results header shows the verdict:
Authentication-Results: mx.google.com;
dkim=pass header.d=forthright.engineer header.s=selector1
DKIM’s Limitation
DKIM proves integrity and origin, but it doesn’t tell receiving servers what to do when it fails. A forged message will fail DKIM — but without a policy in place, it might still be delivered. That’s DMARC’s job.
DMARC (Domain-based Message Authentication, Reporting, and Conformance)
DMARC is the policy layer. It ties SPF and DKIM together and gives domain owners explicit control over what happens when those checks fail. It also adds a critical concept the other two lack: alignment.
The Alignment Requirement
Here’s the gap DMARC addresses. SPF can pass based on the envelope sender (MAIL FROM). DKIM can pass based on the d= domain in the signature. Neither of those need to match the From: address the human recipient sees in their email client.
DMARC requires that at least one of those authenticated identifiers aligns with the visible From: domain:
- SPF alignment: The
MAIL FROMdomain must match theFrom:header domain. - DKIM alignment: The
d=domain in the DKIM signature must match theFrom:header domain.
This alignment check is what closes the phishing loophole. An attacker who sets up a legitimate SMTP server for attacker.com could pass SPF — but won’t pass DMARC alignment if the From: claims to be yourbank.com.
How DMARC Works
- You publish a DMARC policy as a DNS TXT record at
_dmarc.yourdomain.com. - Receiving servers check whether SPF passes with alignment, or DKIM passes with alignment (or both).
- Based on your policy, they deliver, quarantine, or reject messages that fail.
- They send you aggregate reports on authentication outcomes across all mail claiming to be from your domain.
Checking Your DMARC Record
dig +short _dmarc.yourdomain.com TXTWhat this does: Queries the DNS TXT record at the _dmarc subdomain where your policy lives. Note the underscore prefix — this is required.
Example DMARC record:
"v=DMARC1; p=reject; rua=mailto:dmarc-reports@yourdomain.com; pct=100"
What each part means:
v=DMARC1— Version identifier. Required, always first.p=reject— The policy applied to failed messages. Options:none,quarantine, orreject.rua=mailto:...— Where to send aggregate reports (XML files summarizing authentication results across all mail for your domain). Essential during initial deployment.pct=100— Apply this policy to 100% of messages. You can use a lower percentage while ramping up a stricter policy.
Policy progression:
p=none— Monitor only. Failed messages are delivered normally, but reports are generated. Start here.p=quarantine— Failed messages go to spam/junk. Move here after reviewing reports and confirming your legitimate senders are covered.p=reject— Failed messages are rejected outright. The destination to aim for.
Verifying DMARC in Headers
Authentication-Results: mx.google.com;
dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=forthright.engineer
Key parts:
dmarc=pass— Both alignment and authentication passed.p=REJECT— The policy published for this domain.sp=REJECT— Subdomain policy (if separate from the main policy).dis=NONE— Disposition taken on this message.nonemeans it was delivered normally because it passed.
When DMARC fails, dis= reflects the actual action taken: quarantine if it was sent to spam, none even if policy says reject (if the receiver chose not to enforce).
ARC (Authenticated Received Chain)
ARC addresses a problem that SPF, DKIM, and DMARC collectively create. When email passes through intermediaries — mailing lists, forwarding services, security gateways — those services often legitimately modify the message or relay it from their own IP addresses. That breaks DKIM signatures and SPF alignment, causing DMARC to fail for messages that were originally legitimate.
ARC preserves the authentication state across those hops, letting the final recipient know that authentication passed before the message was forwarded.
How ARC Works
- The first server to receive a message records the SPF, DKIM, and DMARC results in an ARC header.
- Each subsequent intermediary adds its own set of ARC headers, signing the previous authentication state.
- The final recipient can read the full chain, seeing authentication results at each hop.
If the ARC chain is intact and trusted, the receiving server can override a DMARC failure caused by forwarding — because it can see that the message passed authentication before it was forwarded.
The Three ARC Headers
At each hop, three headers are added:
ARC-Authentication-Results (AAR): Records the SPF, DKIM, and DMARC results at this point in the chain.
ARC-Authentication-Results: i=1; mx.google.com;
spf=pass smtp.mailfrom=mailing-list.org;
dkim=pass header.d=forthright.engineer;
dmarc=pass header.from=forthright.engineer
ARC-Message-Signature (AMS): A DKIM-style signature of the message at this point, preserving its state.
ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed;
d=google.com; s=arc-20160816;
h=from:to:subject:date;
b=signature...
ARC-Seal: Signs the ARC headers themselves, ensuring the chain record hasn’t been tampered with.
ARC-Seal: i=1; a=rsa-sha256; t=1234567890; cv=none;
d=google.com; s=arc-20160816;
b=signature...
What each field means:
i=— Instance number. Increments at each hop (i=1, i=2, i=3…).cv=— Chain validation for the ARC-Seal.noneon the first hop,passif the chain is intact,failif it was tampered with.
When ARC Matters
ARC becomes visible when DMARC fails but the underlying message was legitimate:
Authentication-Results: mx.google.com;
dmarc=fail (p=REJECT dis=NONE) header.from=forthright.engineer;
arc=pass (i=2 spf=pass dkim=pass dmarc=pass)
Here, DMARC failed because forwarding broke alignment — but the ARC chain shows authentication passed at hop 2. The receiving server delivered the message rather than rejecting it, because it trusts the ARC chain.
On Microsoft’s infrastructure, look for compauth=pass reason=130 in the Authentication-Results header — that specifically indicates ARC was used to override a DMARC failure.
ARC is worth understanding, but it’s largely automatic — major mail servers (Gmail, Microsoft, Yahoo) implement it. You don’t configure ARC yourself unless you’re operating a mail gateway or forwarding service.
Viewing Email Headers
To verify authentication results yourself, you need to see the raw headers of a received message:
- Gmail: Open the message → Three-dot menu → “Show original”
- Outlook: Open the message → File → Properties → “Internet headers”
- Apple Mail: View → Message → All Headers
- Thunderbird: View → Headers → All
Headers appear in reverse chronological order — newest additions at the top. To trace a message’s path, read from bottom to top. The Authentication-Results header near the top is added by the final receiving server and reflects the overall authentication outcome.
Implementing Authentication: The Right Order
The right sequence matters. Rolling out DMARC enforcement before you’ve confirmed SPF and DKIM are working correctly will break legitimate mail.
Phase 1: Establish a baseline
- Publish an SPF record listing your known sending sources (your mail server, any third-party services like Mailchimp, Mailgun, Postmark, etc.).
- Configure DKIM on your mail server. Most managed mail services (Google Workspace, Microsoft 365) do this for you — verify DKIM is enabled and the DNS record is published.
- Publish DMARC with
p=noneand a reporting address:"v=DMARC1; p=none; rua=mailto:dmarc@yourdomain.com"
Start receiving reports. Tools like DMARC Analyzer or MXToolbox can parse the XML aggregate reports into something readable.
Phase 2: Review and adjust
Review reports for 2–4 weeks. Look for:
- Sources sending on behalf of your domain that aren’t in your SPF record
- Services that aren’t signing with DKIM
- Any DMARC alignment failures on mail you recognize as legitimate
Add missing sources to SPF. Work with missing DKIM signers to enable it.
Phase 3: Enforce
Once reports show only legitimate mail is passing:
- Move DMARC to
p=quarantine - After another review period with no unexpected quarantining, move to
p=reject - Change SPF from
~allto-all
Troubleshooting Authentication Failures
When things break, narrow it down systematically.
SPF failures:
- Is the sending IP listed in your SPF record? Check with
dig +short yourdomain.com TXT. - Did you exceed the 10 DNS lookup limit? Every
include:that expands to otherinclude:statements counts. Use MXToolbox’s SPF checker to count your lookups. - Is a third-party service sending on your behalf that isn’t in your record? Check DMARC aggregate reports for unfamiliar sending IPs.
DKIM failures:
- Is the public key published at the correct selector? The selector is in the
DKIM-Signatureheader’ss=field. - Has the message been modified by a gateway or spam filter? Some filters rewrite headers or modify the body, breaking the signature.
- Are the signed headers (
h=) being changed downstream? If a mailing list adds a footer, the body hash (bh=) will fail.
DMARC failures:
- SPF or DKIM might pass, but alignment might fail. Check whether the SPF
MAIL FROMdomain and DKIMd=domain actually match the visibleFrom:domain. - Mailing lists almost always break SPF alignment (they relay from their own servers) and often break DKIM (they modify the message). This is exactly the scenario ARC is designed to handle.
- Forwarding services that don’t implement SRS (Sender Rewriting Scheme) will break SPF alignment.
ARC considerations:
- If mail is being forwarded through a major provider (Gmail, Microsoft), ARC headers are likely being added automatically.
- If you’re running your own forwarding or mailing list infrastructure, verify it’s adding ARC headers.
- The receiving server has to trust the intermediate server’s ARC signatures. Major providers are on each other’s trusted lists; your personal mail server may not be.
Closing Thoughts
These four protocols are unglamorous plumbing — TXT records in DNS, headers most users never see — but they’re the difference between mail that arrives and mail that doesn’t. More importantly, they’re the difference between a domain that can be impersonated in phishing attacks and one that can’t.
Getting to p=reject on DMARC and -all on SPF takes patience. The aggregate reports will surface senders you forgot about. Some third-party service will turn out to be sending on your behalf without DKIM. Work through it methodically rather than rushing to enforcement and breaking legitimate mail.
Done right, you end up with something solid: a domain where spoofing is cryptographically difficult, delivery is reliable, and you have visibility into every server on the planet that’s trying to send email in your name.
Footnotes:
[1] SPF specification (RFC 7208): https://datatracker.ietf.org/doc/html/rfc7208 [2] DKIM specification (RFC 6376): https://datatracker.ietf.org/doc/html/rfc6376 [3] DMARC specification (RFC 7489): https://datatracker.ietf.org/doc/html/rfc7489 [4] ARC specification (RFC 8617): https://datatracker.ietf.org/doc/html/rfc8617 [5] Microsoft ARC documentation: https://learn.microsoft.com/en-us/defender-office-365/email-authentication-arc-configure
Tags: email, DNS, SPF, DKIM, DMARC, ARC, infrastructure, security, deliverability