If your emails land in spam, get rejected by Gmail or Outlook, or if someone is spoofing your domain, the fix almost always starts in your DNS zone. This guide shows you exactly how to set up SPF, DKIM, and DMARC for your domain, with copy-paste record syntax, verification commands, the misconfigurations that silently break deliverability, and a realistic timeline to move from p=none to p=reject without losing legitimate mail.
This is not a vendor tour. It is the checklist we run internally at devchatt.org whenever we onboard a new sending domain.
What SPF, DKIM, and DMARC Actually Do
The three records answer three different questions. You need all three, because each one alone is trivially bypassed.
| Record | Question it answers | DNS type | Where it lives |
|---|---|---|---|
| SPF | Is this IP address allowed to send for my domain? | TXT | Root of the domain (@) |
| DKIM | Was this message signed with my private key and untampered? | TXT (or CNAME) | selector._domainkey |
| DMARC | What should a receiver do if SPF and DKIM fail, and where do I get reports? | TXT | _dmarc |
The concept most people miss is alignment. DMARC does not just check that SPF or DKIM passed. It checks that the domain that passed matches the domain in the visible From: header. A message can pass SPF for bounces.sendgrid.net and still fail DMARC for yourdomain.com. Keep that in mind, it explains 80% of confusing DMARC failures. What Is SPF, DKIM & DMARC covers this in more depth.

Before You Touch DNS: Inventory Your Senders
Skipping this step is the number one reason DMARC rollouts break invoices, password resets, and newsletters. Build a list first:
- Your main mailbox provider (Google Workspace, Microsoft 365, Zoho, self-hosted)
- Transactional providers (SendGrid, Mailgun, Postmark, Amazon SES, Brevo)
- Marketing platforms (Mailchimp, HubSpot, Klaviyo, ActiveCampaign)
- CRM, helpdesk and ticketing (Salesforce, Zendesk, Freshdesk, Intercom)
- Application servers, cron jobs, WordPress plugins, ERP, monitoring alerts
- Billing and e-signature tools (Stripe, Xero, DocuSign)
Tip: you do not have to guess. Publish DMARC at p=none first (Step 3), collect two weeks of aggregate reports, and the reports will reveal every source sending as your domain, including the ones nobody documented.
Step 1: Create Your SPF Record
SPF syntax explained
SPF is a single TXT record published at the root of your domain. Basic shape:
Host/Name: @ (or yourdomain.com)
Type: TXT
TTL: 3600
Value: v=spf1 include:_spf.google.com ~all
Real world examples:
| Setup | SPF value |
|---|---|
| Google Workspace only | v=spf1 include:_spf.google.com ~all |
| Microsoft 365 only | v=spf1 include:spf.protection.outlook.com -all |
| Microsoft 365 + SendGrid + own server | v=spf1 ip4:203.0.113.25 include:spf.protection.outlook.com include:sendgrid.net -all |
| Domain that never sends email | v=spf1 -all |
Mechanisms you will actually use
ip4:andip6:for your own servers, single IPs or CIDR rangesinclude:to pull in a provider’s authorized rangesaandmxto authorize the hosts behind your A or MX records~all(softfail) or-all(hardfail) as the final catch-all
SPF mistakes that break deliverability
- Two SPF records on the same domain. This is a permanent error and SPF fails entirely. Merge everything into one
v=spf1record. Never publish a second one for a new provider. - Exceeding 10 DNS lookups. Every
include,a,mx,ptrandredirectcounts, and nested includes count too. Over 10 givespermerrorand SPF fails. Remove unused providers or use an SPF flattening service. - Using
+all. This authorizes the entire internet to send as you. Delete it immediately. - Using
ptr. Deprecated, slow, unreliable. Drop it. - Character limit. A single TXT string is capped at 255 characters. Longer records must be split into multiple quoted strings inside the same record, which most DNS panels handle automatically.
- Forgetting subdomains. SPF is not inherited. If
mail.yourdomain.comsends, it needs its own record.

Step 2: Enable and Publish DKIM
DKIM adds a cryptographic signature to each outgoing message. Your provider holds the private key, DNS publishes the public key. The selector lets you run several keys at once, which is exactly what you want with multiple senders.
Record shape
Host/Name: selector1._domainkey
Type: TXT
Value: v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA...
Some providers give you CNAMEs instead, which is preferable because they can rotate keys for you:
Host: s1._domainkey Type: CNAME Value: s1.domainkey.uXXXXXX.wlYYYYYY.eu1.dkim.example-esp.net
Where to generate the key, by platform
| Platform | Where to find DKIM | Typical selector |
|---|---|---|
| Google Workspace | Admin console > Apps > Google Workspace > Gmail > Authenticate email, generate a 2048-bit key, publish it, then click Start authentication | google |
| Microsoft 365 | Defender portal > Email & collaboration > Policies > Email authentication settings > DKIM, publish the two CNAMEs, then enable | selector1, selector2 |
| cPanel hosting | Email > Email Deliverability > Manage, copy the suggested DKIM value | default |
| SendGrid / Mailgun / Postmark / SES | Domain authentication or verified domain wizard, usually CNAMEs | Provider specific |
| Self-hosted (Postfix + OpenDKIM / rspamd) | Generate with opendkim-genkey -b 2048 -s mail -d yourdomain.com |
Your choice |
DKIM mistakes to avoid
- Pasting the key with line breaks or the surrounding quotes. Strip whitespace, keep the base64 blob intact.
- Using 1024-bit keys. Use 2048-bit. Only fall back to 1024 if your DNS provider truly cannot store the longer string.
- Enabling signing before DNS has propagated. Publish the record, wait for it to resolve, then flip the switch in the admin panel.
- Forgetting one sender. Every platform that sends as your domain needs its own selector and its own key.
- Never rotating. Rotate keys once or twice a year, or use provider-managed CNAMEs.
Step 3: Publish DMARC at p=none
Only after SPF and DKIM have been authenticating for at least 48 hours should you add DMARC. Start in monitoring mode. You are collecting data, not enforcing anything yet.
Host/Name: _dmarc
Type: TXT
TTL: 3600
Value: v=DMARC1; p=none; rua=mailto:[email protected]; fo=1; adkim=r; aspf=r
DMARC tags reference
| Tag | Meaning | Recommended value |
|---|---|---|
v |
Version, must come first | DMARC1 |
p |
Policy for the organizational domain | none then quarantine then reject |
sp |
Policy for subdomains | Set sp=reject on non-sending subdomains |
rua |
Address for aggregate (XML) reports | A dedicated mailbox or a report parser |
ruf |
Forensic/failure reports, rarely sent, privacy sensitive | Optional, often omitted |
fo |
When to generate failure reports | 1 |
adkim / aspf |
Alignment mode, relaxed or strict | r (relaxed) unless you have a specific reason |
pct |
Percentage of mail the policy applies to | Useful during rollout, but being deprecated in the DMARCbis update, so do not build a permanent strategy on it |
Receiving reports at another domain
If you send rua to a mailbox on a different domain, that domain must authorize it with a record like:
Host: yourdomain.com._report._dmarc
Type: TXT
Value: v=DMARC1
Published on the receiving domain. Miss this and reports are silently dropped.

Step 4: Verify Every Record Before You Move On
Never assume the DNS panel saved what you pasted. Check from the outside.
Command line checks
# SPF
dig +short TXT yourdomain.com
# DKIM (replace the selector)
dig +short TXT google._domainkey.yourdomain.com
dig +short TXT selector1._domainkey.yourdomain.com
# DMARC
dig +short TXT _dmarc.yourdomain.com
On Windows: nslookup -type=TXT _dmarc.yourdomain.com 8.8.8.8
Check the headers of a real message
Send an email to a Gmail address, open it, choose Show original, and look at the Authentication-Results header. You want to see all three passing and the DMARC domain matching your From::
Authentication-Results: mx.google.com;
spf=pass (google.com: domain of [email protected] designates 203.0.113.25 as permitted sender)
dkim=pass [email protected] header.s=google
dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=yourdomain.com
Reading it correctly: if dkim=pass shows [email protected] instead of your domain, DKIM passed but is not aligned, and it will not help your DMARC score. Fix that in the provider by enabling domain authentication or custom return-path.
Step 5: Read Your DMARC Aggregate Reports
Within 24 to 72 hours you will start receiving zipped or gzipped XML files from Google, Microsoft, Yahoo, Comcast and others. Each covers one day of traffic from one receiver.
What the XML contains
| Element | What to look at |
|---|---|
<source_ip> |
Who sent the mail. Resolve it. Is it yours, a known provider, or an unknown host? |
<count> |
Message volume from that IP. Low counts from odd IPs are often forwarding, not attacks |
<policy_evaluated> |
The DMARC verdict and the action applied |
<auth_results> |
Raw SPF and DKIM results with the domains they authenticated, this is where you spot alignment failures |
<header_from> |
The visible From domain being claimed |
Sample fragment
<record>
<row>
<source_ip>198.51.100.44</source_ip>
<count>312</count>
<policy_evaluated>
<disposition>none</disposition>
<dkim>fail</dkim>
<spf>pass</spf>
</policy_evaluated>
</row>
<identifiers><header_from>yourdomain.com</header_from></identifiers>
<auth_results>
<spf><domain>yourdomain.com</domain><result>pass</result></spf>
<dkim><domain>esp-provider.net</domain><result>pass</result></dkim>
</auth_results>
</record>
Translation: 312 messages passed SPF in alignment, but DKIM was signed by the provider’s own domain, so DKIM alignment failed. The mail still passes DMARC because one aligned mechanism is enough, but if that mail ever gets forwarded, SPF breaks and the message fails. Action: enable custom DKIM signing at that provider.
Parsing reports without going insane
- Manually: unzip and read the XML for very low volume domains
- Free or freemium dashboards: DMARC report analyzers that turn XML into charts and per-source pass rates
- Self-hosted: open source parsers such as parsedmarc feeding Elasticsearch or a database

Step 6: Move From p=none to p=reject Safely
Do not jump straight to enforcement. Here is the schedule we use. Adjust the pace to your sending volume, not to the calendar.
| Phase | Duration | DMARC record | Exit criteria |
|---|---|---|---|
| 1. Monitor | 2 to 4 weeks | v=DMARC1; p=none; rua=mailto:... |
Every legitimate source identified and documented |
| 2. Fix | 2 to 6 weeks | Same record | Aligned pass rate above 97 to 99% for known sources |
| 3. Partial quarantine | 1 to 2 weeks | p=quarantine; pct=25 |
No spike in complaints or missing mail |
| 4. Full quarantine | 2 to 4 weeks | p=quarantine |
Reports stable, failures are only spoofing or forwarding |
| 5. Reject | Permanent | p=reject; sp=reject |
Keep monitoring reports monthly |
Final target record:
v=DMARC1; p=reject; sp=reject; rua=mailto:[email protected]; fo=1; adkim=s; aspf=s
Only tighten to strict alignment (adkim=s; aspf=s) once you are certain no provider signs with a subdomain that you rely on. wpmailsmtp.com goes into the numbers.
Do not forget your parked and non-sending domains
Old brands, typo domains and internal-only domains are prime spoofing targets. Lock them down on day one, no monitoring period needed:
yourolddomain.com TXT v=spf1 -all
*._domainkey.yourolddomain.com TXT v=DKIM1; p=
_dmarc.yourolddomain.com TXT v=DMARC1; p=reject; rua=mailto:[email protected]
Troubleshooting: Common Failures and What They Really Mean
| Symptom | Likely cause | Fix |
|---|---|---|
spf=permerror |
More than 10 DNS lookups, or two SPF records | Merge records, remove dead includes, flatten if needed |
spf=none |
No SPF on the return-path domain | Publish SPF on the bounce domain, not only the From domain |
| DKIM passes but DMARC fails | Signature aligned to the provider domain | Enable branded or custom DKIM at the provider |
| DKIM fails only on some messages | A gateway, signature appliance or mailing list modifies the body after signing | Sign last in the chain, or disable footer injection |
| Forwarded mail fails | SPF breaks on forwarding by design | Rely on aligned DKIM, which survives most forwarding |
| Mailing list mail fails | List rewrites subject or body | Ask the list to enable From rewriting and ARC |
| No aggregate reports arriving | Typo in rua, missing external authorization record, or reports in spam |
Recheck syntax, add the _report._dmarc record, whitelist senders |
| DMARC record not found | Record created as _dmarc.yourdomain.com.yourdomain.com |
Enter only _dmarc in the host field on most panels |

Why This Matters Now
Since the 2024 bulk sender requirements from Gmail and Yahoo, and the enforcement Microsoft applied to high-volume senders on Outlook consumer domains, authentication is no longer optional. Bulk senders need SPF, DKIM, aligned DMARC, one-click unsubscribe and spam complaint rates under 0.3%. Even low-volume senders benefit: an unauthenticated domain gets filtered harder and spoofed more easily.
Once you are at p=reject, you also unlock the next layer: BIMI for your logo in the inbox, plus MTA-STS and TLS-RPT for transport security. Those all require a valid enforcing DMARC policy first.
Quick Recap Checklist
- List every system that sends email as your domain
- Publish one SPF TXT record, under 10 lookups, ending with
~allor-all - Enable DKIM on every sending platform, 2048-bit, one selector per source
- Wait at least 48 hours, then publish
_dmarcwithp=noneand aruaaddress - Verify with
digand by readingAuthentication-Resultsheaders - Analyze aggregate reports and fix unaligned sources
- Step up to
p=quarantine, thenp=rejectwithsp=reject - Lock down parked domains immediately, keep monitoring reports
FAQ
Does DMARC need both SPF and DKIM?
No. DMARC passes if at least one of SPF or DKIM passes and is aligned with the From domain. In practice you should configure both, because SPF breaks on forwarding and DKIM can break when a mailing list modifies a message. Two mechanisms give you redundancy.
How do SPF, DKIM, and DMARC work together?
SPF validates the sending IP against a published list. DKIM validates a cryptographic signature against a published public key. DMARC checks that one of those passed and matches the visible From domain, then tells the receiver what to do on failure and where to send reports.
How do I verify SPF, DKIM, and DMARC?
Use dig +short TXT yourdomain.com, dig +short TXT selector._domainkey.yourdomain.com and dig +short TXT _dmarc.yourdomain.com for the records. Then send a test message to Gmail and read the Authentication-Results header. Online checkers and DMARC analyzers are useful, but header inspection is the ground truth.
How long does DNS propagation take?
Usually minutes to a few hours, depending on your TTL. Lower the TTL to 300 seconds before making changes, then raise it back to 3600 once everything is confirmed working. godaddy.com has a solid rundown on this.
Can I have more than one SPF record?
No. A domain must publish exactly one v=spf1 record. Multiple records cause a permanent error and SPF fails completely. Combine all include and ip4 mechanisms into a single record.
What is a good DMARC record to start with?
v=DMARC1; p=none; rua=mailto:[email protected]; fo=1. It changes nothing about how your mail is handled, and it starts the flow of data you need before enforcing.
Should I use ~all or -all in SPF?
Use ~all while you are still discovering sending sources. Move to -all once your aggregate reports confirm every legitimate sender is authorized. With DMARC at p=reject, the difference matters less, but -all is the stricter and preferred end state.
How long before I can go to p=reject?
Most organizations need 4 to 12 weeks. Small domains with a single provider can do it in two weeks. The gating factor is not time, it is whether your aggregate reports show a consistent aligned pass rate for every legitimate source.
Do subdomains inherit SPF and DKIM?
No. SPF and DKIM must be published per subdomain that sends mail. DMARC is the exception: subdomains inherit the organizational domain policy unless you override it with the sp tag.
Need a second pair of eyes on your DNS zone before flipping to enforcement? The devchatt.org team reviews sending infrastructure and DMARC rollouts every week. Get in touch.
