Setting up email DNS records, one at a time
SPF, DKIM, DMARC and MAIL FROM: what each DNS record looks like, exactly where it goes, and how to check it with dig.
Four DNS records make a domain ready to send marketing email: SPF, DKIM, DMARC, and a custom MAIL FROM subdomain if you use one. Each is one line of text in the right place at your DNS provider. Almost every failure is about the place, not the line. For what each of the first three actually proves before you publish it, see SPF, DKIM and DMARC without the acronym soup.
Key Takeaways
- A domain gets exactly one SPF record. A second one doesn’t add to the first, it invalidates both.
- DKIM is usually a CNAME pointing at your provider’s key, not a raw public key you paste in yourself.
- DMARC goes on
_dmarc.yourdomain.com, but its policy applies to the registrable domain, even when you send from a subdomain.- A custom MAIL FROM subdomain needs its own MX and SPF records, and it’s what lets SPF actually count toward DMARC alignment.
The four records at a glance
| Record | Type | Host / name | What it does |
|---|---|---|---|
| SPF | TXT | root domain (example.com), or a MAIL FROM subdomain if you use one | Lists which servers may send as this domain |
| DKIM | CNAME or TXT | a selector at _domainkey.example.com, e.g. s1._domainkey.example.com | Signs the message so a receiver can tell it wasn’t altered |
| DMARC | TXT | _dmarc.example.com, at the registrable domain | Tells receivers what to do with mail that fails SPF and DKIM, and where to send reports |
| MAIL FROM MX | MX | a subdomain, e.g. mail.example.com | Routes bounce and complaint notifications back to your sending provider |
| MAIL FROM SPF | TXT | the same MAIL FROM subdomain | Authorizes your provider to send as that specific subdomain |
SPF: one record, and only one
SPF (Sender Policy Framework) is a TXT record listing which mail servers are allowed to send as your domain. A receiver checks it against the server that actually delivered the message. You get exactly one SPF record per domain, not one per sending tool.
It goes at your domain’s root, the same place a website’s A record lives, unless you’re authenticating a MAIL FROM subdomain instead (below). Google’s own recommended record for a Workspace-only domain, published at the root, looks like this:
example.com. TXT "v=spf1 include:_spf.google.com ~all"
That’s the exact string Google Workspace documents for a domain sending only through Workspace, entered with the host set to @ (Google Workspace, “Set up SPF”). If you also send through a marketing platform, you add its include: mechanism to that same record, rather than publishing a second one:
example.com. TXT "v=spf1 include:_spf.google.com include:mail.yourprovider.com ~all"
Check it with:
dig +short TXT example.com
You should see exactly one string starting with v=spf1. Two means the failure mode below. A third-party checker like MXToolbox’s SPF tool runs the same lookup and calls out syntax problems in plain language, which is worth running once alongside dig.
DKIM: usually a CNAME, not a key you paste in
DKIM (DomainKeys Identified Mail) signs each outgoing message with a private key your provider holds, so a receiver can verify the signature against a matching public key in your DNS. That public key lives at selector._domainkey.yourdomain.com, where the selector is a short name your provider assigns (RFC 6376, section 3.6.2).
Most providers ask you to publish a CNAME rather than the key itself. SendGrid’s own pattern for domain authentication looks like this:
s1._domainkey.example.com. CNAME s1.domainkey.u1234567.wl123.sendgrid.net.
(Twilio SendGrid, “How to set up domain authentication”) A CNAME means the provider keeps the real key on their own DNS, where they can rotate it without asking you to touch a record again. The alternative is publishing the key directly as a TXT record, which trades that rotation convenience for the reverse property: your DNS record never has to change again, even if the provider swaps the infrastructure signing your mail behind it.
s1._domainkey.example.com. TXT "v=DKIM1; k=rsa; p=MIGfMA0GCSq..."
Check whichever type your provider told you to publish:
dig +short CNAME s1._domainkey.example.com
dig +short TXT s1._domainkey.example.com
A lookup that returns nothing usually means the host field picked up your domain twice, covered below. Your provider’s own dashboard almost always has a verify or check DNS button next to this record specifically, and it’s worth trusting over a generic tool, since it knows what value it’s actually expecting back.
DMARC: the policy record
DMARC (Domain-based Message Authentication, Reporting and Conformance) doesn’t authenticate anything itself. It tells a receiver what to do with mail that fails SPF and DKIM, and asks for reports. It’s a single TXT record at _dmarc.yourdomain.com, and the v and p tags have to appear first, in that order (RFC 7489, section 6.3):
_dmarc.example.com. TXT "v=DMARC1; p=none; rua=mailto:dmarc-reports@example.com"
p=none asks receivers to take no action and just report. p=quarantine asks them to send failing mail to spam. p=reject asks them to refuse it outright. Start at none and read the reports before tightening it, since a false positive under reject bounces real mail rather than filing it.
One placement detail catches people. DMARC applies at the registrable domain, the one you’d register with a registrar, not at whatever subdomain you happen to send from. Sending marketing mail from news.example.com doesn’t move the record: it still goes at _dmarc.example.com, not _dmarc.news.example.com. A sending subdomain inherits the parent’s policy by default; a separate record on the subdomain overrides it, usually weakening it by accident.
dig +short TXT _dmarc.example.com
A DMARC-specific checker (MXToolbox and most mailbox providers’ own postmaster tools have one) will parse the tags for you, which is easier than reading the raw string.
The MAIL FROM subdomain: the record most guides skip
Every message carries two addresses: the From header a recipient sees, and the MAIL FROM address (also called the envelope sender, or Return-Path) that mail servers use to route bounces. Most providers set MAIL FROM to something on their own domain by default, which is fine for delivery but means SPF passes for their domain, not yours.
That gap matters because DMARC’s SPF check requires alignment: the domain SPF authenticated has to match, or share a parent with, the domain in your From address. A provider-owned MAIL FROM domain can’t align with your brand’s From domain, no matter how correctly it’s configured elsewhere. A custom MAIL FROM subdomain, one you own and authenticate yourself, closes that gap.
It needs two records at the subdomain you choose, for example mail.example.com:
mail.example.com. MX 10 feedback-smtp.us-east-1.amazonses.com.
mail.example.com. TXT "v=spf1 include:amazonses.com ~all"
That’s Amazon SES’s own pattern for a custom MAIL FROM domain: the MX record routes bounce notifications back to SES, and the SPF record authorizes SES to send as that subdomain specifically (AWS, “Using a custom MAIL FROM domain”). Any provider that supports a custom MAIL FROM domain publishes the equivalent pair; only the MX target and the SPF include host change.
dig +short MX mail.example.com
dig +short TXT mail.example.com
AWS’s own console shows the pair as Pending, Success, or Failed once it starts checking for the MX record, which is worth watching alongside dig since it’s checking the exact thing SES cares about. This SPF record never goes on your root domain. If your root domain already carries its own SPF record, for Google Workspace or anything else, it stays untouched; the MAIL FROM subdomain gets a completely separate one.
EmailFig generates and checks seven records for a domain you add: three DKIM CNAMEs, this MX and SPF pair on its own MAIL FROM subdomain, a DMARC record, and a tracking CNAME. The exact host fields are shown on one page: see Publish DNS records at your domain provider.
What actually goes wrong
Four failure modes account for most of the “I published it and it still says pending” messages.
Two SPF records on one domain. SPF allows exactly one record per domain. A lookup that returns more than one is a hard failure, permerror, and it breaks the whole check rather than just the newer record (RFC 7208, section 4.5). This usually happens when a second tool tells you to “add an SPF record” and you do, without noticing one is already there. The fix is to merge the two into one record with both include: mechanisms, never to leave two.
A host field with the domain appended twice. Providers ask for the relative host, s1._domainkey, but some registrar dashboards append your domain to whatever you type automatically. Paste the full name into one of those and the record that actually gets published is:
s1._domainkey.example.com.example.com
That record exists, but it isn’t the one anything is checking. If a record looks published but a checker still can’t find it, this is the first thing worth ruling out.
A TTL that makes a fix look like it didn’t work. DNS answers get cached for the record’s TTL, which can run from a few minutes to a day or more depending on your provider’s default. Fix a record and re-check it thirty seconds later, and you may still see the old answer, not because the fix failed but because a resolver somewhere in the path is still holding the previous one. Querying a public resolver directly reflects a change sooner than whatever cache your own machine or ISP is using:
dig @8.8.8.8 +short TXT example.com
A record added at the registrar while DNS is served elsewhere. Buying a domain and hosting its DNS aren’t the same thing, and it’s common to do them in different places, registering at one company and pointing the domain’s nameservers at Cloudflare, Route 53, or somewhere else entirely. Adding a record in the registrar’s own dashboard does nothing if the registrar isn’t where DNS is actually served. Check which one is authoritative before publishing anything:
dig +short NS example.com
Whatever that returns is where every record above has to live.
Checking your work
Run the dig command for whichever row you just published, wait a few minutes, and re-run it after any fix rather than trusting a dashboard’s cached state alone. If EmailFig is checking a domain for you, domain verification statuses explains what Pending, Verified, and Failed mean, and what to do if a verified domain drops back to pending covers the case where a record that used to work stops. Getting all four right is also most of what Gmail and Yahoo’s bulk sender rules ask for: authentication is one of a handful of checks both apply before your mail is even scored for content, and Gmail, Yahoo and Microsoft’s bulk sender rules, quoted directly covers where the three providers agree and where they don’t.
These four records are the technical floor of deliverability, not the ceiling; see email deliverability for people who aren’t experts for how they fit alongside bulk sender rules, bounce and complaint rates, and list hygiene.