SPF, DMARC, and DKIM Setup Guide: Verify and Fix Mail Auth
Stop Discovering Broken Mail Auth Through Client Complaints
SPF and DMARC feel like a one-time setup, but DNS changes break them silently and repeatedly. Agencies managing multiple client domains are especially exposed: a new email SaaS added to an SPF record, a nameserver migration that drops authentication records, or a DKIM key rotation that misses the publish step. The first sign of failure is almost always a client saying "emails aren't arriving."
This guide covers the correct configuration and verification procedure for SPF, DMARC, DKIM, and MX records — with commands you can run immediately during initial setup, domain handoffs, or routine audits.
Understanding the Four Authentication Types
| Type | Purpose | Where it lives |
|---|---|---|
| MX | Declares the servers that accept inbound email | TXT record at the apex domain |
| SPF | Declares which servers are authorized to send | TXT record at the apex domain |
| DMARC | Specifies what happens when SPF or DKIM fails | TXT record at _dmarc.<domain> |
| DKIM | Cryptographically signs outbound messages | TXT record at <selector>._domainkey.<domain> |
Each type is independent. A valid SPF record does not protect you if the DMARC policy is malformed — email may still land in spam.
SPF: Correct Configuration
Basic syntax
example.com. IN TXT "v=spf1 include:_spf.google.com ~all"
v=spf1— Version tag. Must appear first.include:— Authorizes an external set of sending servers.~all— Soft fail for unauthorized senders (recommended starting point).-all— Hard fail: reject unauthorized senders entirely (stricter enforcement).
Common SPF mistakes
| Mistake | Consequence |
|---|---|
Missing v=spf1 prefix |
Record is not recognized as SPF — effectively disabled |
Two v=spf1 records on the same domain |
RFC 7208 violation — receiving MTAs treat this as permanent failure |
| SPF lookup chain exceeds 10 DNS queries | RFC 7208 limit exceeded — evaluation fails permanently |
No all terminal |
Policy is incomplete — sender evaluation is undefined |
Verify SPF with dig
# Extract TXT records starting with v=spf1
dig +short TXT example.com | grep 'v=spf1'
# Check that exactly one SPF record is returned
# Two or more records require immediate remediation
DMARC: Correct Configuration
Basic syntax
_dmarc.example.com. IN TXT "v=DMARC1; p=quarantine; rua=mailto:[email protected]; pct=100"
v=DMARC1— Version tag.p=— Policy:none(monitor only) →quarantine(spam folder) →reject(block). Escalate gradually.rua=— Aggregate report destination as amailto:URI.pct=— Percentage of messages the policy applies to (0–100).
Common DMARC mistakes
| Mistake | Consequence |
|---|---|
Missing p= tag |
Required tag absent — the entire record is invalid |
pct=120 or other out-of-range value |
RFC 7489 violation — some parsers silently ignore the record |
rua=example.com without mailto: |
Malformed URI — reports never arrive |
| Record placed at wrong subdomain | Not queried by receiving MTAs |
Verify DMARC with dig
# Retrieve the DMARC record
dig +short TXT _dmarc.example.com
# Confirm p= tag is present
dig +short TXT _dmarc.example.com | grep 'p='
If p=none, the policy is monitoring-only and no messages are filtered. Once your authentication is stable, step up to p=quarantine, then eventually to p=reject.
DKIM: Correct Configuration
Public key record syntax
selector1._domainkey.example.com. IN TXT "v=DKIM1; k=rsa; p=MIGfMA0GCSq..."
v=DKIM1— Version tag.k=rsa— Key algorithm (can usually be omitted; defaults to RSA).p=— Base64-encoded public key. An emptyp=means the key has been revoked.
Finding your selector name
The selector name depends on which email sending service you use:
| Service | Common selector |
|---|---|
| Google Workspace | google |
| SendGrid | s1, s2 |
| Amazon SES | amazonses |
| Mailchimp | k1 |
# Verify the DKIM public key for selector "google"
dig +short TXT google._domainkey.example.com
# A valid response contains v=DKIM1 and a non-empty p= value
Common DKIM mistakes
| Mistake | Consequence |
|---|---|
| Publishing new selector key but forgetting DNS | All signatures fail for that selector |
| Not removing old selector after rotation completes | Stale records cause confusion; some parsers may match the wrong key |
p= value is empty |
Key is treated as revoked — all signature verifications fail |
Verifying MX Records
# Check MX records and priority values
dig +short MX example.com
# Example output:
# 10 aspmx.l.google.com.
# 20 alt1.aspmx.l.google.com.
If no MX record is returned, or the record still points to a temporary migration host, inbound email will fail. After any domain or DNS migration, confirm the MX records point to the intended mail servers.
Combined Spot-Check Script
Use this during new client onboarding or as part of a periodic audit:
#!/bin/bash
# Usage: ./check-mail-auth.sh example.com [selector]
DOMAIN="${1:?Provide a domain name}"
SELECTOR="${2:-google}"
echo "=== MX ==="
dig +short MX "$DOMAIN"
echo "=== SPF ==="
dig +short TXT "$DOMAIN" | grep 'v=spf1'
echo "=== DMARC ==="
dig +short TXT "_dmarc.$DOMAIN"
echo "=== DKIM (selector: $SELECTOR) ==="
dig +short TXT "${SELECTOR}._domainkey.$DOMAIN"
Once you have confirmed the output looks correct, register each type in Miterl so future changes are caught automatically.
Move From Manual Checks to Continuous Monitoring
Even a correct setup breaks again at predictable moments:
- Adding a new email SaaS causes the SPF lookup count to exceed 10.
- A DNS zone migration drops authentication records that were not in the export.
- An automatic DKIM key rotation at the ESP does not update the published TXT record.
Manual verification catches the state at one point in time. Continuous monitoring catches changes the moment they happen.
Miterl monitors MX, SPF, DMARC, and DKIM records using the same API you use for HTTP and SSL monitors:
# Register a DMARC monitor (validates p= tag, pct range, and rua URI format)
curl -X POST https://miterl.com/api/v1/monitors \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "example.com DMARC",
"type": "dmarc",
"url": "example.com",
"interval_seconds": 300
}'
Syntax validation is built in. An SPF record that exceeds 10 lookups, a DMARC record missing p=, or a DKIM key with an empty p= field all trigger a Down alert — not just a missing record. For the full setup walkthrough, see "Monitor SPF, DMARC, DKIM, and MX Records Continuously."
Summary
- SPF: One
v=spf1TXT record at the apex domain, with a confirmedallterminal and a lookup chain under 10 hops. - DMARC: Required
p=tag at_dmarc.<domain>. Start withnone, escalate toquarantinethenrejectas confidence grows. - DKIM: Before rotating a selector, verify the new public key is live in DNS. Confirm the selector at the ESP matches what your DNS serves.
- MX: After any migration, verify MX records point to the intended mail servers — not a temporary hostname from the migration.
After initial setup, shift from manual checks to continuous monitoring so you catch silent breakage before clients do. For domain-level checks at launch, the "Pre-Launch Monitoring Checklist" covers the full set. To understand how mail authentication fits alongside HTTP, DNS, and SSL monitoring, see "Server Monitoring Basics: HTTP, Ping, DNS, and SSL." Feature documentation is at /en/docs, pricing questions are answered in the FAQ, and you can start testing from the free signup.