SPF, DKIM, and DMARC for Transactional Email Authentication
Configure SPF, DKIM, and DMARC for transactional email with real DNS records, the 10-lookup limit, alignment rules, and per-provider evaluation at Gmail, Outlook, and Yahoo.
Receiving mail servers no longer trust the From header at face value: forged sender domains are trivial to construct over SMTP, so mailbox providers verify three cryptographic and DNS-based signals before they decide whether your password reset or receipt reaches the inbox. SPF, DKIM, and DMARC are those signals. Getting them right is the difference between deterministic delivery and silent spam-foldering, and since 2024 it is a hard requirement for any sender pushing meaningful volume to Gmail or Yahoo. This guide is the authentication layer of the broader Transactional Email Delivery Infrastructure reference, covering exact DNS records, how each provider evaluates them, and the rollout and debugging steps that keep mail flowing.
Why Authentication Exists: Forgery and the 2024+ Mandate
SMTP was designed without sender verification. Anyone can connect to a mail server and announce MAIL FROM:<billing@yourbank.com> regardless of whether they control that domain. This is the mechanical basis of phishing and brand spoofing. SPF, DKIM, and DMARC layer verifiable proof onto this trust-free protocol:
- SPF answers "is this sending IP authorized by the envelope-sender's domain?"
- DKIM answers "was this message cryptographically signed by the domain, and is it unmodified?"
- DMARC answers "do SPF or DKIM align with the visible
Fromdomain, and what should I do if neither does?"
In February 2024, Gmail and Yahoo turned long-standing best practice into policy. Bulk senders (5,000+ messages/day to their users) must now publish SPF, DKIM, and a DMARC record at minimum p=none, keep spam complaint rates below 0.3%, and offer one-click unsubscribe on marketing mail. Microsoft followed with similar enforcement for high-volume senders to Outlook.com and Hotmail in 2025. Transactional senders rarely qualify as "bulk," but the same checks run on every message, and unauthenticated transactional mail is increasingly throttled or rejected outright. Treat all three as mandatory.
SPF: Authorizing the Sending IPs
Sender Policy Framework publishes, as a DNS TXT record on the envelope-sender (Return-Path) domain, the set of IPs and hosts allowed to send on its behalf. A receiver looks up the record, expands its mechanisms, and checks whether the connecting IP is listed.
; SPF record published at the root of your sending domain (TXT)
; Used by Gmail, Yahoo, and corporate gateways to verify the connecting IP.
yourdomain.com. IN TXT "v=spf1 include:amazonses.com include:_spf.google.com -all"
; | | | |
; | | | +-- hard fail: reject unlisted IPs
; | | +-- Google Workspace relay (transactional + corporate mail)
; | +-- Amazon SES sending IPs (your ESP)
; +-- SPF version marker, required first token
Key constraints:
include:mechanisms delegate to a provider's own SPF record.include:amazonses.compulls in Amazon SES's authorized ranges;include:sendgrid.netdoes the same for SendGrid. Your ESP selection and integration choices directly determine which includes you need.- The 10-DNS-lookup limit is the single most common SPF failure. RFC 7208 caps SPF evaluation at 10 DNS-querying mechanisms (
include,a,mx,ptr,exists,redirect). Nested includes count cumulatively, so two or three ESP includes can silently exceed the cap and produce aPermError. The dedicated guide on fixing SPF PermError from too many DNS lookups walks through counting and flattening. -allvs~allsets the disposition for unlisted IPs.-all(hard fail) instructs receivers to treat unauthorized senders as a failure;~all(soft fail) marks them suspicious but not rejected. Use~allwhile you are still discovering all your senders, then tighten to-allonce your inventory is complete.
SPF authenticates the envelope (MAIL FROM) domain, not the visible From: header. That distinction is the single most misunderstood point in email authentication, and it is precisely what makes DMARC alignment necessary. When your ESP sends on your behalf, the envelope sender is frequently a provider-controlled bounce domain such as bounces.amazonses.com rather than your own domain. SPF will happily pass for that provider domain — the IP is authorized — yet a human reading the message sees you@yourdomain.com in the From header. SPF alone therefore proves nothing about the domain the recipient actually trusts. To close that gap, configure a custom Return-Path (also called a custom MAIL FROM) at your ESP so the envelope domain becomes a subdomain you control, like mail.yourdomain.com, which then aligns with your From domain for DMARC. Without that step, you depend entirely on DKIM for alignment, and a single forwarder that breaks the DKIM signature leaves the message with no aligned, passing mechanism at all.
SPF records also have practical length limits. A single TXT record string is capped at 255 characters, and the full record is capped at 512 octets in older resolvers; long flattened records may need to be split into multiple quoted strings within one DNS record. Keep the record lean — every redundant mechanism is both a lookup you cannot afford and a character you may not have room for.
DKIM: Cryptographically Signing the Message
DomainKeys Identified Mail attaches a digital signature to outgoing mail. Your ESP holds a private key and signs a canonicalized hash of selected headers plus the body; you publish the matching public key in DNS under a selector. Receivers fetch the public key, recompute the hash, and confirm the message is unmodified and genuinely from the domain.
; DKIM public key published at ._domainkey. (TXT)
; The selector lets you rotate keys and run multiple signers (e.g. one per ESP).
s1._domainkey.yourdomain.com. IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA..."
; | | |
; | | +-- base64 public key (truncated); Amazon SES/SendGrid generate this
; | +-- key type, RSA
; +-- DKIM version
The signing header the ESP injects looks like this:
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yourdomain.com;
s=s1; h=from:to:subject:date; bh=; b=
; d= is the signing domain (must align with From for DMARC); s= is the selector
; h= is the signed header list; bh= is the body hash Gmail/Outlook recompute and compare
Practical guidance:
- Use 2048-bit keys. 1024-bit RSA keys still validate but are considered weak; Gmail and Microsoft 365 prefer 2048-bit, and some receivers down-weight 1024-bit signatures. The only constraint is that a 2048-bit public key may need to be split across multiple
TXTstrings because of DNS 255-character chunking — most DNS providers handle this automatically. - Let the ESP sign. Amazon SES (Easy DKIM), SendGrid, and Postmark all generate the key pair and provide the exact CNAME or TXT records to publish. SES typically uses three CNAME records pointing back into the
amazonses.comzone so it can rotate keys on your behalf. - Selectors enable multiple signers and rotation. Running
s1._domainkeyfor SES andsg._domainkeyfor SendGrid lets two providers sign the same domain without colliding. Rotation is then simply publishing a new selector, switching the ESP to sign with it, and retiring the old record once no in-flight mail still references it.
DKIM has one decisive advantage over SPF: it survives forwarding. Because the signature travels inside the message and covers a hash of the headers and body, a forwarder that relays the message unchanged preserves a valid, aligned DKIM signature even though SPF has broken (the connecting IP is now the forwarder's). This is why a robust authentication posture never relies on SPF alone — DKIM is what keeps DMARC passing through mailing lists and corporate forwarders. The exception is any intermediary that modifies the body or signed headers: a list server that appends an unsubscribe footer changes the body, the recomputed bh= body hash no longer matches, and DKIM fails. For those legitimate-but-modifying paths, ARC (Authenticated Received Chain) preserves the original authentication results across hops, and most large receivers honor it.
The signed-header list (h=) deserves attention. Sign at least from, to, subject, and date; over-signing volatile headers a relay might add or reorder can cause spurious failures, while under-signing leaves the message open to header tampering. Most ESPs choose a sensible default, but verify it if you see intermittent dkim=fail on otherwise-unmodified mail.
DMARC: Alignment and Policy
DMARC ties SPF and DKIM to the domain a human actually sees in the From: header, and tells receivers what to do on failure. It requires alignment: SPF passes for DMARC only if the envelope domain matches the From domain (relaxed alignment allows subdomains); DKIM passes for DMARC only if the signing d= domain matches the From domain. A message passes DMARC if either SPF or DKIM verifies and aligns.
; DMARC policy published at _dmarc. (TXT)
_dmarc.yourdomain.com. IN TXT "v=DMARC1; p=none; rua=mailto:dmarc-agg@yourdomain.com; ruf=mailto:dmarc-forensic@yourdomain.com; sp=none; adkim=s; aspf=s; pct=100"
; | | | | | | | |
; | | | | | | | +-- apply policy to 100% of mail
; | | | | | | +-- strict SPF alignment
; | | | | | +-- strict DKIM alignment
; | | | | +-- subdomain policy (inherits p if omitted)
; | | | +-- forensic/failure reports (RFC 5322 format), few receivers send these
; | | +-- aggregate XML reports; Google/Yahoo/Microsoft send daily rollups here
; | +-- policy: none (monitor) -> quarantine -> reject
; +-- DMARC version, must be first
The p= policy moves through three stages: p=none (monitor only, no action), p=quarantine (failing mail goes to spam/Junk), and p=reject (failing mail is bounced). The rua aggregate reports are how you discover every system sending as your domain before you tighten the policy. Because moving to enforcement can break legitimate mail routed through forwarders or unaligned third parties, follow the staged process in configuring a DMARC policy from p=none to p=reject rather than jumping straight to enforcement.
A subtlety that bites high-volume senders: alignment mode. The aspf and adkim tags control whether alignment is s (strict — domains must match exactly) or r (relaxed — a subdomain of the organizational domain is accepted). Relaxed is the default and is correct for most setups, because it lets a From: you@yourdomain.com message pass on a DKIM signature with d=mail.yourdomain.com. Use strict alignment only when you specifically need to prevent any subdomain from authenticating for the parent — an uncommon requirement that most transactional senders should leave relaxed to avoid self-inflicted failures.
The rua aggregate reports are intentionally privacy-preserving: they contain source IPs and pass/fail counts but no message content, which is why they are safe to collect at scale and form the backbone of any rollout. The ruf forensic reports, by contrast, can include message samples, so few receivers send them and you should not depend on them.
Once DMARC reaches enforcement, it also unlocks BIMI (Brand Indicators for Message Identification), which displays your verified logo next to authenticated mail — covered in its own section below, since it is strictly downstream of getting these three records aligned.
BIMI: Displaying a Verified Logo on Authenticated Mail
Once your domain reaches p=quarantine or p=reject, BIMI (Brand Indicators for Message Identification) lets you publish a record that displays your verified brand logo in the avatar slot next to authenticated mail at Gmail, Apple Mail, Yahoo, and Fastmail. It is the visible payoff for getting authentication right, and receivers ignore it entirely until DMARC is at enforcement — there is no shortcut.
; BIMI record published at default._bimi. (TXT)
; Gmail/Apple require both an SVG logo (l=) and a Verified Mark Certificate (a=).
default._bimi.yourdomain.com. IN TXT "v=BIMI1; l=https://yourdomain.com/bimi/logo.svg; a=https://yourdomain.com/bimi/vmc.pem"
; | | |
; | | +-- VMC: Verified Mark Certificate proving trademark ownership
; | +-- square logo, SVG Tiny PS profile, served over HTTPS
; +-- BIMI version, must be first
The constraints are strict and trip up most first attempts:
- Logo format. The logo must be SVG Tiny Portable/Secure (SVG Tiny PS) — a restricted profile with no scripts, external references, or raster images — and must be square with a solid (non-transparent) background. A general-purpose SVG export from a design tool will be rejected; run it through a BIMI-specific converter.
- DMARC at enforcement with
pct=100. Gmail requiresp=quarantineorp=rejectapplied to 100% of mail. A policy still atp=none, or at quarantine with a reducedpct, yields no logo display. - VMC for Gmail and Apple. A Verified Mark Certificate (issued by a recognized CA against a registered trademark) is mandatory for the logo to appear in Gmail and Apple Mail. Yahoo and some others will show a logo without a VMC, but treat the certificate as required for full coverage.
- Alignment still matters. BIMI displays only on messages that pass DMARC with alignment, so an unaligned-but-passing message that slipped through at
p=nonewill not show the logo even after you publish the record.
Because BIMI is strictly downstream of DMARC, sequence it last: finish the staged enforcement rollout, confirm aggregate reports are clean, then publish the BIMI record and certificate. It is a reward for authentication, never a substitute for it.
Provider and Client Evaluation Constraints
Each mailbox provider weighs the three signals slightly differently. The table below summarizes how the major receivers evaluate authentication.
| Provider | SPF | DKIM | DMARC | Notes |
|---|---|---|---|---|
| Gmail / Google Workspace | Required; ~all accepted, -all preferred |
2048-bit strongly preferred | Enforced for bulk senders since Feb 2024; p=none minimum |
Honors rua; one-click unsubscribe required on bulk mail |
| Outlook.com / Microsoft 365 | Required; PermError treated as fail | Validates and down-weights 1024-bit | Enforces published policy; high-volume enforcement since 2025 | SmartScreen also weighs sender reputation independent of auth |
| Apple Mail / iCloud | Checked at iCloud server, not the client | Validated server-side | Honors published policy | Apple Mail (the app) renders what iCloud already authenticated |
| Yahoo / AOL | Required; aligned SPF or DKIM needed | Validated | Enforced for bulk senders since Feb 2024 | Complaint rate <0.3% required to avoid throttling |
| Corporate gateways (Proofpoint, Mimecast) | Strictly evaluated, PermError = fail | Validated | Often override to stricter local policy | May quarantine on SPF softfail regardless of your ~all |
The takeaway: an SPF PermError is treated as an outright failure by Outlook, Yahoo, and most corporate gateways, so the 10-lookup limit is not academic. And because Apple Mail and iCloud authenticate server-side, there is no client-side fix — the DNS records must be correct.
Rolling Out Authentication: Numbered Pipeline
Deploy authentication in a fixed order so each layer can be verified before the next depends on it.
- Inventory every sender. List every system that sends as your domain: your ESP, Google Workspace for corporate mail, helpdesk and CRM tools, billing platforms. Each one needs an SPF include and ideally its own DKIM selector.
- Publish SPF. Add a single
TXTrecord with the includes for your authorized senders, ending in~allinitially. Confirm the lookup count stays at or below 10. - Enable DKIM at the ESP. Generate 2048-bit keys in Amazon SES, SendGrid, or Postmark and publish the provided CNAME/TXT records. Send a test message and confirm
dkim=passin the received headers. - Publish DMARC at
p=none. Add the_dmarcTXTrecord withruapointing at a monitored mailbox or an aggregate-report processor. Collect at least two weeks of reports. - Read the aggregate reports. Identify any legitimate senders failing alignment and fix them (add includes, enable DKIM, or migrate them onto an aligned subdomain).
- Ramp to enforcement. Move SPF to
-all, then DMARC top=quarantinewith apctramp, thenp=reject. Set the subdomain policysp=rejectto stop spoofing of unused subdomains. - Wire reports into your event pipeline. Feed DMARC
ruadata and bounce signals into your webhook event pipelines so authentication regressions surface as alerts rather than silent delivery loss.
Verifying the Records From the Command Line
Before trusting a preview tool, confirm what DNS actually returns. The three records are queryable directly, and the Authentication-Results header on a delivered test message is the ground truth for how a receiver evaluated them.
# Query each record directly. Run after every DNS change; results should match what your ESP provided.
dig +short TXT yourdomain.com # SPF — expect a single v=spf1 ... line
dig +short TXT s1._domainkey.yourdomain.com # DKIM — expect v=DKIM1; k=rsa; p=... (full 2048-bit key)
dig +short TXT _dmarc.yourdomain.com # DMARC — expect v=DMARC1; p=...
# Send a test to a Gmail and an Outlook address, then inspect the received headers:
# Authentication-Results: mx.google.com;
# spf=pass ... dkim=pass header.d=yourdomain.com ... dmarc=pass (p=NONE)
# Gmail shows this verbatim under "Show original"; Microsoft 365 exposes it under message details.
If dig returns nothing for the DKIM selector, the record was never published or was split incorrectly across TXT strings — the most frequent root cause of dkim=fail (key not found) at Gmail and Outlook.
Debugging: Named Symptoms, Causes, and Fixes
Symptom: spf=permerror in received headers. Cause: SPF evaluation exceeded the 10-DNS-lookup limit, usually from stacked ESP includes. Fix: count your lookups, remove unused includes, or flatten — see the SPF PermError deep-dive. Outlook and corporate gateways treat PermError as a hard fail.
Symptom: dkim=fail (body hash did not verify). Cause: the message body was modified after signing — typically a mailing-list footer, a forwarder, or a gateway that rewrites content, breaking the bh= body hash. Fix: ensure nothing between your ESP and the receiver alters the body; for legitimate forwarders, rely on aligned SPF or ARC instead. Confirm the c= canonicalization is relaxed/relaxed, which tolerates whitespace changes.
Symptom: dkim=fail (key not found) or permerror. Cause: the selector TXT record is missing, truncated, or the public key was split incorrectly across DNS strings. Fix: query <selector>._domainkey.yourdomain.com directly and confirm the full 2048-bit key is returned as one logical record.
Symptom: dmarc=fail despite spf=pass and dkim=pass. Cause: alignment failure — SPF passed for the envelope domain but it differs from the From domain (common when the ESP uses its own Return-Path), and DKIM signed with a d= that does not match From. Fix: configure a custom Return-Path/MAIL FROM subdomain at your ESP so SPF aligns, and set the DKIM d= to your From domain. Relax alignment with aspf=r/adkim=r only if strict alignment is impractical.
Symptom: mail to Gmail throttled despite passing auth. Cause: spam complaint rate exceeded 0.3% or volume spiked without reputation. Fix: authentication is necessary but not sufficient — pair it with bounce and complaint handling to keep complaints below the threshold.
Symptom: BIMI logo does not display despite a published record. Cause: usually DMARC is not at enforcement (p=none, or p=quarantine/p=reject with pct below 100), or the logo is not a valid SVG Tiny PS file, or — for Gmail and Apple Mail specifically — there is no Verified Mark Certificate. Fix: confirm p=quarantine/reject at pct=100, validate the SVG against the SVG Tiny PS profile (square, solid background, no scripts or external refs), and attach a VMC via the a= tag. Remember BIMI only shows on messages that pass DMARC with alignment, so fix any lingering alignment gap first.
Symptom: intermittent dkim=fail only on mail through a mailing list or alias. Cause: an intermediary appended a footer or rewrote a signed header, breaking the body hash, and the receiver does not honor ARC. Fix: rely on aligned SPF for those paths where possible, or accept that DMARC will fail through modifying relays; for list traffic specifically, send from a subdomain whose DMARC policy you keep at p=quarantine rather than p=reject so legitimate list mail is not bounced.
Validation and Deployment Checklist
- SPF
TXTrecord exists, starts withv=spf1, and resolves to 10 or fewer DNS lookups. - SPF terminates in
~allduring rollout and-allonce the sender inventory is complete. - DKIM selector record published; a test message shows
dkim=passwith a 2048-bit key. - DKIM
d=domain matches the visibleFromdomain for DMARC alignment. - DMARC
TXTrecord published at_dmarcstarting withv=DMARC1. ruaaggregate reports are flowing to a monitored mailbox or processor.- A test message to Gmail, Outlook, and Yahoo shows
spf=pass,dkim=pass,dmarc=passin headers. - Subdomain policy
sp=is set to block spoofing of unused subdomains. - Records are stored in version-controlled DNS-as-code, not edited by hand in a console.
Related
- Configuring a DMARC policy from p=none to p=reject — the staged enforcement rollout that avoids breaking legitimate mail
- Fixing SPF PermError: too many DNS lookups — diagnosing and resolving the 10-lookup limit
- ESP selection and integration — how your provider choice determines required SPF includes and DKIM selectors
- Bounce and complaint handling — keeping complaint rates under the 0.3% provider threshold
- Webhook event pipelines — surfacing authentication regressions as alerts