Rolling Thunder Security · Codex · Social Engineering · Mail Authentication

SPF, DKIM, DMARC:
The Mail Authentication Trio

Email was designed in an era of trust. The original SMTP protocol takes a sender's word for who they are, full stop. Three later standards close that gap. SPF says which IPs are allowed to send for a domain. DKIM cryptographically signs the message. DMARC ties the two together with a policy and reports the verdict back to the domain owner. Together they decide whether the From header is the truth.

Three standards · one verdict Required by · Gmail / Yahoo / Microsoft Lives in · DNS
01
The Problem

Why Mail Authentication Exists

SMTP, the protocol that delivers email, was designed in 1982 with no authentication of any kind. Anyone can send a message claiming to be from anyone. Without help, every email is anonymous.

This was fine in 1982 because the entire internet trusted itself. By the time spam, phishing, and business-email-compromise became the dominant economic activity on email, the protocol was too widely deployed to redesign. So the industry stacked authentication standards on top of SMTP, one at a time, each filling a different gap that the others had missed.

The result is the trio on this page. None of them are mandatory parts of SMTP. None of them prevent a message from being sent. All of them help the receiver decide whether to trust a message after it arrives. They are also additive: a domain that publishes all three is much harder to spoof than a domain that publishes one or none.

What each one actually authenticates

SPF authenticates the sending server: is this IP allowed to send mail for this domain? DKIM authenticates the message: was this exact body and these headers signed by someone who controls the domain's private key? DMARC authenticates the identity claim: do SPF's domain or DKIM's signing domain agree with the visible From: header that the user sees?

02
Standard 01

SPF · Sender Policy Framework

SPF is an allow-list of IP addresses (and other domains) permitted to send mail for your domain. It lives as a single TXT record in DNS.

The domain owner publishes a list saying, in effect, "these IPs and these third-party services are allowed to send email claiming to be from me." When a receiving server gets a message, it looks at the SMTP envelope sender's domain, pulls up that domain's SPF record, and checks whether the connecting IP is in the allow-list. If it is, SPF passes. If it is not, SPF fails (or soft-fails, depending on the all-mechanism at the end of the record).

SPF has limits. It checks the MAIL FROM address (the envelope sender, which becomes Return-Path), not the visible From: header. A phisher can put one domain in the envelope and a different domain in the visible From, and SPF will happily pass on the envelope while the user still sees the spoofed name. DMARC (later) closes this gap by checking alignment between the two.

northgate.edu.IN TXT "v=spf1 ip4:128.210.0.0/16 include:_spf.google.com include:mailgun.org -all" // Allow mail from Northgate's own 128.210.0.0/16 range, plus Google Workspace and Mailgun. Anyone else: hard-fail.

Read the record as a series of mechanisms separated by spaces. Each mechanism either matches the connecting IP or does not. Evaluation stops at the first match. The final all mechanism is the catch-all and decides what happens when nothing else matched.

MechanismExampleWhat it means
v=spf1v=spf1Required version tag. Always the first thing in the record.
ip4:ip4:128.210.7.45
ip4:128.210.0.0/16
This IPv4 address (or CIDR range) is allowed to send for this domain.
ip6:ip6:2620:0:e10::/48Same as ip4 but for IPv6.
aa  or  a:mail.northgate.eduThe A/AAAA records of this domain (or the named host) are allowed senders.
mxmxThe MX servers of this domain are allowed senders. Convenient for small setups where the same server sends and receives.
include:include:_spf.google.com"And whatever their SPF record says is also allowed." Used to delegate to providers like Google Workspace, Microsoft 365, Mailgun, SendGrid.
+all+allCatch-all: pass anyone not matched above. Dangerous. Effectively disables SPF.
~all~allSoft-fail: receiver should be suspicious of unmatched senders but may still deliver. Common during initial rollout.
-all-allHard-fail: receiver should reject unmatched senders. The correct final stance for any mature deployment.
?all?allNeutral: no policy expressed. Effectively useless for enforcement.
The 10-lookup limit

SPF caps the number of DNS lookups a single evaluation can make at 10. Every include, a, mx, and similar mechanism counts. Bloated SPF records that pull in too many third-party providers exceed the limit and the receiver returns permerror, which most servers treat as fail. If you publish SPF, audit your lookup count.

03
Standard 02

DKIM · DomainKeys Identified Mail

DKIM cryptographically signs each outgoing message with a private key. The matching public key lives in the sender's DNS. Receivers verify the signature against the public key and know the message has not been tampered with in transit.

The sending mail server computes a cryptographic hash over the body and a selected list of headers, then signs the hash with its private RSA or Ed25519 key. The resulting signature, along with metadata describing which headers were signed and which selector to use, is attached as a DKIM-Signature: header. The corresponding public key is published as a TXT record at a well-known location: <selector>._domainkey.<domain>.

The receiving server pulls the public key from DNS using the selector named in the DKIM-Signature header, recomputes the hash, and verifies the signature. If the body or any signed header has changed (or never matched in the first place), verification fails. If the public key cannot be retrieved, DKIM is treated as none.

Sender (northgate.edu)

  1. Compose the message.
  2. Compute a hash over the body and selected headers (From, To, Subject, Date, Message-ID, etc.).
  3. Sign the hash with the domain's private key.
  4. Add a DKIM-Signature: header carrying the signature, the selector name, the signed-headers list, and the hashing algorithm.
  5. Send the message.

Receiver (anyone)

  1. Read the DKIM-Signature: header.
  2. Look up the public key in DNS at <selector>._domainkey.northgate.edu.
  3. Re-compute the same hash over the same headers and body.
  4. Verify the signature against the public key.
  5. Record the result in Authentication-Results: as dkim=pass, dkim=fail, or dkim=none.
default._domainkey.northgate.edu.IN TXT "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC7vQF8...AB" // The public RSA key, base64-encoded. Selector "default" is named in every signed message's DKIM-Signature header.
What DKIM signs and what it doesn't

DKIM signs the body and the headers the sender chose to include in the signature's h= tag. Received: headers added by relays are not signed (they don't exist yet when signing happens). Footers added by mailing lists often break DKIM signatures, which is one reason DMARC has its own alignment rules to compensate. Always sign the From: header at minimum — that is what DMARC needs.

04
Standard 03

DMARC · The Policy Layer

DMARC is the standard that ties SPF and DKIM to the visible From header, declares what to do when neither aligns, and asks the world to send aggregated reports back to the domain owner.

SPF and DKIM each authenticate a piece of the message, but neither one inherently protects the field your users actually see — the From: header. DMARC fills that gap. It defines two new requirements: alignment (covered in the next section), and a published policy of what receivers should do when the alignment check fails. It also adds a reporting channel so the domain owner can see who is sending mail as them.

The DMARC policy lives at a well-known DNS location: _dmarc.<domain>. It is a single TXT record with a small set of tags.

_dmarc.northgate.edu.IN TXT "v=DMARC1; p=quarantine; sp=reject; rua=mailto:dmarc-agg@northgate.edu; ruf=mailto:dmarc-fail@northgate.edu; adkim=r; aspf=r; pct=100" // Quarantine messages that fail on the main domain, reject for subdomains, send aggregate reports to dmarc-agg, send forensic per-message reports to dmarc-fail, relaxed alignment for both DKIM and SPF, apply policy to 100% of mail.
TagExampleWhat it means
vv=DMARC1Required version tag. Always present.
pp=none
p=quarantine
p=reject
The policy to apply when a message fails DMARC. None = monitor only. Quarantine = treat as spam. Reject = bounce the message.
spsp=rejectOptional policy applied to subdomains. If not set, subdomains inherit p.
ruarua=mailto:agg@example.comWhere to send aggregate reports (daily XML summaries). The single most useful tag in the record.
rufruf=mailto:fail@example.comWhere to send forensic reports (per-failed-message detail). Many receivers don't honor this for privacy reasons.
adkimadkim=r (relaxed)
adkim=s (strict)
DKIM alignment mode. Relaxed allows the DKIM signing domain to be any organizational match. Strict requires an exact domain match.
aspfaspf=r (relaxed)
aspf=s (strict)
SPF alignment mode. Same logic as adkim but for the SPF-validated domain.
pctpct=100Percentage of messages to apply the policy to. Lets you ramp up enforcement gradually (e.g. start at 10%, ramp to 100% over weeks).
p=none

Monitor mode

The receiver still applies SPF and DKIM checks and still writes the result into Authentication-Results, but takes no enforcement action against failing messages. The sender simply receives aggregate reports.

When to use: the first 4–8 weeks of deployment, while you find every legitimate mail source on your domain.
p=quarantine

Send to spam

Failing messages should be treated as suspicious and delivered to the spam / junk folder, not the inbox. Recipients can still recover them by digging.

When to use: after monitor mode confirms you have not missed any legitimate sender. Lets you enforce without bouncing real mail outright.
p=reject

Refuse the message

Failing messages are bounced at SMTP time. The mail never reaches the user, not even spam. The sender gets a bounce back.

When to use: the destination posture for any mature deployment. Required for Gmail / Yahoo bulk-sender compliance.
DMARC also gives you reports

This is the under-appreciated half of DMARC. Receivers that honor rua= send the domain owner a daily aggregate XML report listing every IP that tried to send mail claiming the domain, broken down by SPF and DKIM result. You will learn things you didn't know — including legitimate third-party services your own organization signed up for that aren't in your SPF record yet. Free tools (parsedmarc, postmark, etc.) turn the XML into dashboards.

05
The Key Concept

DMARC Alignment

SPF can pass while the message is still spoofed. DKIM can pass while the message is still spoofed. DMARC catches both because it requires alignment: SPF's domain or DKIM's signing domain has to match the visible From domain.

Recall: SPF checks the SMTP envelope sender (the domain in MAIL FROM, which becomes Return-Path:). DKIM signs whichever domain the sender chose to sign with (the d= tag in the DKIM-Signature header). Neither is required to be the same as the From: header that the user sees. A phisher can perfectly pass SPF for bulkmailer.co (the envelope they actually used) while writing From: alice@northgate.edu in the visible header.

DMARC declares this attack out of bounds. It requires that at least one of SPF or DKIM passes and aligns with the From domain. Either one is sufficient. Both failing means DMARC fails. Whether "aligns" means "exact match" or "organizational match" depends on the alignment mode in the DMARC record.

Relaxed vs strict alignment

Relaxed (the default): the organizational domains must match. From: alice@mail.northgate.edu aligns with SPF's northgate.edu because both share the organizational domain northgate.edu.

Strict: the full domain names must match exactly. From: alice@mail.northgate.edu would not align with SPF's northgate.edu under strict mode. Reserved for organizations that want maximum protection and have no sub-domain mail.

Example A · legitimate mail DMARC Pass
From:alice@northgate.edu Return-Path:bounces@northgate.edu DKIM d=northgate.edu SPFpass (envelope IP authorized for northgate.edu) SPF aligns?yes — northgate.edu = northgate.edu DKIM aligns?yes — northgate.edu = northgate.edu

Both SPF and DKIM pass and both align with the From domain. DMARC passes by either path. Mail is delivered.

Example B · spoofed mail DMARC Fail
From:alice@northgate.edu Return-Path:bounce@send-mailer.co DKIM d=(no signature) SPFpass (envelope IP authorized for send-mailer.co) SPF aligns?no — send-mailer.co ≠ northgate.edu DKIM aligns?no — no signature to align

SPF passed for the bulk mailer's own domain, but that domain does not align with the visible From. DKIM was never signed. DMARC fails. The domain's p=quarantine policy sends the message to spam.

06
How a Receiver Decides

The Evaluation Flow

When a message arrives at a receiving server, it runs the trio in order. The diagram below shows the full decision tree.

Message arrives Receiving server has the .eml SPF check Is sending IP in the Return-Path domain's SPF? DKIM verify Fetch public key, recompute hash, verify signature DMARC alignment Does SPF domain OR DKIM d= domain match the visible From: domain? DMARC pass Deliver to inbox. Record dmarc=pass in Authentication-Results. DMARC fail Look up _dmarc.<from-domain> Apply policy: none / quarantine / reject aligned + passed no alignment
SPF and DKIM are not gates — alignment is

An SPF pass alone does not mean DMARC passes. A DKIM pass alone does not mean DMARC passes. DMARC requires that at least one of the two also aligns with the visible From:. A message can have spf=pass dkim=pass dmarc=fail, which is exactly what happens when a spoofer correctly authenticates their own domain but writes a different domain in From.

07
Industry State

Industry Adoption

Major mailbox providers have moved from "we encourage SPF / DKIM / DMARC" to "we require all three for any bulk sender." That requirement quietly went into effect on February 1, 2024 and has not relaxed since.

If you operate any mailing list, marketing platform, or transactional sender that delivers more than 5,000 messages per day to Gmail or Yahoo accounts, your domain must pass all three checks or your messages will be filtered, deferred, or rejected. Microsoft has signaled they will reach the same posture on similar timelines. The era of opt-in mail authentication is over.

Gmail (Google)
Required since Feb 1, 2024
  • SPF and DKIM both required for any sender >5,000 messages/day to Gmail.
  • DMARC required (any policy, including p=none) with a valid rua reporting address.
  • One-click List-Unsubscribe header required for marketing mail.
  • Hard spam-rate ceiling of 0.3%.
Yahoo Mail
Required since Feb 1, 2024
  • Same requirements as Gmail. The two announced jointly.
  • Failure mode: defer, then bounce. Senders see delivery rates collapse rather than receive clean rejections.
Microsoft 365
Tightening since 2024
  • SPF and DKIM strongly recommended; aggressive spam scoring against senders without DMARC.
  • Tenant-level enforcement available to admins; default trending toward required.
Apple iCloud
Strict checks since 2022
  • All three checked; failures heavily weighted in spam scoring.
  • Mail Privacy Protection adds an extra layer that can interfere with simple open-tracking pixels.
What this means for a small institution

If you teach at a university, run a small business, or operate any service that sends email from a custom domain, you need all three. Start with SPF and DKIM at your mail provider (every major provider documents this), then add a DMARC record at p=none to collect reports for a few weeks, then graduate to p=quarantine and finally p=reject. The whole process takes a few hours of setup and a few weeks of monitoring. It is no longer optional.

08
Reference

A Complete Setup

Below are the three DNS records a hypothetical small institution would publish to authenticate its mail. Together they take less than five lines of zone file.

example.edu.IN TXT "v=spf1 ip4:198.51.100.0/24 include:_spf.google.com -all" // SPF: only our /24 and Google Workspace may send for us. Everyone else hard-fails.
google._domainkey.example.edu.IN TXT "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNAD..." // DKIM: the public key Google uses to sign our outgoing mail. Selector "google" matches the s= tag in the DKIM-Signature header.
_dmarc.example.edu.IN TXT "v=DMARC1; p=reject; sp=reject; rua=mailto:dmarc-reports@example.edu; adkim=r; aspf=r; pct=100" // DMARC: reject mail that fails both, send aggregate reports to dmarc-reports@, relaxed alignment, applied to 100% of mail.
Verifying your setup

Three quick checks: dig +short TXT example.edu for SPF, dig +short TXT google._domainkey.example.edu for DKIM, and dig +short TXT _dmarc.example.edu for DMARC. Online validators (MXToolbox, dmarcian, Postmark) parse the records and tell you whether anything is malformed. Once published, send a test message to a Gmail account and use Show original to confirm all three pass.

09
Going Back

Where to Go Next

You now have the three pieces of the phishing puzzle. Take the concepts back to a real email and read its headers.