Skip to content

How to Set Up SPF, DKIM, and DMARC Records — The Basics

New to email sending? These are the 3 DNS records you absolutely need before sending a single campaign. This guide is the basics — what each does, what to publish, how AcelleMail verifies them.

The 3 must-have records

Email deliverability has many factors. The 3 DNS records you MUST have to send legitimate email at any volume:

Record What it does
SPF (TXT) Tells receiving servers which IPs are authorized to send for your domain
DKIM (TXT or CNAME) Cryptographically signs your emails so receivers can verify they're really from you
DMARC (TXT) Tells receivers what to do when SPF or DKIM check fails

Without ALL THREE, your emails go to spam (or worse — blocked entirely).

AcelleMail's verify-domain wizard generates these for you

You don't write SPF / DKIM / DMARC from scratch. AcelleMail's wizard generates the records based on your sending vendor + setup.

Open the sending-domain detail

In AcelleMail's sidebar, Sending → Sending domains. The list shows every domain you've registered with status chips (Verified / Pending / Failed) and per-auth indicators:

Sending domains list

Click into your domain row. The detail page surfaces exactly which DNS records to publish (TXT for SPF, CNAMEs for DKIM, TXT for DMARC) with copy-paste-ready values + current verification state per check:

Sending-domain detail — DNS records + auth status

The sending-domain detail page shows you the EXACT records to publish at your DNS host. Click "Show DNS records" — copy each line, paste into your DNS provider (Cloudflare, Route 53, Namecheap, etc.) as a new record.

After publishing, click Verify domain in AcelleMail. The dig-check confirms each record is reachable + correctly formatted.

What you'll publish

SPF (TXT record at apex)

Type:  TXT
Name:  yourdomain.com  (the root — no subdomain)
Value: v=spf1 include:amazonses.com -all
TTL:   3600

Replace amazonses.com with whatever vendor you use:

  • Amazon SES → include:amazonses.com
  • Mailgun → include:_spf.mailgun.org
  • SendGrid → include:sendgrid.net
  • Postmark → include:spf.mtasv.net

Combine for multi-vendor:

v=spf1 include:amazonses.com include:_spf.mailgun.org -all

-all tells receivers to REJECT mail from any IP not in your SPF. Use ~all while testing; switch to -all once production-stable.

DKIM (CNAME or TXT)

AcelleMail generates a keypair when you add a sending domain. The publish is typically:

Type:  CNAME
Name:  acellemail._domainkey.yourdomain.com
Value: acellemail._domainkey.acellemail.com
TTL:   3600

The selector (acellemail) and target are shown in your sending-domain detail page.

DMARC (TXT at _dmarc subdomain)

Start in monitor mode:

Type:  TXT
Name:  _dmarc.yourdomain.com
Value: v=DMARC1; p=none; rua=mailto:[email protected]
TTL:   3600

Key parts:

  • p=none — monitor only (no enforcement); collect aggregate reports for 30+ days
  • rua=mailto:... — where to send aggregate reports

After 30 days of clean reports, step up to p=quarantine and eventually p=reject. See DMARC enforcement migration for the staged plan.

Verify in AcelleMail

After publishing all 3 records, return to AcelleMail and click Verify domain. The auth chips:

The auth chips on the sending-server detail

Open Settings → Sending servers → click your active server. The toolbar shows the live SPF / DKIM / DMARC chip status:

Sending server detail with auth chips

  • Green chips on all three = receiving servers can confirm you're authorized to send from this domain.
  • Any chip red = receiving servers immediately downgrade reputation. Click Verify domain in the toolbar to walk through the DNS-fix wizard.

All three should turn Green within minutes (depending on DNS propagation speed). If any stays Red:

  • Check the record at your DNS host (typo? wrong record type?)
  • Wait — DNS takes 5-60 minutes typically, up to 24h for stubborn caches
  • Use dig from your terminal to verify the record IS published: dig TXT yourdomain.com +short

Common questions

Question Answer
Can I have multiple SPF records? NO. Receivers accept only one TXT starting with v=spf1. Combine includes.
Where does the DKIM key go on my DNS? Wherever your sending-domain detail page tells you (usually CNAME at {selector}._domainkey.yourdomain.com)
Should p= be none, quarantine, or reject? Start with none (monitor). Move up gradually.
What happens if I skip DMARC? Receivers fall back to general spam filtering; your reputation builds slower
My DNS host doesn't accept TXT >255 chars Split via quoted-string concatenation: "v=spf1 ..." "..." "..."
When can I add BIMI? After DMARC reaches p=quarantine or p=reject — see BIMI setup

Common UI signals + fixes

Symptom Likely cause UI fix
Verify-domain stays Pending Records not yet propagated Wait up to 24h; verify with dig from terminal
SPF chip Red despite published record Syntax error (e.g. ~all typo, missing v=spf1) Re-copy exact value from AcelleMail's wizard
DKIM chip Red despite CNAME CNAME pointing to wrong target Verify selector + target match AcelleMail's wizard
DMARC chip Red TXT record name not _dmarc.yourdomain.com (typo) Re-publish at correct name
All Green but emails still go to spam Reputation/content issue, not auth See Sender reputation monitoring
Records show "MULTIPLE" warning Two SPF records published — receivers reject Delete duplicate; keep one combined record
Advanced: 2048-bit DKIM, DMARC subdomain policies, vendor-specific gotchas

2048-bit DKIM is the modern standard. Some DNS hosts have TXT record character limits — if your DKIM record is >255 chars, you may need to:

  • Switch to CNAME (recommended; AcelleMail's default)
  • Use quoted-string concatenation: "v=DKIM1; k=rsa; p=ABC..." "...DEF"

DMARC subdomain policies via sp=:

v=DMARC1; p=none; sp=reject; rua=mailto:...

p=none (apex policy) but sp=reject (subdomain policy = strict). Useful when you want apex in monitor mode but subdomains in strict.

Vendor-specific SPF gotchas:

Amazon SES (multi-region):  include:amazonses.com   (covers all regions)
SES dedicated IP:           include:amazonses.com   (same — uses shared SES MX)
SendGrid (specific subaccount): include:u123456.sendgrid.net  (per-subaccount)
Mailgun (EU region):        include:_spf.eu.mailgun.org

Multi-vendor SPF combine:

v=spf1 include:amazonses.com include:_spf.mailgun.org include:sendgrid.net -all

Stay under 10 DNS lookups total (see SPF record deep dive for the math).

Per-customer DKIM (SaaS):

For SaaS sending-on-behalf, customers add their own DKIM CNAME. Your platform exposes the CNAME via the sending-domain detail page; customer publishes at their DNS host.

DKIM rotation:

Industry standard: rotate DKIM key every 6-12 months. AcelleMail's admin → Sending → DKIM Key Rotation generates a new keypair + updates the CNAME target. Old keys remain valid for 30 days during transition (so in-flight messages don't fail signature check). See DKIM key rotation playbook.

Test before going live:

mail-tester.com — free service. Send a test email to a generated address; receive a deliverability report:

  • SPF: pass/fail + reason
  • DKIM: pass/fail + reason
  • DMARC: pass/fail + reason
  • Spam score: 0-10 (10 = perfect)

Aim for 9.0+. Below 8.0, fix issues before live sending.

Related articles

19 comments

11 comments

  1. Sofia
    DNS setup is one of those things where you don't know what you don't know. This article should be required reading for anyone running their own mail...
    1. Admin
      The "don't know what you don't know" part is why we wrote it. The one that bites people hardest isn't SPF or DKIM existing, it's alignment: a message can pass SPF and still fail DMARC because the Return-Path domain doesn't match the From domain. Nothing in the DNS record tells you that, you only see it in the aggregate reports. One caveat on this article as it stands, it stops at "publish p=none and read the reports". It doesn't cover moving to quarantine or reject, or the SPF 10-lookup limit that quietly breaks setups once you've added a few vendors. Both are worth their own section and I'd rather add them here than leave people to guess.
  2. Mai
    If you use Vercel or Netlify for the apex, watch out — they sometimes override TXT records via their auto-DNS feature. Bit us once with a stripped SPF record.
  3. Yuki
    The SPF flattening explanation finally made it click for me. I'd been hitting the 10-lookup limit and didn't understand why nesting includes counted.
  4. Isabella
    hit the 10-lookup spf limit when we tried to layer ses on top of an existing google workspace setup. flattened with a tool (spfwizard.com) and it's been fine since. that tool's worth a mention.
    1. Admin
      Flattening works but it's a snapshot. If Google or Amazon rotates an IP range your record silently stops matching, so re-check it on a schedule.
  5. Akira
    Thanks for the explicit cautionary tales. The alignment-vs-pass distinction is exactly where I lost a week last year.
  6. Chen
    Easy win: set up dmarcian.com (free tier) to receive your DMARC RUA reports. The first 2 weeks of reports tell you everything you didnt know about who's sending as you.
    1. Admin
      The RUA aggregate reports are the part people skip, and they're the only reason p=none is worth publishing at all. If you go straight to p=quarantine without reading them for a couple of weeks you'll usually find some forgotten helpdesk or invoicing tool sending as you, and you'll only notice when someone complains their receipts stopped arriving. Worth adding one caveat for anyone copying this: rua=mailto: only works cross-domain if the receiving domain publishes an authorisation record. dmarcian's own docs cover it, but the raw XML dumps into any mailbox you own if you'd rather not use a third party. The article only mentions rua in passing right now, I'll give it its own section.
  7. Nadia
    our dkim rotation broke for 2 days because we updated the active selector first, then waited to delete the old. should be the other way — publish new, wait 48h for cache, switch sending, then remove old.
    1. Admin
      That's the right order, and the article doesn't spell it out. Publish the new selector, let it resolve everywhere, then flip the signing selector, then drop the old TXT once nothing is signing with it. The 48h is really about whatever TTL you set on the new selector record plus resolver slack, so if you drop the TTL to 300 a week before rotation the wait gets a lot shorter. Two days of broken DKIM usually means old mail was still in flight signed with a selector that no longer resolved, which is why the old record has to outlive the switch, not precede it. I'll add a rotation section with the ordering.
  8. Thuỳ
    What's your recommendation for sub-domains? We send from mail.example.com AND notifications.example.com. Same DKIM selector or separate?
    1. Admin
      Separate selectors. There's no benefit to sharing one, and there are two real costs: if you ever need to rotate a key because it leaked or because a provider forces it, a shared selector means rotating both streams at once, and your two streams probably have different lifetimes anyway (marketing vs transactional notifications). Give each its own, something like `s1._domainkey.mail.example.com` and `s1._domainkey.notifications.example.com`, or name them by purpose if that reads better to you later. Two things people trip on with this setup. SPF is per sending subdomain, so `mail.example.com` and `notifications.example.com` each need their own TXT record. The root `example.com` SPF does not cover them. And DMARC at the org level applies to subdomains unless you publish a subdomain policy, so if you set `p=reject` on `_dmarc.example.com` while notifications is still misaligned, it gets rejected. Use `sp=none` on the root record while you're bringing the second subdomain up, then tighten it. Alignment is the part that actually bites. Relaxed alignment (the default) means the DKIM d= just has to share the org domain, so both subdomains pass against a root DMARC fine. If you've set `adkim=s`, the d= must match the From domain exactly, so From on notifications.example.com needs DKIM signed with d=notifications.example.com, not the root. I'll add a subdomain section to the article, it comes up often enough.
  9. Aditi
    How do you handle DNS for clients in white-label setups? The customer would need to add records to their domain — is there a clean way to bulk-verify those?
    1. Admin
      There's no bulk DNS verifier today. Each customer domain gets checked on its own record set (SPF, the DKIM selector, DMARC), and the check is per sending identity, so with 40 white-label clients you're looking at 40 checks. What people usually do instead: keep the DKIM selector and the SPF include the same across all of them, so the record the customer pastes is identical apart from their own domain. Then the only variable is whether they actually added it. If you want it automated, the verification is just a DNS lookup, so you can loop over your domains and check the selector yourself before you ever ask the customer to click anything. A bulk re-verify action on the sending identity list is on the list, I'm not going to promise a date on it. One thing worth saying to clients up front: if they're on a DNS provider that appends the root domain, the DKIM selector record often ends up as selector._domainkey.example.com.example.com. That's the single most common reason a verify fails when the record "looks right" in their panel.
  10. Linh
    quick question: do receivers actually enforce the spf -all hard fail, or do most just downrate? i've heard mixed things and i'm hesitant to switch from ~all.
    1. Admin
      Mixed things is roughly right, because it depends on the receiver. Gmail and Outlook.com don't reject on SPF -all by itself, they feed the result into the overall spam decision, so in practice a -all fail looks a lot like a downrate. Plenty of corporate gateways and smaller providers do reject outright on -all. So the fail is real, it's just not universal. The thing that actually matters more than -all vs ~all is DMARC. Once you're at p=reject, an SPF fail with no DKIM pass gets rejected regardless of which qualifier you used, and DKIM survives forwarding while SPF doesn't. That's the enforcement lever. If you're hesitant, the usual order is: stay on ~all, get DMARC to p=none with rua reporting, read a few weeks of aggregate reports until you're sure every legit sender is in your record, then move to -all and raise DMARC. Switching to -all before you know your full sending inventory is how people break their invoicing system or their CRM.
  11. Marcus
    Worth noting: our DNS provider (Cloudflare) caches negative responses for 1 hour. We added a TXT record, dig showed it, but mail-tester said missing for another 40 minutes. Almost lost our minds. TTL was set to 300 but the parent zone NS cache held.
    1. Admin
      Negative caching bites people constantly and the article doesn't mention it. Your record TTL of 300 only applies once the record exists. Before that, the resolver caches the "no such record" answer according to the SOA minimum, and Cloudflare's SOA minimum is 3600, so anything that asked before you published is stuck for the hour. dig against 1.1.1.1 hits Cloudflare's own resolver and looks fine while mail-tester's resolver is still holding the NXDOMAIN. The practical move is to publish the TXT record first and only run a checker after, never the other way round. If you already poisoned it, `dig +trace TXT selector._domainkey.example.com` goes straight to the authoritative servers and skips the cached negative, which at least tells you the record is really live. I'll add a short section on this to the article, with the SOA minimum vs record TTL distinction spelled out.

More in DNS & Domain Setup