Skip to content

Complete DNS Setup for Email Sending — The 6 Records You Need

Email deliverability runs on DNS. SPF, DKIM, DMARC, MX, custom-tracking-domain CNAME, BIMI — that's the full setup. This guide walks each in order with the exact records to publish, how AcelleMail verifies them, what each does.

The 6-record full setup

Every robust email-sending domain needs:

Record Purpose Required?
SPF (TXT) Authorize sending IPs Yes — base authentication
DKIM (TXT or CNAME) Cryptographically sign emails Yes — base authentication
DMARC (TXT) Tell receivers what to do if SPF/DKIM fails Yes — base authentication
MX (for return-path / bounce subdomain) Route bounces to AcelleMail If using custom envelope-sender
Tracking domain CNAME (CNAME) Brand the click-redirect Optional (recommended)
BIMI (TXT) Show your logo in inbox Optional (advanced)

This guide walks each.

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

Record 1: SPF (Sender Policy Framework)

Tells receiving servers which IPs are authorized to send from your domain.

Publish at the apex domain (yourdomain.com):

Type:  TXT
Name:  yourdomain.com  (root)
Value: v=spf1 include:amazonses.com include:_spf.mailgun.org -all
TTL:   3600

Includes:

  • include:amazonses.com if using Amazon SES
  • include:_spf.mailgun.org if using Mailgun
  • include:sendgrid.net if using SendGrid
  • include:spf.example.com for any other vendor (check their docs)

-all (hard fail) tells receivers to REJECT messages from any IP not listed. Use ~all (soft fail) if you're still bringing new vendors online; switch to -all once production-stable.

See SPF record deep dive for the full reference + edge cases.

Record 2: DKIM (DomainKeys Identified Mail)

Cryptographically signs your outgoing emails so receivers can verify authenticity.

AcelleMail generates the DKIM keypair when you add a sending domain. Per the verify-domain wizard:

Type:  CNAME
Name:  acellemail._domainkey.yourdomain.com
Value: acellemail._domainkey.acellemail.com  (or your AcelleMail-side selector)
TTL:   3600

The exact CNAME target varies per AcelleMail install — the sending-domain detail page shows yours specifically. Most installs use AcelleMail's auto-generated 1024-bit or 2048-bit keys.

See DKIM key rotation playbook for rotation discipline.

Record 3: DMARC (Domain-based Message Authentication, Reporting & Conformance)

Tells receivers what to do when SPF/DKIM fails for your domain. Plus collects aggregate reports.

Publish at _dmarc subdomain:

Type:  TXT
Name:  _dmarc.yourdomain.com
Value: v=DMARC1; p=quarantine; rua=mailto:[email protected]; ruf=mailto:[email protected]; fo=1; pct=100
TTL:   3600

Key parameters:

  • p= — what to do with failed messages (none = monitor only, quarantine = junk folder, reject = bounce)
  • rua= — where to send aggregate reports (typically [email protected])
  • ruf= — where to send forensic reports (per-failure detail; some receivers don't send these)
  • fo= — what failure types to report (1 = SPF or DKIM fail; s = SPF fail; d = DKIM fail; 0 = both fail)
  • pct= — what percentage of failed messages to apply the policy to (use 100 for full enforcement; useful for staged rollout)

Staged rollout: start p=none for 30 days. Move to p=quarantine once SPF/DKIM pass rate >99%. Move to p=reject for hardest enforcement.

See DMARC enforcement migration for the staged plan.

Record 4: MX for return-path / bounce subdomain (custom envelope-sender)

If you use a custom envelope-sender (e.g. bounce.yourdomain.com), AcelleMail needs an MX record so bounces route correctly:

Type:  MX
Name:  bounce.yourdomain.com
Value: feedback.acellemail.com  (or your install's bounce processor)
Priority: 10
TTL: 3600

Without this, bounce messages get rejected by the receiving server's MX lookup. AcelleMail's sending-domain detail page tells you the exact MX target.

For default vendor envelope-senders (e.g. SES's [email protected]), the MX is on AWS's side — no action needed.

Record 5: Custom tracking domain CNAME

If using a custom click-tracking domain (recommended for brand consistency):

Type:  CNAME
Name:  click.yourdomain.com
Value: track.acellemail.com  (or your install's tracking endpoint)
TTL:   3600

See Custom tracking domain for click URLs for the full setup.

Record 6: BIMI (show your logo in inbox)

After DMARC enforcement is stable, add BIMI:

Type:  TXT
Name:  default._bimi.yourdomain.com
Value: v=BIMI1; l=https://yourdomain.com/bimi/logo.svg; a=https://yourdomain.com/bimi/vmc.pem
TTL:   3600

Required: DMARC at p=quarantine or p=reject. See BIMI setup walkthrough.

Verify everything in AcelleMail

After all 6 records published, the sending-domain detail in AcelleMail shows green chips per auth check:

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.

Click Verify domain to re-check on demand. AcelleMail's dig-check runs against the receiving-server-side perspective (not your local cache), so propagation issues are detected accurately.

Common UI signals + fixes

Symptom Likely cause UI fix
All 4 auth chips Green except DMARC DMARC record published but pass rate <99% Check rua aggregate reports; identify failing source IPs
SPF chip Red after adding a new vendor SPF lookup count exceeded 10 (DNS limit) Combine includes or use SPF flattening (advanced)
DKIM chip Red despite CNAME published DNS propagation pending OR CNAME pointing wrong target dig CNAME acellemail._domainkey.yourdomain.com to verify
MX chip Red on bounce subdomain MX not published or pointing wrong target Check sending-domain detail page for exact MX target
BIMI logo not appearing in Gmail VMC not configured See BIMI VMC cost walkthrough
Different chip states on different campaigns Per-campaign From: domain doesn't match the verified sending domain Use consistent From: domain per sending-server config

Per-vendor SPF includes reference

Vendor SPF include
Amazon SES include:amazonses.com
SendGrid include:sendgrid.net
Mailgun include:_spf.mailgun.org
Postmark include:spf.mtasv.net
Sparkpost include:sparkpostmail.com
Self-hosted Postfix Your sending server IPs (ip4:1.2.3.4)

Combine for multi-vendor:

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

DNS lookup limit: 10. Most senders fit comfortably.

Advanced: SPF flattening, DKIM key length recommendations, DMARC ARC for forwarders

SPF flattening:

If you have many includes (3+ vendors + corporate apps), you can hit the 10-lookup DNS limit. SPF flattening resolves all includes at publish time + republishes as a single record:

# Before:
v=spf1 include:amazonses.com include:_spf.mailgun.org include:sendgrid.net include:spf.mtasv.net -all
# 4 lookups; if any vendor's include has 2-3 sub-includes, you blow the cap

# After (flattened):
v=spf1 ip4:54.240.0.0/18 ip4:13.32.0.0/15 ip4:54.240.36.0/22 ... -all

Tools like ValiMail SPF + Easy SPF auto-flatten + re-publish daily (vendors change their IP ranges). Self-flatten manually = maintenance burden; tool is worth it for 4+ vendor stacks.

DKIM key length:

  • 1024-bit: legacy; still works at all receivers
  • 2048-bit: modern; recommended for new setups
  • 4096-bit: maximum security; some DNS hosts don't allow >2048-bit TXT records

For DKIM-via-CNAME (AcelleMail default), the key length is managed at the AcelleMail side — typically 2048-bit.

DMARC ARC (Authenticated Received Chain):

For forwarding scenarios — when your message is forwarded by a recipient or middleman — the original SPF + DKIM can fail. ARC records the original auth state so the eventual receiver can trust the chain.

ARC-Authentication-Results: i=1; mx.google.com;
       dkim=pass [email protected] header.s=acellemail header.b=...;
       spf=pass [email protected];
       dmarc=pass header.from=yourdomain.com
ARC-Seal: i=1; a=rsa-sha256; t=...; ...
ARC-Message-Signature: ...

AcelleMail handles ARC signing automatically when forwarding scenarios are detected.

Aggregate DMARC report parsing:

DMARC rua= reports arrive at your inbox as XML files (.zip or .gz). Parse via:

  • dmarcian.com (free tier)
  • onDMARC by Red Sift (paid; full visualization)
  • DMARCLY (budget; basic reports)
  • Custom parser (open-source XML libraries)

Reports tell you which IPs sent from your domain and what auth state was — including unauthorized senders trying to spoof your domain.

Multi-tenant DMARC for SaaS:

If your platform sends on behalf of many customers:

Customer A:  _dmarc.customerA.com  → Customer's own DMARC policy
Customer B:  _dmarc.customerB.com  → Customer's own DMARC policy

Each customer manages their own DMARC. Your platform-side SaaS DMARC policy is separate (for emails sent FROM your own platform domain).

Verification automation:

# Daily script: verify all 6 records on all sending domains
domains=$(curl -sH "Authorization: Bearer $TOKEN" \
  "https://acellemail.com/api/v1/admin/sending-domains" | jq -r '.data[].name')

for domain in $domains; do
  spf=$(dig TXT $domain +short | grep -c "v=spf1")
  dkim=$(dig TXT acellemail._domainkey.$domain +short | grep -c "k=rsa")
  dmarc=$(dig TXT _dmarc.$domain +short | grep -c "v=DMARC1")
  bimi=$(dig TXT default._bimi.$domain +short | grep -c "v=BIMI1")

  echo "$domain: SPF=$spf DKIM=$dkim DMARC=$dmarc BIMI=$bimi"
done

Alert if any record drops to 0 (DNS host accidentally removed). DNS-host bugs do happen.

Related articles

18 comments

11 comments

  1. Ahmed
    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 keys, and I'd use separate selector names too even though you don't strictly have to. The DKIM record lives at `selector._domainkey.mail.example.com`, so `s1` on mail.example.com and `s1` on notifications.example.com are already two different DNS records with two different keys. It works. The reason I still name them differently (say `mail1` and `notif1`) is rotation. When you're mid-rotation and staring at DNS, having both subdomains showing `s1` and `s2` is how you end up publishing the wrong public key under the wrong host. Two other things for that split: SPF is per-subdomain. mail.example.com needs its own TXT record, it does not inherit from example.com. Same for notifications.example.com. DMARC at the org level (`_dmarc.example.com`) covers both subdomains by default, so you probably don't need per-subdomain DMARC records. But note relaxed alignment means both subdomains pass against example.com, which is usually what you want for transactional plus marketing. If you want reputation isolation between the two, that's what the subdomain split buys you at the DKIM/SPF layer, not at DMARC. The article only walks through a single sending domain. Subdomain splits come up often enough that I'll add a section on it.
  2. Akira
    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.
  3. Daniel
    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 verify today. Each sending domain gets checked on its own, so with white-label clients you're doing it one domain at a time as they add the SPF/DKIM/DMARC records on their side. Two things that make it less painful in practice. Send the customer the exact record set rather than the article, most of the back and forth is them pasting a host value with the domain appended twice. And expect to re-check, TTL on a fresh record means the first verify attempt often fails for a reason that isn't the record being wrong. A batch re-verify across a customer's domains is a reasonable ask and I don't have a good argument against it. If you open an issue with roughly how many domains you're managing, that helps me judge whether it needs a proper queue job or just a button that loops.
  4. Anna
    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.
    1. Admin
      The nesting part trips up almost everyone, because the limit counts every include your includes pull in, not just the ones you typed. One caveat on flattening though: once you replace an include with literal IPs, you own that list. When the vendor rotates their sending IPs your record silently goes stale and mail starts failing SPF with no warning. If you flatten, either use a service that re-resolves and updates the record for you, or set a reminder to re-check it. Removing unused includes first is usually enough to get back under 10 without taking on that maintenance.
  5. Hùng
    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 part that catches people is that five of the six records will pass a checker while your mail still lands in spam. SPF, DKIM and DMARC are the ones with real teeth, the rest are hygiene. If there's a record you got burned by that isn't in the list, tell me and I'll add it.
  6. Olufemi
    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.
  7. Joel
    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 is the part everyone misses. Your record's TTL of 300 only applies once the record exists in a resolver's cache. Before that, the NXDOMAIN/NODATA answer is cached per the SOA minimum field, and Cloudflare's SOA minimum is 3600, which is exactly the hour you waited. So the rule of thumb is: create the record before you go check it anywhere, because the first failed lookup costs you an hour on every resolver that saw it. dig showing it just means Cloudflare's authoritative servers have it. mail-tester uses its own resolvers, which had already cached the miss. `dig +trace TXT selector._domainkey.yourdomain.com` bypasses caches if you want the real answer during the wait. I'll add a note about SOA minimum vs record TTL to the article, it belongs in the verification section.
  8. Aditi
    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.
    1. Admin
      Vercel's auto-DNS is the one I've seen do this most. It manages the apex as a set, and when it reconciles it can drop TXT records it didn't create, so SPF goes with it. Netlify's DNS has bitten people the same way on apex ALIAS setups. Two things that help: keep SPF on the apex but verify it after any deploy that touches domain config, and don't rely on the provider's UI showing the record. Check what actually resolves with `dig +short TXT yourdomain.com`. If the record is there in the dashboard but not in the answer, it's been reconciled away. The safer fix if you're on Vercel is to move the sending domain off the apex entirely. Use a subdomain like `mail.yourdomain.com` with its own zone at your registrar or Cloudflare. DKIM and DMARC live there fine, and the apex stays whatever the host wants it to be. That also gives you reputation separation between marketing mail and your site. I'll add this as a warning box in the DNS article. The apex-vs-subdomain tradeoff is worth spelling out properly rather than assuming everyone runs their own zone.
  9. Sarah
    Thanks for the explicit cautionary tales. The alignment-vs-pass distinction is exactly where I lost a week last year
  10. Quân
    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 about right, because it depends on the receiver. Gmail and Microsoft don't reject on an SPF fail by itself in practice, they feed it into a score and then let DMARC make the call. Smaller setups running rspamd or a strict milter are where you actually see -all turn into a 5xx bounce. The thing that makes this mostly moot: if you publish DMARC with p=reject or p=quarantine, that policy is what gets enforced, and ~all vs -all barely changes the outcome. The real reason to prefer -all is that it stops SPF from silently passing on forwarded or spoofed paths you didn't intend. If you're hesitant, the safe order is what the article recommends anyway. Stay on ~all, run DMARC at p=none and read the aggregate reports for two or three weeks until every legit sender shows up aligned, then flip to -all and move DMARC up. Don't flip both on the same day, you lose the ability to tell which one broke something.
  11. Lucas
    Easy win: set up dmarcian.com (free tier) to receive your DMARC RUA reports. The first 2 weeks of reports tell you everything you didn't know about who's sending as you...

More in DNS & Domain Setup