What SPF, DKIM, and DMARC actually do for cold email
Direct answer. SPF, DKIM, and DMARC are the three DNS records every cold email sender must publish before a mailbox provider will trust the message. SPF lists which servers can send from your domain. DKIM cryptographically signs each message. DMARC tells receivers what to do when authentication fails and where to send forensic reports. Without all three aligned, Gmail and Yahoo route cold mail to spam or reject it outright as of February 2024.
Cold email lives or dies on three lines of DNS text. The body copy matters. The cadence matters. None of it reaches an inbox if the domain cannot prove who sent the message. That proof is what SPF, DKIM, and DMARC give the receiving server.
Mailbox providers built these records to fight phishing and spam, not to punish outbound sellers. The side effect is that any rep who skips the setup looks identical to a spammer at the protocol level. Google\u2019s 2024 sender requirements turned that side effect into policy. As of November 2025, non-compliant mail to Gmail addresses now receives permanent 550 SMTP rejections, per Google Workspace Admin Help.
This guide walks through what each record does, how to set it up correctly on the four DNS providers most outbound teams use, and how to verify every layer with command-line tools before the first prospect ever sees the From line. The framework you will follow is what we call the 3-Record Deliverability Stack \u2014 the same sequence Gangly runs inside its outreach writer as a pre-flight check on every new sequence.
The authentication chain at a glance
When a receiving server accepts a message, it runs through a fixed evaluation order. SPF resolves first because it is the cheapest lookup. DKIM verifies the cryptographic signature in the message header. DMARC then reads the From domain, checks alignment between that domain and the SPF or DKIM result, and applies the policy you published. The whole chain runs in under 200 milliseconds. Any single break in the chain triggers the DMARC policy you set \u2014 quarantine, reject, or monitor.
Note. Receivers treat alignment as the trust signal, not the raw pass or fail. SPF can pass while DMARC fails if the bounce domain differs from the From domain. The same applies to DKIM. Always test the full chain end to end \u2014 a green check on a single record means nothing.
Why all three records are mandatory in 2026
The threshold for what counts as a trustworthy sender shifted hard in early 2024. Google and Yahoo published joint sender requirements that took effect February 1, 2024. Microsoft followed in May 2025. The combined effect is that the inbox providers serving roughly 95 percent of B2B mailboxes now enforce the same baseline.
The baseline has three parts for any sender. SPF or DKIM is required on every domain that sends any mail. For bulk senders \u2014 defined by Google as 5,000 or more messages per day to Gmail addresses \u2014 SPF and DKIM both become mandatory, alignment must pass, and DMARC must be published with any enforcement level. Spam complaints must stay under 0.30 percent per Postmaster Tools, and one-click unsubscribe must be implemented in the headers.
Cold email sits in a peculiar position relative to these rules. Most outbound teams send 100 to 1,000 messages per day per inbox, well under the 5,000 bulk threshold. They still get judged by the bulk standard. The reason is simple: cold mail is the highest-risk traffic class because receivers have no prior engagement signal from the recipient. A receiver that flags any single message as spam in a low-volume domain drives the complaint rate above 0.30 percent instantly. The defense is having every authentication signal pre-cleared so the few flags that do happen do not pull down the rest of the queue.
What changed since 2024
Three concrete shifts matter for any outbound stack heading into 2026:
- Hard SMTP rejections replaced silent filtering. A misconfigured DKIM key in 2023 sent your mail to the spam folder. In 2026 it returns a 550 bounce, which most cold email platforms then mark as a hard bounce and remove from the queue. Bad authentication now actively shrinks your list.
- DMARC enforcement spread beyond bulk. Microsoft 365 began honoring published DMARC policies for inbound mail at every volume in 2025. A p=reject on your domain now affects how Microsoft tenants treat your forwarded messages, not just Google ones.
- DKIM key strength became a ranking signal. Enterprise spam filters now downgrade reputation on 1024-bit keys. The Suped deliverability research shows 2048-bit is the working minimum for new domains.
Set up the records correctly once, and the entire cold email cadence you ship runs on a foundation that survives policy tightening. Skip them, and every iteration on subject lines or send timing is wasted effort.
The 3-Record Deliverability Stack (the Gangly framework)
Most deliverability guides treat SPF, DKIM, and DMARC as three independent setup tasks. That framing produces partial wins and quiet failures. The records depend on each other in a strict order. Setting one without the others creates a stack that looks complete but routes mail to spam under load.
The 3-Record Deliverability Stack is a sequence. Each record builds on what the previous one establishes, and each has a verification gate before you move on. Run the stack in this order or restart from the top:
| Layer | Record | What it proves | Verification gate |
|---|---|---|---|
| 1 | SPF | The IP that delivered the message is allowed to send for your domain | dig returns one v=spf1 record, lookup count under 10 |
| 2 | DKIM | The message body and headers have not been altered since signing | Test send shows dkim=pass with the 2048-bit selector |
| 3 | DMARC | The From domain aligns with the authenticated domain, and the policy fits the risk profile | Aggregate reports arrive at the rua address within 24 hours |
The reason the order matters: DMARC alignment cannot pass if SPF or DKIM is broken, and DKIM cannot pass if the signing platform has not been DNS-delegated. Setting DMARC first against a half-configured SPF record under p=reject blackholes every legitimate send. We have seen teams do this and lose two weeks of pipeline before noticing.
Verdict. The 3-Record Deliverability Stack is a sequence, not a checklist. Run SPF, then DKIM, then DMARC. Hold each layer at a passing test before moving down. The whole stack takes 30 to 45 minutes for a clean domain and protects every send for the next 12 months.
SPF setup: the 10-lookup rule and the syntax that passes
SPF is a single TXT record at the root of your sending domain. The record lists which mail servers are allowed to send mail on behalf of that domain. Receivers query it, compare the result to the IP that delivered the message, and pass or fail SPF accordingly.
A minimal SPF record looks like this:
v=spf1 include:_spf.google.com ~all That record authorizes Google Workspace to send mail from your domain and softfails everything else. The pieces matter:
- v=spf1 identifies the record version. There is no v=spf2 \u2014 ignore any guide that mentions one.
- include:_spf.google.com tells receivers to fetch the SPF record at that subdomain and treat its IPs as authorized for your domain too.
- ~all is the softfail qualifier. It tells receivers to accept mail from non-listed IPs but mark it as failed. Use ~all during setup, then move to -all (hard fail) once DMARC is at p=quarantine or p=reject.
The 10 DNS lookup limit
SPF authentication fails entirely if the record requires more than 10 DNS lookups to resolve, per RFC 7208 section 4.6.4. Every include, a, mx, exists, and redirect mechanism counts as one lookup. Nested includes count too.
A typical B2B stack hits the limit fast. Google Workspace plus HubSpot plus Mailgun plus Outreach plus a CRM webhook sender is already eight lookups, and each include can nest two or three deeper. The record passes today, then breaks the moment a vendor adds one IP to their SPF record.
Two fixes work in production:
- SPF flattening. Replace include statements with the resolved IP ranges. Tools like dmarcian and EasyDMARC do this automatically and republish the record when upstream IPs change. The risk is a vendor IP rotation breaks your record between flattening cycles, so check weekly.
- Subdomain delegation. Send transactional mail from mail.example.com, marketing mail from news.example.com, and cold outbound from cold.example.com. Each subdomain gets its own SPF record with its own lookup budget. This is the structurally correct fix and what we recommend for any team sending from more than three platforms.
Watch out. A domain can have only one v=spf1 record. Adding a second record creates a permerror and breaks SPF entirely \u2014 every message fails authentication regardless of which IP sent it. Consolidate every sender into one record using multiple include statements separated by spaces.
Picking the right qualifier
The qualifier on the all mechanism decides what receivers do with unlisted senders:
- +all \u2014 never use. This authorizes the entire internet to send from your domain.
- ?all \u2014 neutral. Useful only during the initial 24 hours of setup.
- ~all \u2014 softfail. Default for the first 30 days. Receivers mark non-listed mail as failed but still deliver it.
- -all \u2014 hardfail. The production setting once DMARC is at p=quarantine or p=reject. Receivers reject non-listed mail outright.
DKIM setup: 2048-bit keys, selectors, and rotation
DKIM signs every outgoing message with a cryptographic signature in the email headers. Receivers look up the corresponding public key in your DNS and verify the signature against it. If the message body or critical headers changed in transit, the signature fails and the receiver knows the message was tampered with.
Unlike SPF, DKIM lives at a selector subdomain rather than the root. The standard format is:
selector1._domainkey.example.com TXT "v=DKIM1; k=rsa; p=<public-key-base64>" The selector name (selector1, google, k1, mxvault, etc.) is arbitrary \u2014 your sending platform chooses it. The receiver pulls the selector from the DKIM-Signature header on the message itself, so the lookup always finds the right key.
Key length: use 2048-bit, never 1024
The minimum acceptable DKIM key length is 1024 bits per the RFC, but 2048-bit is the working standard in 2026. The reasons are concrete:
- 1024-bit keys are within reach of state-funded compute today and will be in commodity range by 2028.
- Enterprise spam filters from Proofpoint, Mimecast, and Microsoft Defender treat short keys as a weak-sender signal and apply a reputation penalty.
- Google\u2019s 2024 requirements specify 1024-bit as the floor but recommend 2048-bit explicitly.
Most cold email platforms generate 2048-bit keys by default. The only consistent blocker is legacy DNS portals (GoDaddy classic, older Network Solutions) that truncate TXT values above 255 characters. Split the key into two quoted strings or migrate to a modern DNS host. The full background on this is in the Suped DKIM technical reference.
The rotation discipline
DKIM keys leak. Sending platforms get breached. Employees keep credentials past their tenure. The defense is rotating keys on a 6 to 12 month cycle with overlap.
The safe rotation sequence:
- Generate a new 2048-bit key with a new selector name (selector2, k2026, etc.) inside your sending platform.
- Publish the new public key to DNS as selector2._domainkey.example.com and wait 30 minutes for propagation.
- Switch the sending platform to sign with selector2.
- Send three test messages and confirm dkim=pass with the new selector in the headers.
- Leave selector1 published for 7 days to validate any in-flight or delayed mail.
- Remove selector1 from DNS only after the 7-day window.
Pro tip. Never edit an existing selector in place. Delete-and-recreate breaks every message still signed with the old key until DNS caches expire \u2014 sometimes 48 hours. New selector, parallel publish, atomic switch. Always.
DMARC setup: from p=none to p=reject without losing mail
DMARC is the policy layer that ties SPF and DKIM together. It does three things receivers care about. It tells them what to do when authentication fails (none, quarantine, or reject). It demands alignment between the From domain and the SPF or DKIM authenticated domain. And it specifies where to send forensic and aggregate reports so the sender can see who is using their domain.
The minimum DMARC record:
_dmarc.example.com TXT "v=DMARC1; p=none; rua=mailto:dmarc@example.com" That record asks receivers to monitor your domain and email aggregate reports to dmarc@example.com daily. It does not enforce anything yet.
The three policies and when to use each
| Policy | Receiver behavior on failure | When to use |
|---|---|---|
| p=none | Deliver normally, send a report | Days 1\u201330: monitor what your real sending sources are |
| p=quarantine | Deliver to spam folder, send a report | Days 30\u201360: once 95 percent of legitimate mail is aligned |
| p=reject | Reject the message at SMTP, send a report | Day 60+: once aggregate reports show zero unaccounted sources |
Most B2B teams should reach p=reject within 60 to 90 days. The 9 to 18 month timelines published by enterprise security vendors apply to organizations with hundreds of legacy sending systems. A clean cold email stack moves faster.
Alignment is the part that bites
DMARC requires that the domain in the visible From header matches the domain SPF or DKIM authenticated. This is called alignment, and it has two modes:
- Strict alignment (aspf=s, adkim=s). The From domain and authenticated domain must match exactly. example.com From with example.com SPF passes. example.com From with mail.example.com SPF fails.
- Relaxed alignment (default). Subdomains count as aligned. example.com From with mail.example.com SPF passes.
Use relaxed alignment unless you have a specific compliance reason for strict. Strict alignment breaks the moment a vendor switches to a subdomain for tracking or DKIM signing.
The reporting addresses
DMARC supports two report types and two report addresses:
- rua \u2014 aggregate reports, sent daily as XML. Use a dedicated mailbox or a third-party parser like Postmark\u2019s free DMARC monitor or dmarcian.
- ruf \u2014 forensic reports, sent per failure with the original message. Most receivers no longer send these for privacy reasons. Skip ruf for cold email setups.
A production DMARC record at p=quarantine looks like:
v=DMARC1; p=quarantine; rua=mailto:dmarc-reports@example.com; pct=100; adkim=r; aspf=r DNS provider walkthroughs: Cloudflare, Route 53, GoDaddy, Namecheap
The records above are universal. The screens you click through to publish them are not. Here is the exact path on each of the four DNS providers most B2B teams use.
Cloudflare
- Log into Cloudflare and pick the domain from the dashboard.
- Click DNS in the left sidebar, then Records.
- Click Add record. Type: TXT. Name: @ (this means the root domain). Content: paste your SPF record verbatim. Set Proxy status to DNS only \u2014 SPF records cannot be proxied. Save.
- For DKIM: click Add record. Type: TXT. Name: selector1._domainkey (Cloudflare auto-appends the domain). Content: paste the DKIM value your sending platform gave you. Save.
- For DMARC: click Add record. Type: TXT. Name: _dmarc. Content: paste your DMARC record. Save.
- Verify in 5 minutes with dig +short txt example.com from any terminal.
AWS Route 53
- Open Route 53 in the AWS console and pick your hosted zone.
- Click Create record. Record type: TXT. Record name: leave blank for SPF (the root). Value: paste your SPF record wrapped in double quotes. TTL: 300. Create record.
- For DKIM: Create record. Record name: selector1._domainkey. Type: TXT. Value: paste the DKIM key, wrapped in double quotes. If the key exceeds 255 characters, Route 53 requires you to split it into two quoted strings on the same line, with a space between them.
- For DMARC: Create record. Record name: _dmarc. Type: TXT. Value: paste the DMARC record in double quotes.
- Route 53 propagates within 60 seconds for new zones. Verify with dig.
GoDaddy
- Sign into GoDaddy, click your profile, then Domain Portfolio.
- Find the domain and click the three-dot menu, then Edit DNS.
- Scroll to the DNS Records section and click Add New Record.
- For SPF: Type TXT. Name @. Value: paste the SPF record without quotes (GoDaddy adds them). TTL 1 Hour. Save.
- For DKIM: Type TXT. Name selector1._domainkey. Value: paste DKIM key. GoDaddy\u2019s classic editor truncates values over 255 characters silently \u2014 use the new editor (Domain Portfolio interface) or migrate the domain.
- For DMARC: Type TXT. Name _dmarc. Value: paste DMARC record. Save.
- Propagation on GoDaddy takes 30 to 60 minutes. Verify with dig before trusting the change.
Namecheap
- Log into Namecheap, click Domain List, then Manage next to your domain.
- Click the Advanced DNS tab.
- Click Add New Record. Type: TXT Record. Host: @ for SPF, selector1._domainkey for DKIM, _dmarc for DMARC. Value: paste the corresponding record. TTL: Automatic.
- Click the green checkmark to save each row before adding the next.
- Namecheap propagates within 30 minutes. Verify with dig.
Note. If your domain registrar and DNS host are different (common with managed registrars like Hover pointing at Cloudflare for DNS), make changes at the DNS host, not the registrar. Editing at the registrar with active nameservers elsewhere does nothing.
Verification commands and what a passing header looks like
Never trust a DNS portal\u2019s green checkmark. Always verify with command-line tools that hit live resolvers. Here is the exact set of commands to run after publishing each record.
SPF verification
# Fetch the SPF record
dig +short txt example.com
# Count includes (each include = 1 lookup, max 10)
dig +short txt example.com | tr ' ' '\n' | grep -c include:
# Use the MXToolbox lookup checker
# https://mxtoolbox.com/spf.aspx A passing SPF record returns one line starting with v=spf1. If you see two lines starting with v=spf1, you have a permerror \u2014 fix immediately.
DKIM verification
# Fetch a specific DKIM selector
dig +short txt selector1._domainkey.example.com
# Send a test message to a Gmail address you control
# Open the message, click the three-dot menu, Show original
# Look for: dkim=pass header.d=example.com The DKIM-Signature header on the message itself includes the selector name (s=selector1) and the signing domain (d=example.com). The d= value must match or be a subdomain of your From domain for DMARC alignment.
DMARC verification
# Fetch the DMARC policy
dig +short txt _dmarc.example.com
# Full chain test
# Send a message to check-auth@verifier.port25.com
# Reply contains a full SPF / DKIM / DMARC report within 30 seconds The MXToolbox DMARC checker renders the same data in a browser if dig is not available. The Mail-Tester service sends back a 10/10 score and flags any missing authentication piece.
What a passing authentication header looks like
Open any received message in Gmail (Show original) and scroll to the Authentication-Results header. A clean cold email sender shows:
Authentication-Results: mx.google.com;
dkim=pass header.i=@example.com header.s=selector1 header.b=AbC123;
spf=pass (google.com: domain of bounce@example.com designates 209.85.220.41 as permitted sender) smtp.mailfrom=bounce@example.com;
dmarc=pass (p=QUARANTINE sp=QUARANTINE dis=NONE) header.from=example.com Three pass values. If any one shows fail, neutral, or temperror, do not send production cold email from that domain until the chain is green.
Seven common mistakes that quietly kill deliverability
Most authentication failures are not caused by skipping a record. They are caused by setting the record wrong in a way that looks correct on the surface. These are the seven we see most often in email deliverability audits, and the fix for each.
- Two SPF records on the same domain. Often happens when one team adds Google Workspace and another adds Microsoft 365 months later. Receivers treat any domain with two v=spf1 records as a permerror, which fails SPF entirely. Fix: merge into one record with both includes.
- SPF over 10 lookups. Common with stacks running Google + HubSpot + Mailchimp + Outreach + a CRM webhook. The record passes today and breaks the next time a vendor adds an IP. Fix: SPF flatten or move marketing to a subdomain.
- DKIM key truncated by the DNS portal. GoDaddy classic and Network Solutions silently chop TXT values at 255 characters, which corrupts a 2048-bit key. Fix: split the key into two quoted strings or switch DNS hosts.
- DKIM-signed by the wrong domain. Some platforms sign with their shared subdomain (s=mxvault, d=sendgrid.net) by default. SPF passes, DKIM passes, DMARC fails alignment because d= does not match From. Fix: enable custom DKIM signing on your domain in the platform settings.
- DMARC at p=reject before DKIM is signing. The fastest way to blackhole every message. Receivers reject mail at SMTP because there is no aligned authenticator. Fix: always start at p=none, watch aggregate reports for 14 days, then escalate.
- No rua reporting address. DMARC is published, but you have no visibility into what is failing or which third party is spoofing your domain. Fix: add rua=mailto:dmarc@example.com from day one and parse the XML weekly.
- Forwarded mail breaks SPF, no DKIM to fall back on. Internal forwarding (sales@example.com forwards to a rep\u2019s personal inbox) rewrites the envelope sender but not the From header. SPF fails. DKIM survives because the signature is on the body. Fix: ensure every outbound mail is DKIM-signed so the chain has a fallback when SPF cannot pass.
Watch out. The most expensive mistake is moving to p=reject too fast. We have seen teams lose 60 percent of their outbound for a week because DMARC enforcement caught a misaligned tool nobody knew was sending. Aggregate reports show you those tools before they cost you pipeline. Always read them for 14 days before escalating policy.
How Gangly runs the 3-Record Stack end to end
Authentication setup is the kind of work reps do once and never check again until deliverability tanks. That is the wrong cadence. The records need verification before every new sequence, every new sending domain, every new ESP integration. Doing that manually does not scale past one rep.
Gangly bakes the 3-Record Deliverability Stack into the workflow as a pre-flight check. Before any sequence ships from Gangly\u2019s outreach writer, the platform runs the SPF, DKIM, and DMARC lookup on the sending domain. If any record is missing, misconfigured, or stale, the sequence will not go live. The check takes 12 seconds.
The same pre-flight runs nightly across every active sending domain in the account. When a vendor changes an SPF include or a DKIM key drifts, the workflow flags it before the next morning\u2019s send window. Reps see a single line: SPF: pass. DKIM: pass. DMARC: pass at p=quarantine. Last verified 4 hours ago.
For BDRs running high-volume outbound, the workflow also tracks the bounce rate per sending domain in 24-hour windows and routes mail to the domains with the cleanest authentication history first. The combination of pre-flight checks, nightly verification, and routing logic keeps domain reputation high without anyone manually opening a DNS portal.
Pair the authentication stack with the rest of the outbound mechanics \u2014 the cold email cadence that protects send velocity, the body copy that earns the reply, and the sequence structure that holds it all together \u2014 and you have a system. Read the email warmup glossary entry if you are spinning up new sending domains, and book a demo when you want to see the pre-flight check live.
By Siddharth Gangal