How DKIM, SPF, and DMARC Work: Email Authentication Explained
DKIM, SPF, and DMARC are the three pillars of email authentication -- a set of DNS-based mechanisms that allow domain owners to declare which servers are authorized to send email on their behalf and to cryptographically sign messages so recipients can verify their authenticity. Together, they combat email spoofing, phishing, and spam by giving receiving mail servers a way to distinguish legitimate messages from forgeries. Without these protocols, anyone can send an email claiming to be from any domain -- the base SMTP protocol has no built-in sender verification.
Email authentication is not a single protocol but an ecosystem of complementary standards. SPF (Sender Policy Framework, RFC 7208) declares which IP addresses may send mail for a domain. DKIM (DomainKeys Identified Mail, RFC 6376) attaches a cryptographic signature to each message. DMARC (Domain-based Message Authentication, Reporting and Conformance, RFC 7489) ties SPF and DKIM together with a policy that tells receivers what to do when authentication fails and provides a reporting mechanism back to the domain owner. ARC (Authenticated Received Chain, RFC 8617) preserves authentication results through forwarding chains. Each layer addresses a gap left by the others.
Understanding how these protocols interact -- and where they break down -- is essential for anyone managing mail infrastructure, debugging delivery problems, or defending against phishing attacks.
SPF: Sender Policy Framework
SPF is the simplest of the three protocols. It answers one question: is the server sending this email authorized to do so for this domain? SPF works by publishing a DNS TXT record on the sending domain that lists all IP addresses and networks permitted to send mail on behalf of that domain. When a receiving mail server gets a message, it checks the envelope sender (the MAIL FROM address in the SMTP transaction, also called the Return-Path) against the SPF record of that domain.
SPF Record Syntax
An SPF record is a DNS TXT record that begins with v=spf1 and contains a series of mechanisms and modifiers. Each mechanism matches against the connecting server's IP address and returns a qualifier:
v=spf1 ip4:192.0.2.0/24 ip6:2001:db8::/32 include:_spf.google.com include:servers.mcsv.net ~all
The mechanisms are evaluated left to right, and the first match wins:
ip4:andip6:-- match specific IP addresses or CIDR ranges. These are the most explicit: "this exact server may send our mail."a-- match the A/AAAA records of the domain itself. If the domain's web server also sends mail, this covers it.mx-- match the IP addresses of the domain's MX records. The servers that receive mail for the domain are also allowed to send it.include:-- recursively check the SPF record of another domain. This is how third-party services are authorized:include:_spf.google.commeans "anyone authorized by Google Workspace's SPF record is also authorized for our domain."redirect=-- redirect SPF evaluation entirely to another domain's record. Unlikeinclude, which is just one mechanism,redirectreplaces the entire policy.exists:-- a macro-based mechanism that checks for the existence of a DNS A record, allowing complex per-IP authorization schemes.all-- matches everything. It is always placed last as the catch-all default.
Each mechanism is prefixed with a qualifier (or defaults to + if omitted):
+(Pass) -- the IP is authorized-(Fail) -- the IP is explicitly not authorized; reject the message~(SoftFail) -- the IP is probably not authorized; accept but mark as suspicious?(Neutral) -- no assertion is made; treat as if there were no SPF record
SPF Limitations
SPF has several well-known limitations that make it insufficient on its own:
- DNS lookup limit -- RFC 7208 limits SPF evaluation to 10 DNS lookups (including recursive
include:lookups). Large organizations that use many third-party email services often exceed this limit, causing SPF to return a "permerror" and effectively fail. Flattening SPF records (replacinginclude:with resolved IP ranges) is a common workaround but creates maintenance burden. - Forwarding breaks SPF -- when a message is forwarded (e.g., university alumni forwarding to Gmail), the forwarding server's IP is not in the original domain's SPF record. The message fails SPF at the final destination. This is the primary reason SPF cannot be the sole authentication mechanism.
- SPF checks the envelope sender, not the header From -- the MAIL FROM address in the SMTP envelope may differ from the From: header that users see in their email client. An attacker can set a legitimate MAIL FROM domain (passing SPF) while displaying a spoofed From: header to the user. DMARC addresses this gap.
- No message integrity -- SPF verifies the sending server's IP address but says nothing about whether the message content was altered in transit.
DKIM: DomainKeys Identified Mail
DKIM provides what SPF lacks: cryptographic proof that a message was sent by the claimed domain and has not been modified in transit. Defined in RFC 6376, DKIM works by having the sending mail server attach a digital signature to each outgoing message. The signature covers specific message headers and the body, and the public key needed to verify the signature is published in the domain's DNS records.
How DKIM Signing Works
When a DKIM-enabled mail server sends a message, it performs the following steps:
- Canonicalization -- the message headers and body are normalized to handle minor variations introduced by different mail servers (extra whitespace, header folding, case differences). DKIM defines two canonicalization algorithms: simple (almost no changes allowed) and relaxed (whitespace and case normalization). The
c=tag in the signature specifies which algorithm is used for headers and body separately, e.g.,c=relaxed/relaxed. - Hash the body -- a hash of the canonicalized body is computed (typically SHA-256). The body hash is included in the DKIM-Signature header as the
bh=tag. - Select headers to sign -- the signer chooses which headers to include in the signature. At minimum, the
From:header must be signed. Typically,Subject:,Date:,To:,Cc:,Message-ID:,MIME-Version:, andContent-Type:are also included. Theh=tag lists the signed headers. - Compute the signature -- the signer concatenates the canonicalized signed headers plus the DKIM-Signature header itself (with an empty
b=tag), hashes the result, and signs it with the domain's private key using RSA-SHA256 or Ed25519-SHA256. - Attach the signature -- the signature is added as a
DKIM-Signature:header at the top of the message.
A typical DKIM-Signature header looks like this:
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=example.com; s=selector1;
h=from:to:subject:date:message-id:mime-version:content-type;
bh=2jUSOH9NhtVGCQWNr9BrIAPreKQjO6Sn7XIkfJVOzv8=;
b=AuUoFEfDxTDkHlLXSZEpZj79LICEps6eda7W3deTVFOk2P3QNPGdhYe
NMRgTvQJDbhD7gxLNNJtT9CanCMnrSa...
The key tags in the signature are:
v=1-- DKIM version (always 1)a=-- signing algorithm (rsa-sha256 or ed25519-sha256)c=-- canonicalization method (header/body)d=-- the signing domain (what the verifier checks against)s=-- the selector, used to locate the public key in DNSh=-- list of signed header fieldsbh=-- body hash (Base64-encoded)b=-- the actual signature value (Base64-encoded)l=-- (optional) length of the body that was signed, allowing content to be appended without breaking the signature (rarely used, security risk)
DKIM Key Management and DNS
The public key for DKIM verification is published in a DNS TXT record at <selector>._domainkey.<domain>. For example, if the signing domain is example.com and the selector is selector1, the public key is at:
selector1._domainkey.example.com. IN TXT "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4..."
The selector mechanism allows a domain to maintain multiple active DKIM keys simultaneously. This is essential for key rotation: deploy a new key with a new selector, start signing with it, and retire the old selector once all in-flight messages have been delivered. Large mail providers like Google use selectors like 20230601 to indicate the key's deployment date.
DKIM supports two signing algorithms:
- RSA-SHA256 -- the most widely supported algorithm. Key sizes of 2048 bits are standard (1024-bit keys are deprecated and increasingly rejected by receivers). The downside is that 2048-bit RSA keys are long -- 400+ characters in Base64 -- which can exceed the 255-byte limit for a single DNS TXT string and requires splitting across multiple strings.
- Ed25519-SHA256 -- defined in RFC 8463, this uses elliptic curve cryptography with much shorter keys (44 characters in Base64) and faster signing/verification. Adoption is growing but not yet universal. Messages should be dual-signed with both RSA and Ed25519 during the transition period.
DKIM Verification
When a receiving mail server gets a message with a DKIM-Signature header, it:
- Extracts the signing domain (
d=) and selector (s=) from the signature. - Queries DNS for the TXT record at
<selector>._domainkey.<domain>to retrieve the public key. - Canonicalizes the signed headers and body using the method specified in
c=. - Computes the body hash and compares it to the
bh=value in the signature. - Verifies the cryptographic signature using the public key.
- Records the result (pass, fail, or other) in an
Authentication-Results:header added to the message.
A crucial distinction from SPF: DKIM survives forwarding. When a message is forwarded by an intermediary server, the DKIM signature remains intact (assuming the forwarder does not modify the signed headers or body), because the signature was computed by the original sending domain, not by the IP address of the sending server. This makes DKIM far more robust than SPF for messages that traverse mailing lists, alumni forwarding services, or other intermediaries.
DKIM Limitations
DKIM is not without its weaknesses:
- DKIM does not specify what to do on failure -- if a message fails DKIM verification, the receiving server has no guidance from the sending domain about whether to reject, quarantine, or accept it. This is the gap DMARC fills.
- Header reordering and modification -- mailing list software often modifies subject lines (adding "[listname]"), appends footers to the body, or adds new headers. Any modification to signed content invalidates the DKIM signature.
- Replay attacks -- a valid DKIM-signed message can be replayed (re-sent) by anyone who has a copy. The signature remains valid because it is not tied to a specific recipient or time. Attackers exploit this by taking a legitimately signed message and sending it to millions of spam targets.
- Key management complexity -- organizations must securely store private keys on every outbound mail server, rotate keys periodically, and manage selectors across multiple sending services.
DMARC: Tying SPF and DKIM Together
DMARC (RFC 7489) is the policy and reporting layer that makes SPF and DKIM actionable. Without DMARC, a receiving server that detects an SPF failure or a DKIM failure has no guidance from the sending domain about what to do -- and no way to inform the domain owner that failures are occurring. DMARC solves both problems.
DMARC Alignment
The core concept in DMARC is alignment: the domain in the From: header (visible to the user) must align with the domain authenticated by SPF or DKIM. This closes the gap where SPF checks the envelope sender (MAIL FROM) and DKIM signs with an arbitrary domain -- neither necessarily matches what the user sees in the From: field.
DMARC defines two types of alignment:
- Strict alignment -- the domains must match exactly.
mail.example.comdoes not align withexample.com. - Relaxed alignment (default) -- the organizational domains must match.
mail.example.comaligns withexample.combecause they share the same organizational domain.
A message passes DMARC if either SPF or DKIM passes and aligns with the From: domain:
- SPF alignment -- the domain in the MAIL FROM address (used for SPF check) must match the From: header domain.
- DKIM alignment -- the domain in the DKIM signature's
d=tag must match the From: header domain.
DMARC Policy Records
DMARC policies are published as DNS TXT records at _dmarc.<domain>:
_dmarc.example.com. IN TXT "v=DMARC1; p=reject; rua=mailto:[email protected]; ruf=mailto:[email protected]; adkim=r; aspf=r; pct=100; sp=reject"
The key tags:
p=-- the policy for messages that fail DMARC:none-- take no action (monitor only, collect reports)quarantine-- deliver to spam/junk folderreject-- reject the message entirely (SMTP 550 error)
sp=-- subdomain policy (same options asp=). If absent, subdomains inherit the parent domain's policy.rua=-- URI for aggregate reports (daily XML reports summarizing authentication results across all messages)ruf=-- URI for forensic/failure reports (per-message reports for DMARC failures; many receivers do not send these due to privacy concerns)adkim=-- DKIM alignment mode:r(relaxed) ors(strict)aspf=-- SPF alignment mode:r(relaxed) ors(strict)pct=-- percentage of messages subject to the policy (allows gradual rollout)fo=-- failure reporting options:0(report if all fail),1(report if any fail),d(report DKIM failure),s(report SPF failure)
DMARC Deployment Strategy
DMARC should be deployed in stages to avoid disrupting legitimate email flows:
- Monitor (
p=none) -- publish a DMARC record withp=noneand collect aggregate reports. Analyze the reports to identify all legitimate mail sources for the domain. This phase typically lasts 2-4 weeks. - Quarantine (
p=quarantine; pct=10) -- gradually increase enforcement. Start with 10% of failing messages being quarantined, then ramp up to 100% while monitoring for legitimate mail being incorrectly caught. - Reject (
p=reject) -- once all legitimate sources are authenticated, enforce full rejection. At this point, any message failing DMARC is definitively spoofed.
DMARC Aggregate Reports
DMARC aggregate reports are XML documents sent daily (typically) by receiving mail servers. They contain a summary of all messages claiming to be from your domain, grouped by source IP, with SPF and DKIM results for each group. A simplified example:
<record>
<row>
<source_ip>192.0.2.10</source_ip>
<count>1523</count>
<policy_evaluated>
<disposition>none</disposition>
<dkim>pass</dkim>
<spf>pass</spf>
</policy_evaluated>
</row>
<row>
<source_ip>203.0.113.45</source_ip>
<count>87</count>
<policy_evaluated>
<disposition>reject</disposition>
<dkim>fail</dkim>
<spf>fail</spf>
</policy_evaluated>
</row>
</record>
These reports are essential for identifying misconfigured legitimate senders (marketing platforms, CRM systems, support ticketing systems that send on behalf of your domain) and for quantifying the volume of spoofing attempts targeting your domain.
ARC: Authenticated Received Chain
ARC (RFC 8617) solves the most persistent problem with SPF and DKIM: message forwarding. When a message passes through a mailing list or forwarding service, SPF fails (the forwarding server's IP is not in the original domain's SPF record) and DKIM often fails (the mailing list modifies the subject or appends a footer). DMARC then fails because neither SPF nor DKIM passes with alignment.
ARC allows intermediary servers to assert the authentication results they observed when the message arrived, and to sign those assertions. Each intermediary in the forwarding chain adds a set of three ARC headers:
ARC-Authentication-Results (AAR)-- the authentication results (SPF, DKIM, DMARC) as observed by this intermediary when the message arrived.ARC-Message-Signature (AMS)-- a DKIM-like signature over the message as it existed at this point in the chain.ARC-Seal (AS)-- a signature over the ARC headers themselves, creating a chain of custody. Each seal covers all previous ARC header sets, preventing tampering with earlier entries.
Each set is numbered with an instance counter (i=1, i=2, etc.), creating an ordered chain. When the final destination receives the message, it can walk the ARC chain backward: if it trusts the most recent ARC intermediary and that intermediary saw valid DKIM/SPF, the destination can accept the message despite the current DKIM/SPF failures.
ARC does not replace DMARC -- it supplements it. A receiver's DMARC evaluation can consider ARC results when making disposition decisions, but only if the receiver trusts the ARC-signing intermediaries. Gmail, Microsoft, and other major receivers maintain lists of trusted ARC signers.
Putting It All Together: The Full Authentication Pipeline
When a receiving mail server processes an inbound message, the full authentication pipeline looks like this:
- SMTP connection -- the sending server connects and provides the envelope sender (MAIL FROM).
- SPF check -- the receiver queries DNS for the SPF record of the envelope sender domain and checks the connecting IP against it. Result: pass, fail, softfail, neutral, permerror, or temperror.
- Message received -- the message headers and body are received.
- DKIM check -- the receiver extracts the DKIM-Signature header, fetches the public key from DNS, and verifies the signature. Result: pass, fail, or none (no signature).
- DMARC check -- the receiver queries DNS for the DMARC record of the From: header domain. It checks whether SPF or DKIM passed with alignment to the From: domain. Based on the DMARC policy (
p=), the message is accepted, quarantined, or rejected. - ARC check (if present) -- if DMARC fails but ARC headers are present, the receiver evaluates the ARC chain to determine if a trusted intermediary saw valid authentication earlier in the chain.
- Authentication-Results header -- the receiver adds an
Authentication-Results:header summarizing all checks, which downstream mail processing (spam filters, user-visible indicators) can use.
Authentication-Results: mx.google.com;
dkim=pass header.d=example.com header.s=selector1;
spf=pass (google.com: domain of [email protected] designates 192.0.2.10 as permitted sender) [email protected];
dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=example.com
Common Authentication Failures and Debugging
Email authentication failures are notoriously difficult to debug because the symptoms (messages going to spam, being silently dropped, or being rejected) are often reported by end users long after the message was sent. Common failure scenarios include:
SPF Failures
- Missing
include:for a third-party sender -- when an organization starts using a new email service (marketing platform, helpdesk, CRM) but forgets to add the service's SPF include. The fix is to add the appropriateinclude:mechanism to the SPF record. - DNS lookup limit exceeded -- the SPF record, after resolving all
include:chains, requires more than 10 DNS lookups. This results in apermerror, which most receivers treat as a fail. Solutions include consolidating IP ranges, usingip4:/ip6:mechanisms instead of includes, or using SPF flattening tools. - Forwarding -- as discussed, forwarded messages fail SPF because the forwarding server's IP is not authorized. SRS (Sender Rewriting Scheme) is a partial mitigation: the forwarding server rewrites the envelope sender to its own domain, so SPF is checked against the forwarder's domain instead.
DKIM Failures
- Key not published or selector mismatch -- the sending server signs with selector
s1, but the DNS TXT record is published ats2._domainkey.example.com. Verify the selector in the DKIM-Signature header matches the DNS record. - Body modification -- mailing lists, email gateways, or security appliances that append footers, rewrite URLs, or add disclaimers to the body will invalidate the DKIM body hash. The solution is to ensure DKIM signing happens after all body modifications.
- Expired or rotated keys -- if the DNS record for a selector is removed before all signed messages with that selector have been delivered, verification will fail. Maintain old selectors in DNS for at least 7 days after stopping use.
- DNS caching -- after rotating DKIM keys, the old key may remain in DNS caches for up to the record's TTL. Set DKIM key TTL to a short value (300-600 seconds) before rotation.
DMARC Failures
- Alignment failures -- SPF passes but the MAIL FROM domain does not match the From: header domain. DKIM passes but the
d=domain does not match the From: header domain. Both authenticate successfully but neither aligns, so DMARC fails. This commonly happens with third-party senders that use their own envelope sender domain. - Subdomain policy issues -- a domain has
p=rejectbut does not setsp=reject. Attackers spoof subdomains likeanything.example.com, which is not covered by the parent domain's policy unlesssp=is set or a wildcard DMARC record is published.
BIMI: Brand Indicators for Message Identification
BIMI is a newer standard that builds on top of DMARC to display a verified brand logo next to authenticated messages in supporting email clients. For BIMI to work, a domain must have p=quarantine or p=reject DMARC policy. The BIMI record is a DNS TXT record at default._bimi.<domain> containing a URL to the brand's SVG logo and optionally a Verified Mark Certificate (VMC) issued by a certificate authority.
BIMI provides a visible incentive for domain owners to deploy DMARC: users can see at a glance whether a message is authenticated, and brands get logo display as a reward for securing their email. Gmail, Apple Mail, and Yahoo Mail support BIMI.
DNSSEC and Email Authentication
All three protocols (SPF, DKIM, DMARC) rely on DNS for publishing and retrieving records. Without DNSSEC, an attacker who can spoof DNS responses (via cache poisoning or man-in-the-middle attacks) could provide a false SPF record (making the attacker's IP appear authorized), a false DKIM public key (allowing the attacker to forge signatures), or a false DMARC record (setting p=none to disable enforcement).
DNSSEC provides cryptographic authentication of DNS responses, ensuring that the SPF, DKIM, and DMARC records retrieved by the receiver are authentic and have not been tampered with. While DNSSEC adoption remains incomplete, signing your domain's DNS zone significantly strengthens email authentication.
Real-World Adoption and Impact
Major email providers have progressively tightened email authentication requirements:
- Google (2024) -- requires SPF or DKIM for all senders, and DMARC with
p=quarantineorp=rejectfor bulk senders (more than 5,000 messages/day to Gmail). - Yahoo (2024) -- similar requirements to Google for bulk senders.
- Microsoft 365 -- enforces DMARC policies strictly and generates aggregate reports.
Studies show that domains with p=reject DMARC policies see a 95%+ reduction in spoofed messages reaching recipients. However, as of 2025, fewer than 30% of domains have any DMARC record published, and fewer than 10% have enforcement-level policies (p=quarantine or p=reject).
Relevant RFCs
- RFC 7208 -- Sender Policy Framework (SPF)
- RFC 6376 -- DomainKeys Identified Mail (DKIM) Signatures
- RFC 8463 -- Ed25519 for DKIM
- RFC 7489 -- Domain-based Message Authentication, Reporting, and Conformance (DMARC)
- RFC 8617 -- Authenticated Received Chain (ARC)
- RFC 8601 -- Message Header Field for Indicating Message Authentication Status
- RFC 7960 -- Interoperability Issues between DMARC and Indirect Email Flows
See It in Action
Email authentication is deeply tied to DNS infrastructure. Every SPF lookup, DKIM key retrieval, and DMARC policy check is a DNS query that traverses the internet's routing infrastructure. Use the god.ad BGP Looking Glass to explore the networks of major email providers and see the AS paths between them:
- AS15169 -- Google (Gmail, Workspace)
- AS8075 -- Microsoft (Outlook, Exchange Online)
- AS36646 -- Yahoo Mail
- AS13238 -- Yandex Mail
- AS24940 -- Hetzner, a major mail hosting provider
Every email you send traverses BGP-routed paths from your mail server to the recipient's MX server. The SMTP connection, the DNS lookups for SPF/DKIM/DMARC, and the aggregate report delivery all depend on the global routing table. Look up your mail server's IP address to see its route origin and the path it takes to reach major email providers.