How-To

How to Set Up SPF, DKIM, and DMARC (Step-by-Step)

A hands-on guide to configuring SPF, DKIM, and DMARC records in DNS. Includes example TXT values, provider-specific tips for Cloudflare and Route 53, a staged DMARC rollout plan, and verification with MXToolbox and mail-tester.

Sohail HussainSohail Hussain13 min read

You'll add three DNS TXT records to authenticate your sending domain: SPF lists who can send on your behalf, DKIM cryptographically signs each message, and DMARC tells receivers what to do with messages that fail. This guide walks through each record with example values, provider screenshots, and a staged DMARC rollout that won't break legitimate mail.

Since February 2024, Google and Yahoo require SPF, DKIM, and DMARC on every domain sending more than 5,000 messages per day to their users (Google Email Sender Guidelines, 2024). Unauthenticated mail either lands in spam or gets rejected outright; Yahoo's Sender Hub documentation reports that fully authenticated senders see roughly 10% higher inbox placement than those missing any of the three.

Table of contents

Before you start

You'll need four things in front of you before opening a terminal:

  1. Admin access to your domain's DNS zone (Cloudflare, GoDaddy, Route 53, Namecheap; wherever your nameservers point).
  2. Credentials for your sending platform (Mailneo, Google Workspace, Microsoft 365, SendGrid, Postmark, etc.).
  3. A test inbox on a major provider (Gmail and Outlook.com both work; you'll send yourself a test message to verify).
  4. About 45 minutes of uninterrupted time. Most of that is waiting for propagation; the actual edits take under 10 minutes.

One more thing: if your domain already has an SPF record, don't add a second one. RFC 7208 §4.5 is unambiguous; a domain with two SPF records is treated as having none (RFC 7208, IETF). Check what's there first. You'll merge, not duplicate.

Step 1: set up SPF

SPF (Sender Policy Framework) is a TXT record that lists the IP addresses and hostnames allowed to send email for your domain. Receivers look up the record, compare the sending IP to the list, and decide whether the mail is authorized. See our full explainer on SPF if you want the theory; otherwise, let's configure it.

1.1 Inventory your senders

Before you write a single include, list every service that sends email from your domain. Typical culprits: your marketing platform (Mailneo, Mailchimp, Klaviyo), transactional provider (Postmark, SendGrid, SES), Google Workspace or Microsoft 365, CRM tools (HubSpot, Salesforce), support desk (Zendesk, Intercom), and anything else hitting your customers' inboxes. Missing one here is the single most common cause of DMARC failures later (see the DMARC glossary entry for why).

1.2 Generate the record

For a domain sending via Google Workspace plus Mailneo, the record looks like this:

v=spf1 include:_spf.google.com include:spf.mailneo.co ~all

Each include: pulls in that provider's authorized IPs. ~all means "softfail anything not in the list"; start here rather than -all (hardfail), which rejects outright. You can tighten to -all once you're confident nothing legitimate is outside the record.

If you don't know your provider's include string, use our SPF generator; it covers the 40 most common ESPs. For an example record with three senders (example.com):

example.com.    IN  TXT  "v=spf1 include:_spf.google.com include:mailgun.org include:spf.mailneo.co ~all"

1.3 Watch the 10-lookup limit

Here's the gotcha that breaks SPF for big senders. RFC 7208 caps the number of DNS lookups during evaluation at 10; exceed it and the record returns PermError, which DMARC treats as a failure (RFC 7208 §4.6.4). Every include:, a, mx, ptr, or exists counts; nested includes count too. A record with include:_spf.google.com (which itself chains to three more includes) already burns four lookups before you've added anything else.

If you're hitting the ceiling, SPF flattening services (EasyDMARC, PowerDMARC) can collapse the chain into a static IP list. The tradeoff: you'll need to refresh the flattened record whenever an ESP rotates IPs.

1.4 Publish the record

Log into your DNS provider and add a TXT record at the root of your domain (@ or leave the name field blank, depending on the UI):

[SCREENSHOT: Cloudflare DNS dashboard showing the "Add record" dialog with Type=TXT, Name=@, Content=v=spf1 include:_spf.google.com ~all, TTL=Auto]

Provider-specific notes:

  • On Cloudflare, go to DNS → Records → Add record → TXT. Leave Proxy status off (Cloudflare's proxy doesn't apply to TXT records).
  • On GoDaddy, open DNS Management → Add → TXT. Host = @, TXT Value = your record, TTL = 1 Hour.
  • On AWS Route 53, go into Hosted zones → your zone → Create record → TXT. Wrap the value in double quotes.
  • On Namecheap, open Advanced DNS → Add New Record → TXT Record. Host = @, Value = your record.

Save, then wait. DNS propagation typically takes 5–15 minutes, but Cloudflare documents up to 48 hours in edge cases. Verify with dig TXT example.com +short or MXToolbox's SPF check.

Step 2: set up DKIM

DKIM (DomainKeys Identified Mail) signs the message headers and body with a private key; receivers fetch your public key from DNS and verify the signature hasn't been tampered with. RFC 6376 is the spec (IETF, 2011); our DKIM overview covers the concept in plain English.

2.1 Get the public key from your sending platform

Each platform generates its own DKIM keypair. You never handle the private key (that stays on the platform's servers); you only publish the public half as a TXT record. Where to find it:

  • Mailneo: Settings → Sending Domains → Add Domain → copy the DKIM value.
  • Google Workspace: Admin console → Apps → Google Workspace → Gmail → Authenticate email → Generate new record (use 2048-bit).
  • SendGrid: Settings → Sender Authentication → Authenticate Your Domain.
  • Postmark: Servers → Sending → DKIM → View DKIM Settings.

Always pick 2048-bit keys if the platform offers a choice. M3AAWG's Sender Best Common Practices recommends 2048 as the minimum; 1024-bit keys are considered weak and some receivers flag them. If you're stuck with a 1024-bit legacy key (some providers still default to it), rotate within 6 months.

2.2 Publish the selector record

DKIM records live at a "selector" subdomain; this lets you rotate keys without breaking the old signature. The TXT record name looks like selector1._domainkey.example.com, and the value is something like:

selector1._domainkey.example.com.  IN  TXT  "v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAw2... (base64-encoded public key, usually 200+ chars)"

Most DNS UIs will split values over 255 characters into multiple quoted strings automatically; the standard allows this.

[SCREENSHOT: mail-tester.com result page showing a 10/10 score with SPF, DKIM, and DMARC all green-checked]

Need a hand generating the selector? Our DKIM generator outputs both the selector name and the TXT value based on your domain.

2.3 Verify DKIM signing end-to-end

Send a test email from your platform to a Gmail address you control. Open the message, click the three-dot menu → Show original. Under "DKIM:" you should see PASS with domain example.com. If it says NEUTRAL or FAIL, the public key didn't match; re-check you pasted the full value (no trailing newlines, no truncation).

Google's Postmaster Tools will show DKIM authentication rates for your domain once you verify ownership; aim for 100%.

Step 3: set up DMARC

DMARC (Domain-based Message Authentication, Reporting & Conformance) ties SPF and DKIM together and tells receivers what to do with failing mail. Without DMARC, receivers guess; with it, you dictate policy. RFC 7489 defines it (IETF, 2015); for the comparison view, see SPF vs DKIM vs DMARC.

3.1 Publish a monitoring-only policy

Never start with enforcement. Start with p=none, which tells receivers to deliver as normal but send you aggregate reports. The record name is _dmarc.example.com:

_dmarc.example.com.  IN  TXT  "v=DMARC1; p=none; rua=mailto:dmarc@example.com; ruf=mailto:dmarc@example.com; fo=1; adkim=r; aspf=r; pct=100"

Breakdown:

  • p=none: monitor only, no enforcement.
  • rua: where aggregate (XML) reports go; point to a mailbox you actually read.
  • ruf: forensic reports (individual failed messages); optional, and Gmail doesn't send them.
  • adkim=r / aspf=r: relaxed alignment. "Relaxed" means the subdomain of the authenticated domain counts as aligned; "strict" (s) requires exact match. Start with relaxed.
  • pct=100: apply policy to 100% of mail. You'll change this in step 3.3.

A quick word on alignment, because it trips people up. Relaxed alignment means mail.example.com counts as aligned with example.com; strict means only example.com itself does. If you send transactional mail from notifications.example.com and marketing from example.com, relaxed keeps both authenticated under the same DMARC policy. Strict forces each subdomain to authenticate separately; useful if you're isolating brands, painful otherwise. The RFC 7489 default is relaxed precisely because most real senders need it.

Staged DMARC rollout at a glance:

StagePolicypct=What receivers doTime in this stage
1. Monitorp=none100Deliver every message; send you aggregate XML reports.2–4 weeks, until reports show every legitimate sender passing.
2. Soft enforce (ramp)p=quarantine10 → 25 → 50 → 100Route failing mail to spam; recipient can still retrieve it.~1 week at each percentage level; watch reports for collateral damage.
3. Hard enforcep=reject100Bounce failing mail at SMTP; nothing reaches the inbox.Ongoing. This is the end state.

Use our DMARC generator if you want the tag reference built in.

3.2 Read the reports for 2–4 weeks

Aggregate reports arrive daily as XML attachments from every major receiver. They're painful to read raw; pipe them into a visualizer like DMARC Analyzer or Postmark's free DMARC Weekly. You're looking for:

  • Sources you recognize (Google, Mailneo) passing with high volume.
  • Sources you don't recognize (sketchy forwarders, forgotten SaaS tools) failing.
  • Legitimate sources failing because their SPF include is missing from step 1.

Fix the failures before moving to enforcement. Skipping this step is how companies accidentally null-route their own payroll notifications.

One underrated use of the monitoring phase: it surfaces shadow IT. If a marketing team signed up for a scheduling tool two years ago and forgot about it, that tool's IPs will show up in your reports failing authentication. Now's the time to either add them to SPF or shut down the account.

3.3 Stage the rollout: none → quarantine → reject

Once your legitimate sources are passing at ~99%, step up gradually. Use the pct= tag to ramp:

# Week 3–4: 10% of failing mail goes to spam
v=DMARC1; p=quarantine; pct=10; rua=mailto:dmarc@example.com; adkim=r; aspf=r

# Week 5–6: 50%
v=DMARC1; p=quarantine; pct=50; rua=mailto:dmarc@example.com; adkim=r; aspf=r

# Week 7+: 100% quarantine
v=DMARC1; p=quarantine; pct=100; rua=mailto:dmarc@example.com; adkim=r; aspf=r

# Week 10+: full reject (only after quarantine has been clean for 2+ weeks)
v=DMARC1; p=reject; pct=100; rua=mailto:dmarc@example.com; adkim=r; aspf=r

At p=reject, receivers bounce failing mail at the SMTP layer; there's no spam folder recovery. That's the goal, but only when you're sure nothing legitimate will fall through.

Data from the Global Cyber Alliance's DMARC deployment tracker shows that among domains that have published DMARC, only about 35% have progressed to p=reject; most get stuck at p=none because no one reads the reports. Don't be that domain.

[MY EXPERIENCE: Describe the most common DNS setup mistake you've watched customers make (duplicate SPF records? missing include for their CRM? premature jump to p=reject?), how you caught it, and how long propagation typically took in your case.]

Step 4: verify everything is working

Three checks. Run all three before calling it done.

4.1 Check DNS with MXToolbox

Visit mxtoolbox.com/SuperTool.aspx and run spf:example.com, dkim:selector1._domainkey.example.com, and dmarc:example.com. Each should return the record you published with no warnings. MXToolbox also flags SPF lookup counts over 10; watch for that yellow banner.

4.2 Send-and-check with mail-tester

mail-tester.com gives you a disposable address; send a real campaign (or test message) to it from your platform. You'll get a score out of 10 with per-check breakdowns. Anything under 9/10 shows you exactly what's missing; authentication issues light up in red.

4.3 Inspect headers in Gmail

Send yourself a test. In Gmail: three-dot menu → Show original. Near the top:

Authentication-Results: mx.google.com;
       dkim=pass header.i=@example.com;
       spf=pass (google.com: domain of sender@example.com designates 192.0.2.1 as permitted sender);
       dmarc=pass (p=QUARANTINE sp=QUARANTINE) header.from=example.com

Three pass results; you're done. If any say fail, temperror, or neutral, go back to the relevant step.

Google's Postmaster Tools and Microsoft's SNDS give you ongoing visibility once you verify domain ownership. Check weekly for the first month.

Key takeaways

  • All three records (SPF, DKIM, DMARC) are required by Google and Yahoo as of February 2024 for any domain sending over 5,000 daily messages to their users.
  • SPF has a hard 10-DNS-lookup limit; exceed it and the record returns PermError, which counts as a DMARC failure.
  • DKIM keys should be 2048-bit; 1024-bit is legacy and some receivers flag it.
  • DMARC rollout is staged: p=none (2–4 weeks of monitoring) → p=quarantine with increasing pct=p=reject. Skipping stages breaks legitimate mail.
  • DNS propagation is typically 5–15 minutes but can take up to 48 hours; verify with dig before assuming something's broken.
  • Alignment mode (adkim, aspf) defaults to relaxed (r); keep it there unless you have a specific reason to require exact-match alignment.

Frequently asked questions

How long does DNS propagation take?

Typically 5–15 minutes for most providers, but the spec allows up to 48 hours based on your TTL setting. Cloudflare and Route 53 propagate fastest (usually under 5 minutes); GoDaddy and older registrars can take longer. Use dig +trace if you suspect a cache issue.

Can I have two SPF records on the same domain?

No. RFC 7208 §4.5 says a domain with multiple SPF records is treated as if it has none. You merge them into a single record with multiple include: statements. This is the single most common SPF mistake; always check existing records before adding a new one.

What's the difference between p=quarantine and p=reject in DMARC?

p=quarantine tells receivers to deliver failing mail to the spam folder; the recipient can still find it. p=reject tells receivers to bounce the message at the SMTP layer; it never reaches the inbox at all. Reject is stricter and the recommended end state, but only after your reports show zero legitimate failures.

Do I need DMARC if I already have SPF and DKIM?

Yes, if you send to Gmail or Yahoo in any volume. Google and Yahoo's 2024 bulk sender rules require a published DMARC policy (minimum p=none) regardless of SPF/DKIM status. DMARC is also what makes SPF and DKIM enforceable; without it, receivers decide case-by-case.

How do I know if I've hit the SPF 10-lookup limit?

MXToolbox's SPF checker shows the count explicitly. Anything at 10 or above returns PermError in strict-checking receivers. If you're close, remove unused include: entries first; if you genuinely need more, use SPF flattening (EasyDMARC, PowerDMARC) to replace the includes with resolved IP ranges.

spfdkimdmarctutorialemail-authenticationdns
Share this article
Sohail Hussain

Sohail Hussain

Founder & CEO at Mailneo

Building Mailneo — AI-powered email marketing for growing businesses.

Ready to supercharge your email marketing?

Start sending smarter emails with AI-powered campaigns. No credit card required.

Get Started Free