Set up SPF, DKIM, and DMARC email authentication. Use when configuring a new sending domain, debugging spam/rejection issues, adding email providers, or preparing for Google/Yahoo/Microsoft bulk sender requirements.
Set up SPF, DKIM, and DMARC so your emails actually reach the inbox.
email-warmup - after authentication is in place, ramp sending volume graduallyprovider-setup - choose and configure an email providerbounce-handling - handle delivery failures and protect your reputationemail-compliance - legal requirements (CAN-SPAM, GDPR, unsubscribe)Three protocols work together. All three are required - not optional - for any domain sending email in 2025+.
| Protocol | What it does | DNS record type |
|---|---|---|
| SPF | Declares which servers can send email for your domain | TXT on domain root |
| DKIM | Cryptographically signs each message to prove it wasn't tampered with | TXT or CNAME on selector subdomain |
| DMARC | Tells receivers what to do when SPF/DKIM fail, and sends you reports | TXT on _dmarc subdomain |
A message passes DMARC if either SPF or DKIM passes and aligns with the From domain. Both should pass, but only one is required.
SPF declares which IP addresses and services are authorized to send email for your domain.
v=spf1 include:_spf.google.com include:sendgrid.net ip4:203.0.113.0/24 -all
This is the single most common SPF failure. Per RFC 7208, SPF evaluation allows a maximum of 10 DNS-querying mechanisms. These count toward the limit:
include, a, mx, redirect, exists - each costs 1 lookupinclude:_spf.google.com costs 1 + however many lookups Google's record contains.These do not count: ip4, ip6, all.
Exceeding 10 lookups causes a permerror. Most receivers treat this as a fail.
v=spf1 TXT record is allowed per domain. Two records cause a permerror. This happens when different teams add records independently.~all forever. Softfail was a transitional mechanism. Use -all (hardfail) once you've confirmed all legitimate sources are listed.ptr mechanism. RFC 7208 says "SHOULD NOT be used" - it's slow, unreliable, and some receivers ignore it.When you hit the lookup limit, flattening replaces include mechanisms with their resolved IP addresses:
include to their managed record.mail.example.com for transactional, news.example.com for marketing). Each subdomain gets its own SPF record with a fresh 10-lookup budget.For DMARC, SPF alignment checks whether the envelope-from domain (Return-Path) matches the header From domain.
bounce.example.com aligns with example.com.DKIM adds a cryptographic signature to each outgoing message. The receiver looks up your public key in DNS to verify it.
Always use relaxed/relaxed (for both header and body). The simple mode requires exact byte matching, which breaks when any intermediate server modifies whitespace, wraps headers, or normalizes line endings - which many do.
Rotate DKIM keys at least annually. Every 6 months is better.
Rotation process:
sel-202501).dig).Never reuse a selector name for a different key.
Include a date or version in the selector name: google2024, sel-202503, resend-v2. This makes rotation visible and avoids collisions. Avoid generic names like default that give no indication of age.
Sign at minimum: From, To, Subject, Date, MIME-Version, Content-Type. Over-signing (listing a header twice in the h= tag) prevents header injection attacks.
Do not use the l= (body length) tag. It allows attackers to append content to signed messages. Gmail penalizes messages that use it.
DMARC ties SPF and DKIM together. It tells receivers what to do when authentication fails and sends you reports about it.
_dmarc.example.com TXT "v=DMARC1; p=reject; sp=reject; adkim=r; aspf=r; rua=mailto:[email protected]; fo=1; pct=100"
| Tag | Purpose | Recommendation |
|---|---|---|
p | Policy for your domain | Progress to reject |
sp | Policy for subdomains | Set to reject explicitly |
adkim | DKIM alignment mode | r (relaxed) |
aspf | SPF alignment mode | r (relaxed) |
rua | Where to send aggregate reports | Always set this |
ruf | Where to send forensic reports | Set with fo=1, but few providers send these |
pct | Percentage of failures to apply policy to | Use for rollout, remove when at 100 |
fo | Failure reporting options | fo=1 (report on any mechanism failure) |
Never jump straight to p=reject. You'll block legitimate email you forgot about - marketing tools, CRM systems, invoicing platforms, internal apps.
Step 1 - Monitor (2-4 weeks minimum):
v=DMARC1; p=none; sp=reject; rua=mailto:[email protected]; fo=1
Collect reports. Identify all legitimate sending sources. Fix their authentication.
Step 2 - Quarantine gradually:
v=DMARC1; p=quarantine; pct=10; sp=reject; rua=mailto:[email protected]; fo=1
Increase pct in steps: 10 -> 25 -> 50 -> 100. Monitor reports at each step.
Step 3 - Reject:
v=DMARC1; p=reject; sp=reject; rua=mailto:[email protected]; fo=1
Without sp=, subdomains inherit the parent domain's policy. If you're at p=none during rollout, all subdomains are unprotected too.
Attackers commonly spoof subdomains (e.g., security.example.com, billing.example.com). Set sp=reject on your org domain even during the p=none monitoring phase, unless you have subdomains actively sending email that aren't authenticated yet.
Always set rua. Without it, you're flying blind. Aggregate reports tell you:
You can receive reports directly via email, but at volume they're hard to parse manually. Services like Postmark DMARC Digests, Valimail, or dmarcian parse them into dashboards.
Google, Yahoo, and Microsoft now enforce authentication requirements for domains sending more than 5,000 messages per day to their users.
| Requirement | Details |
|---|---|
| SPF and DKIM | Both required, not just one |
| DMARC | p=none minimum (Google recommends p=quarantine or higher) |
| Valid PTR records | Forward and reverse DNS must match for sending IPs |
| TLS | SMTP transmission must use TLS |
| One-click unsubscribe | RFC 8058 List-Unsubscribe-Post header for marketing mail |
| Spam complaint rate | Below 0.3% (Google recommends below 0.1%) |
Required for marketing and promotional email (not transactional):
List-Unsubscribe: <https://example.com/unsub?id=abc123>
List-Unsubscribe-Post: List-Unsubscribe=One-Click
The mail client sends an HTTP POST to the URL with body List-Unsubscribe=One-Click. Your endpoint must process this without requiring login, confirmation pages, or any user interaction. Honor within 2 days.
Microsoft announced similar requirements for Outlook.com and Hotmail, effective May 5, 2025. SPF, DKIM, and DMARC (p=none minimum) required for high-volume senders. Non-compliant messages go to Junk initially, with future rejection planned.
These are the things that actually break authentication in practice.
The most common real-world issue. When you use SendGrid, Mailchimp, HubSpot, etc.:
bounce.sendgrid.net.sendgrid.net doesn't match example.com.Fix: Configure the provider to use a custom Return-Path on your domain (e.g., em1234.example.com). Most providers call this "domain authentication" or "authenticated sending domain." Then add their SPF include to that subdomain's record.
When mail is forwarded (e.g., [email protected] to [email protected]):
This is largely solved by ARC (Authenticated Received Chain, RFC 8617), which preserves original authentication results through forwarding chains. Gmail and Microsoft trust ARC from validated intermediaries. As a sender, you don't need to implement ARC - it's handled by intermediaries.
Your app sends as [email protected], but marketing sends as [email protected] through the same provider. DKIM is only configured for example.com. Messages from example.io fail DKIM alignment.
Fix: Configure DKIM signing for every domain you send from. Audit all From addresses across all teams and tools.
You rotate a DKIM key and immediately remove the old public key from DNS. Messages still in transit (queued, greylisted, retried) carry the old signature and fail verification.
Fix: Keep old public keys in DNS for at least 7 days after rotation.
Domains that don't send email should publish denial records to prevent spoofing:
; SPF - no one is authorized to send
example.com TXT "v=spf1 -all"
; DKIM - empty public key = explicitly revoked
*._domainkey.example.com TXT "v=DKIM1; p="
; DMARC - reject everything, still collect reports
_dmarc.example.com TXT "v=DMARC1; p=reject; sp=reject; rua=mailto:[email protected]"
This applies to parked domains, redirect domains, and any domain you own but don't use for email. Attackers target unprotected domains you've forgotten about.
BIMI displays your brand logo next to emails in supporting clients. It requires DMARC p=quarantine or p=reject as a prerequisite.
p=quarantine or p=rejectFor most companies: not yet. The VMC cost, trademark requirement, and lack of Outlook support make it impractical unless you're a large brand with high sending volume. Google reports ~10% improvement in engagement for BIMI-enabled senders.
The biggest value of BIMI is that it forces proper DMARC deployment as a prerequisite.
These protocols prevent TLS downgrade attacks on mail delivery.
Declares that your domain only accepts mail over TLS. Deploy if you want to ensure inbound mail is encrypted.
_mta-sts.example.com TXT "v=STSv1; id=20250301"https://mta-sts.example.com/.well-known/mta-sts.txt: