email-deliverability
Use this skill when optimizing email deliverability, sender reputation, or authentication. Triggers on SPF record setup, DKIM signing configuration, DMARC policy deployment, IP warm-up planning, bounce handling strategy, sender reputation monitoring, inbox placement troubleshooting, email infrastructure hardening, DNS TXT record configuration for email, and diagnosing why emails land in spam. Acts as a senior email infrastructure advisor for engineers and marketers managing transactional or marketing email.
communication emaildeliverabilityspfdkimdmarcreputationWhat is email-deliverability?
Use this skill when optimizing email deliverability, sender reputation, or authentication. Triggers on SPF record setup, DKIM signing configuration, DMARC policy deployment, IP warm-up planning, bounce handling strategy, sender reputation monitoring, inbox placement troubleshooting, email infrastructure hardening, DNS TXT record configuration for email, and diagnosing why emails land in spam. Acts as a senior email infrastructure advisor for engineers and marketers managing transactional or marketing email.
email-deliverability
email-deliverability is a production-ready AI agent skill for claude-code, gemini-cli, openai-codex, and 1 more. Optimizing email deliverability, sender reputation, or authentication.
Quick Facts
| Field | Value |
|---|---|
| Category | communication |
| Version | 0.1.0 |
| Platforms | claude-code, gemini-cli, openai-codex, mcp |
| License | MIT |
How to Install
- Make sure you have Node.js installed on your machine.
- Run the following command in your terminal:
npx skills add AbsolutelySkilled/AbsolutelySkilled --skill email-deliverability- The email-deliverability skill is now available in your AI coding agent (Claude Code, Gemini CLI, OpenAI Codex, etc.).
Overview
The discipline of ensuring emails reach the recipient's inbox rather than the spam folder or void. Email deliverability sits at the intersection of DNS configuration, cryptographic authentication, sender behavior, and mailbox provider algorithms. This skill covers the full stack - from DNS records (SPF, DKIM, DMARC) through IP warm-up strategy, bounce management, and long-term reputation maintenance. Designed for engineers setting up email infrastructure and marketers diagnosing delivery problems.
Tags
email deliverability spf dkim dmarc reputation
Platforms
- claude-code
- gemini-cli
- openai-codex
- mcp
Related Skills
Pair email-deliverability with these complementary skills:
Frequently Asked Questions
What is email-deliverability?
Use this skill when optimizing email deliverability, sender reputation, or authentication. Triggers on SPF record setup, DKIM signing configuration, DMARC policy deployment, IP warm-up planning, bounce handling strategy, sender reputation monitoring, inbox placement troubleshooting, email infrastructure hardening, DNS TXT record configuration for email, and diagnosing why emails land in spam. Acts as a senior email infrastructure advisor for engineers and marketers managing transactional or marketing email.
How do I install email-deliverability?
Run npx skills add AbsolutelySkilled/AbsolutelySkilled --skill email-deliverability in your terminal. The skill will be immediately available in your AI coding agent.
What AI agents support email-deliverability?
This skill works with claude-code, gemini-cli, openai-codex, mcp. Install it once and use it across any supported AI coding agent.
Maintainers
Generated from AbsolutelySkilled
SKILL.md
Email Deliverability
The discipline of ensuring emails reach the recipient's inbox rather than the spam folder or void. Email deliverability sits at the intersection of DNS configuration, cryptographic authentication, sender behavior, and mailbox provider algorithms. This skill covers the full stack - from DNS records (SPF, DKIM, DMARC) through IP warm-up strategy, bounce management, and long-term reputation maintenance. Designed for engineers setting up email infrastructure and marketers diagnosing delivery problems.
When to use this skill
Trigger this skill when the user:
- Sets up SPF, DKIM, or DMARC records for a domain
- Plans an IP warm-up schedule for a new sending IP or domain
- Diagnoses why emails are landing in spam or being rejected
- Implements bounce handling logic (hard bounces, soft bounces, complaints)
- Monitors or improves sender reputation scores
- Configures DNS TXT records for email authentication
- Evaluates an ESP (Email Service Provider) or sending infrastructure
- Troubleshoots email delivery failures, deferrals, or blocklisting
Do NOT trigger this skill for:
- Email content/copywriting or subject line optimization (use a marketing skill)
- Building email templates with HTML/CSS (use a frontend skill)
Key principles
Authenticate everything, no exceptions - Every sending domain must have SPF, DKIM, and DMARC configured. Missing any one of these is enough for major mailbox providers (Gmail, Outlook) to treat your mail as suspicious. Authentication is table stakes, not a nice-to-have.
Reputation is earned slowly and lost instantly - Sender reputation is built over weeks of consistent, low-complaint sending. A single spam trap hit or complaint spike can tank your reputation overnight. Treat every send decision as a reputation decision.
Bounces are signals, not noise - Every bounce carries information about your list health, infrastructure, or content. Hard bounces must be removed immediately. Soft bounces must be tracked and acted on. Ignoring bounces is the fastest path to blocklisting.
Warm up before you scale up - New IPs and domains have zero reputation. Mailbox providers throttle unknown senders aggressively. A proper warm-up plan ramps volume gradually over 2-6 weeks, proving you are a legitimate sender before asking for high throughput.
Monitor continuously, not reactively - By the time users report "emails aren't arriving," the damage is done. Monitor bounce rates, complaint rates, and inbox placement proactively. Set alerts on thresholds, not symptoms.
Core concepts
Email deliverability is governed by three layers: authentication (proving you are who you claim to be), reputation (proving you send mail people want), and behavior (proving your sending patterns are consistent and trustworthy).
Authentication uses three DNS-based protocols that work together. SPF declares which IPs may send on behalf of your domain. DKIM attaches a cryptographic signature to each message that receivers verify against a public key in your DNS. DMARC ties SPF and DKIM together with a policy that tells receivers what to do when authentication fails - and sends you reports about it.
Reputation is a score maintained by each mailbox provider independently. It is influenced by complaint rates (users clicking "spam"), bounce rates, spam trap hits, engagement signals (opens, clicks, replies), and sending volume consistency. There is no single universal reputation score - Gmail, Outlook, and Yahoo each maintain their own.
Behavior covers sending patterns: volume consistency, warm-up adherence, list hygiene practices, and how you handle bounces and unsubscribes. Sudden volume spikes, sending to stale lists, or ignoring unsubscribe requests all signal spammer behavior to mailbox providers.
Common tasks
Configure SPF
SPF (Sender Policy Framework) declares which mail servers may send email for your domain via a DNS TXT record.
example.com. IN TXT "v=spf1 include:_spf.google.com include:sendgrid.net ip4:203.0.113.5 -all"Rules:
- Only one SPF record per domain (multiple records cause permerror)
- Use
include:for ESPs,ip4:/ip6:for your own servers - End with
-all(hard fail) for production,~all(soft fail) only during testing - Stay under 10 DNS lookups total (each
include:anda:costs one lookup) - Use SPF flattening tools if you hit the 10-lookup limit
The 10-lookup limit is the most common SPF misconfiguration. Each
include:triggers recursive lookups. Monitor withdig TXT example.comand count.
Configure DKIM
DKIM (DomainKeys Identified Mail) signs outgoing messages with a private key. Receivers verify the signature against a public key published in DNS.
selector1._domainkey.example.com. IN TXT "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBA..."Setup checklist:
- Generate a 2048-bit RSA key pair (1024-bit is deprecated)
- Publish the public key as a TXT record at
<selector>._domainkey.<domain> - Configure your mail server or ESP to sign outgoing mail with the private key
- Use a unique selector per ESP so you can rotate keys independently
- Test with
dig TXT selector._domainkey.example.comto verify publication - Rotate keys annually - publish new key, wait 48h for propagation, then switch
If your TXT record exceeds 255 characters, split it into multiple strings within a single TXT record. Most DNS providers handle this automatically.
Deploy DMARC
DMARC tells receivers what to do when SPF and DKIM fail, and sends you reports.
_dmarc.example.com. IN TXT "v=DMARC1; p=reject; rua=mailto:dmarc@example.com; ruf=mailto:dmarc-forensic@example.com; adkim=s; aspf=s; pct=100"Deployment phases:
- Start with
p=none- monitor only, collect reports for 2-4 weeks - Move to
p=quarantine; pct=10- quarantine 10% of failures, increase gradually - Graduate to
p=reject- full enforcement, only after all legitimate mail passes
Key parameters:
p=policy:none(monitor),quarantine(spam folder),reject(drop)rua=aggregate report destination (daily XML reports)adkim=sstrict DKIM alignment (From domain must exactly match DKIM d= domain)aspf=sstrict SPF alignment (From domain must exactly match envelope sender)
Never jump straight to
p=reject. The monitoring phase catches legitimate senders you forgot about (marketing tools, CRMs, invoicing systems).
Plan an IP warm-up
New IPs have no reputation. A warm-up schedule builds trust gradually.
| Week | Daily volume | Target recipients |
|---|---|---|
| 1 | 50-200 | Most engaged (opened in last 30 days) |
| 2 | 200-1,000 | Engaged (opened in last 60 days) |
| 3 | 1,000-5,000 | Active (opened in last 90 days) |
| 4 | 5,000-25,000 | Full list (excluding bounced/unsubscribed) |
Warm-up rules:
- Send to most engaged recipients first (highest open rates)
- Maintain consistent daily volume - no spikes or gaps
- Pause if hard bounces exceed 2% or complaints exceed 0.1%
- Separate transactional and marketing mail on different IPs/subdomains
- If blocklisted during warm-up, stop, clean list, restart from week 1
Handle bounces
Bounces indicate delivery failures. Proper handling protects reputation.
| Type | Meaning | Action |
|---|---|---|
| Hard bounce (5xx) | Permanent - address does not exist | Remove immediately, never retry |
| Soft bounce (4xx) | Temporary - mailbox full, server down | Retry 3x over 72h, then suppress |
| Complaint (FBL) | User clicked "Report spam" | Remove immediately, investigate cause |
| Block bounce | IP/domain blocklisted | Check blocklists, request delisting |
Threshold alerts:
- Hard bounce rate > 2%: pause sending, clean list
- Complaint rate > 0.1%: investigate content and list source
- Soft bounce rate > 5%: check infrastructure and recipient domains
Process feedback loops (FBLs) from major providers. Gmail uses Postmaster Tools. Yahoo/AOL use the standard ARF format.
Monitor sender reputation
Key metrics and thresholds:
| Metric | Healthy | Warning | Critical |
|---|---|---|---|
| Bounce rate | < 1% | 1-2% | > 2% |
| Complaint rate | < 0.05% | 0.05-0.1% | > 0.1% |
| Spam trap hits | 0 | 1-2/month | > 2/month |
| Inbox placement | > 95% | 85-95% | < 85% |
Monitoring tools: Google Postmaster Tools (domain reputation for Gmail), Microsoft SNDS (IP reputation for Outlook), Sender Score by Validity (third-party IP score 0-100), MXToolbox (blocklist and DNS health checks).
Diagnose spam folder placement
When emails land in spam, investigate in this order:
- Check authentication - verify SPF, DKIM, DMARC pass in email headers
- Check blocklists - query Spamhaus, Barracuda, SURBL for your IP/domain
- Check reputation - review Google Postmaster Tools and Microsoft SNDS
- Check content - look for spam triggers (ALL CAPS, URL shorteners, etc.)
- Check engagement - low open rates signal recipients don't want your mail
- Check infrastructure - verify PTR record, confirm TLS for SMTP
Anti-patterns / common mistakes
| Mistake | Why it's wrong | What to do instead |
|---|---|---|
| No DMARC record | Domain open to spoofing, providers distrust unauthenticated mail | Deploy DMARC in monitor mode, graduate to reject |
| Multiple SPF records | RFC violation causes permerror, all SPF checks fail | Merge into single TXT record with multiple includes |
| Skipping warm-up | Sudden volume from unknown IP triggers throttling and blocks | Follow 2-6 week graduated warm-up plan |
| Ignoring hard bounces | Repeated sends to dead addresses signal spammer behavior | Remove hard bounces on first occurrence |
| Buying email lists | Purchased lists contain spam traps and uninterested recipients | Build organic lists with double opt-in |
| Shared IP without vetting | Other senders on shared IP can ruin your deliverability | Use dedicated IPs for volume > 50K/month |
| No unsubscribe link | Violates CAN-SPAM/GDPR, forces users to report spam instead | Include one-click unsubscribe (RFC 8058) and visible link |
| Sending from no-reply address | Discourages replies which are a positive engagement signal | Use a monitored reply-to address |
Gotchas
SPF over 10 DNS lookups silently fails - and many senders don't know they've hit the limit - Each
include:,a:, andmx:mechanism in an SPF record triggers recursive DNS lookups counted toward the 10-lookup limit. Many companies hit this limit after adding a third or fourth ESP. The result is apermerrorthat causes SPF to fail for all mail, silently. Use an SPF flattening tool and monitor lookup counts.Jumping straight to
p=rejectDMARC breaks legitimate mail you forgot about - CRMs, invoicing tools, support platforms, marketing automation, and third-party senders often send on behalf of your domain without proper DKIM signing. Deployp=nonefirst, monitor aggregate reports for at least 2-4 weeks, and only graduate top=rejectafter all legitimate sources are authenticated.Sending to a re-engagement segment before warming up a new IP causes blocklisting - Dormant subscribers are more likely to mark mail as spam. During IP warm-up, send only to your most engaged subscribers (opened in the last 30 days). Bringing stale addresses into a new IP's warm-up period can tank the IP reputation before it's established.
DKIM keys in DNS must not exceed 255 characters per string without splitting - A 2048-bit RSA public key in base64 exceeds 255 characters. DNS TXT records must split values into multiple quoted strings within the record. Some DNS providers handle this automatically; others require manual splitting. Test with
dig TXT selector._domainkey.yourdomain.comand verify the key assembles correctly.Feedback loop (FBL) complaint data requires separate registration per provider - Gmail uses Google Postmaster Tools, Yahoo/AOL uses their FBL program, and Outlook uses Microsoft SNDS. These are separate registrations with separate dashboards. Many senders set up SPF/DKIM/DMARC and assume they'll receive complaint data automatically - they won't.
References
For detailed implementation guidance on specific sub-domains, read the relevant
file from the references/ folder:
references/spf-dkim-dmarc.md- complete DNS record syntax, alignment modes, troubleshooting authentication failures, BIMI setupreferences/warm-up-and-reputation.md- detailed warm-up schedules by volume tier, reputation recovery playbooks, blocklist delisting proceduresreferences/bounce-handling.md- bounce code reference, FBL setup per provider, suppression list management, list hygiene automation
Only load a references file if the current task requires it - they are long and will consume context.
References
bounce-handling.md
Bounce Handling Reference
Comprehensive bounce code reference, feedback loop setup per provider, suppression list architecture, and list hygiene automation patterns.
1. SMTP bounce code reference
Status code structure
SMTP enhanced status codes follow the format X.Y.Z:
- X = class (2=success, 4=temporary failure, 5=permanent failure)
- Y = subject (0=other, 1=address, 2=mailbox, 3=mail system, 4=network, 5=protocol, 7=security)
- Z = detail (specific to subject)
Hard bounces (5xx) - remove immediately
| Code | Meaning | Action |
|---|---|---|
| 550 5.1.1 | User unknown / mailbox does not exist | Remove from list permanently |
| 550 5.1.2 | Bad destination domain | Remove - domain is invalid |
| 550 5.1.3 | Bad destination mailbox syntax | Remove - address is malformed |
| 550 5.1.10 | Null MX - domain does not accept mail | Remove permanently |
| 551 5.7.1 | Message rejected - policy (spam, blocklist) | Investigate; may need IP/domain cleanup |
| 552 5.2.2 | Mailbox full (some providers treat as permanent) | Suppress after 3 occurrences |
| 553 5.1.3 | Mailbox name invalid | Remove - address format is wrong |
| 554 5.7.1 | Blocked by recipient policy | Check blocklists, content, and reputation |
| 556 5.1.10 | Domain has null MX | Remove permanently |
Soft bounces (4xx) - retry then suppress
| Code | Meaning | Action |
|---|---|---|
| 421 4.7.0 | Connection rate limited / too many connections | Back off, retry in 30 min |
| 450 4.2.1 | Mailbox temporarily unavailable | Retry 3x over 72h |
| 451 4.3.0 | Mail system temporarily unavailable | Retry 3x over 72h |
| 451 4.7.1 | Greylisting - try again later | Retry after 5-15 minutes |
| 452 4.2.2 | Mailbox full (temporary) | Retry 3x over 72h, suppress if persistent |
| 452 4.5.3 | Too many recipients in one message | Reduce batch size |
| 421 4.7.28 | Gmail rate limit exceeded | Back off for 1h, reduce volume |
Block bounces - investigate immediately
| Pattern | Likely cause | Action |
|---|---|---|
| "blocked" or "blacklisted" in response | IP on a blocklist | Check Spamhaus, Barracuda, Spamcop |
| "poor reputation" | Domain or IP reputation is low | Check Google Postmaster Tools, SNDS |
| "too many complaints" | Complaint rate exceeded provider threshold | Review FBL data, clean list |
| "authentication required" or "SPF fail" | SPF/DKIM not configured for this IP | Fix authentication records |
| "DMARC policy" | Message fails DMARC and policy is reject/quarantine | Fix SPF/DKIM alignment |
2. Bounce processing architecture
Processing pipeline
Incoming bounce
|
v
Parse DSN (Delivery Status Notification)
|
v
Extract: recipient, status code, diagnostic message
|
v
Classify: hard bounce / soft bounce / block / complaint
|
+-- Hard bounce --> Add to suppression list immediately
|
+-- Soft bounce --> Increment retry counter
| |
| +-- Retries < 3 --> Schedule retry (exponential backoff)
| |
| +-- Retries >= 3 --> Add to suppression list
|
+-- Block bounce --> Alert ops team, check blocklists
|
+-- Complaint --> Add to suppression list, flag for analysisDSN (Delivery Status Notification) parsing
Bounce messages arrive as DSNs (RFC 3464). Key fields to extract:
Content-Type: multipart/report; report-type=delivery-status
--boundary
Content-Type: message/delivery-status
Reporting-MTA: dns; mail.example.com
Final-Recipient: rfc822; user@recipient.com
Action: failed
Status: 5.1.1
Diagnostic-Code: smtp; 550 5.1.1 The email account does not existFields to extract:
Final-Recipient- the address that bouncedStatus- the enhanced status code (X.Y.Z)Action-failed(hard),delayed(soft),delivered,relayedDiagnostic-Code- the full SMTP response from the receiving server
Retry strategy for soft bounces
Use exponential backoff with jitter:
| Attempt | Wait time | Notes |
|---|---|---|
| 1st retry | 30 minutes | May resolve greylisting |
| 2nd retry | 4 hours | Server outage may resolve |
| 3rd retry | 24 hours | Mailbox full may clear |
| After 3rd | Suppress | Add to soft-bounce suppression (re-evaluate in 30 days) |
Add random jitter of +/- 20% to avoid thundering herd when many bounces resolve simultaneously.
3. Feedback loops (FBL)
Feedback loops deliver complaint notifications when a recipient marks your email as spam. Processing FBLs is critical for maintaining reputation.
FBL setup by provider
| Provider | FBL type | Setup URL | Format |
|---|---|---|---|
| Yahoo/AOL | Traditional FBL | https://senders.yahooinc.com/complaint-feedback-loop | ARF (RFC 5965) |
| Outlook/Hotmail | JMRP (Junk Mail Reporting Program) | https://sendersupport.olc.protection.outlook.com/snds/JMRP.aspx | ARF |
| Gmail | Postmaster Tools only | https://postmaster.google.com | Dashboard (no individual complaints) |
| Comcast | Traditional FBL | https://postmaster.comcast.net/feedback-loop.html | ARF |
| Apple (iCloud) | None publicly available | N/A | N/A |
Gmail does not send individual complaint reports. Use Google Postmaster Tools to monitor aggregate spam rates. This makes Gmail the hardest to diagnose at the individual-message level.
ARF (Abuse Reporting Format) parsing
FBL complaints arrive as ARF messages (RFC 5965):
Content-Type: multipart/report; report-type=feedback-report
--boundary
Content-Type: message/feedback-report
Feedback-Type: abuse
User-Agent: Yahoo!-Mail-Feedback/2.0
Version: 1
Original-Mail-From: bounce@example.com
Arrival-Date: Mon, 14 Mar 2026 10:00:00 -0700
Source-IP: 203.0.113.5Fields to extract:
Feedback-Type- usuallyabuse(spam complaint)Original-Mail-From- your bounce/envelope senderSource-IP- your sending IP- The third MIME part contains the original message (extract recipient address)
FBL processing rules
- Immediately add the complainant to your suppression list
- Never send to a complainant again - ever (not even transactional)
- Track complaint rates per campaign, list segment, and sending IP
- If complaint rate exceeds 0.1% for any segment, investigate:
- Was the list source legitimate (opt-in)?
- Was the content misleading or unexpected?
- Was the frequency too high?
- Use List-Unsubscribe headers (RFC 8058) to give users an easy alternative to the spam button
4. Suppression list management
Suppression list types
| List | Contains | Source | Duration |
|---|---|---|---|
| Hard bounce | Permanently invalid addresses | Bounce processing | Permanent |
| Complaint | Users who reported spam | FBL processing | Permanent |
| Unsubscribe | Users who opted out | Unsubscribe handler | Permanent (per CAN-SPAM/GDPR) |
| Soft bounce | Temporarily failing addresses | Bounce processing | 30 days (then re-evaluate) |
| Role-based | Generic addresses (info@, admin@) | List hygiene scan | Permanent unless explicitly opted in |
| Spam trap | Known spam trap addresses | Third-party hygiene services | Permanent |
Suppression list architecture
Requirements for a production suppression system:
- Global scope - suppression list applies across ALL sending streams, campaigns, and systems. A complaint on marketing mail must suppress transactional mail too.
- Check before every send - every outgoing message must be checked against the suppression list before transmission. No exceptions.
- Immutable hard entries - hard bounces, complaints, and unsubscribes must never be removed without explicit human review and re-confirmation from the recipient.
- Audit trail - log when each entry was added, why (bounce code, complaint, unsubscribe), and from which campaign.
- Import/export - support bulk import from ESP migration and bulk export for compliance requests (GDPR right to access).
Implementation pattern
Suppression Check Flow:
Before sending to recipient@example.com:
1. Normalize email: lowercase, trim whitespace
2. Check suppression table:
SELECT reason, added_at FROM suppression
WHERE email_hash = SHA256('recipient@example.com')
3. If found -> skip send, log suppression hit
4. If not found -> proceed with send
On bounce/complaint:
1. Normalize email
2. INSERT INTO suppression (email_hash, reason, source_campaign, added_at)
3. Log event for analyticsStore email hashes, not plaintext addresses, in the suppression table. This reduces PII exposure. Use a consistent hash function (SHA-256) across all systems.
5. List hygiene automation
Automated hygiene schedule
| Task | Frequency | Method |
|---|---|---|
| Process bounces | Real-time | Automated bounce handler |
| Process FBL complaints | Real-time | Automated FBL parser |
| Remove hard bounces | Real-time | Automated on receipt |
| Re-verify soft bounces | Every 30 days | Re-send or verify via API |
| Sunset inactive subscribers | Every 90 days | Auto-suppress if no engagement in 90-180 days |
| Full list verification | Quarterly | Third-party verification service |
| Spam trap scan | Quarterly | Third-party hygiene service |
Sunset policy
A sunset policy automatically suppresses subscribers who have not engaged within a defined window. This is the single most impactful list hygiene measure.
Recommended sunset thresholds:
| Engagement window | Action |
|---|---|
| No open/click in 90 days | Move to re-engagement segment |
| No open/click in 180 days | Send final re-engagement campaign |
| No response to re-engagement | Suppress permanently |
Re-engagement campaign template
Before suppressing inactive subscribers, send a re-engagement sequence:
- Email 1 (Day 0): "We miss you" - offer value or incentive to re-engage
- Email 2 (Day 7): "Last chance" - clear statement that they will be removed
- No response after Day 14: Add to suppression list
Only subscribers who open or click in the re-engagement sequence should remain on the active list. Passive opens (image proxy pre-fetching) do not count as genuine engagement - track click-throughs for reliable signal.
Email verification services
For bulk list cleaning, use a verification service before any large send:
| Service | What it checks |
|---|---|
| ZeroBounce | Validity, spam traps, abuse emails, catch-all detection |
| NeverBounce | Real-time and bulk verification, deliverability scoring |
| BriteVerify | Syntax, domain, mailbox verification |
| Kickbox | Deliverability, risk scoring, disposable email detection |
Run verification on:
- Any list that has not been mailed in 90+ days
- Lists from acquisitions or migrations
- Before a warm-up campaign
- After any deliverability incident
spf-dkim-dmarc.md
SPF, DKIM, and DMARC Reference
Deep-dive reference for email authentication protocols. Covers full DNS record syntax, alignment modes, common failure patterns, and troubleshooting steps.
1. SPF - Sender Policy Framework
Record syntax
v=spf1 [mechanisms] [qualifier]allMechanisms (evaluated left to right, first match wins):
| Mechanism | Syntax | DNS lookups | Purpose |
|---|---|---|---|
include |
include:_spf.google.com |
1+ (recursive) | Authorize another domain's SPF |
ip4 |
ip4:203.0.113.0/24 |
0 | Authorize an IPv4 address or range |
ip6 |
ip6:2001:db8::/32 |
0 | Authorize an IPv6 address or range |
a |
a:mail.example.com |
1 | Authorize IPs that the A record resolves to |
mx |
mx |
1 per MX record | Authorize IPs of the domain's MX records |
exists |
exists:%{i}._spf.example.com |
1 | Advanced macro-based check |
redirect |
redirect=_spf.example.com |
1 | Delegate entire SPF policy to another domain |
Qualifiers:
| Qualifier | Meaning | Use when |
|---|---|---|
+ (default) |
Pass | Mechanism matches, authorize |
- |
Hard fail | Use with all in production: -all |
~ |
Soft fail | Use with all during testing: ~all |
? |
Neutral | Rarely useful, avoid |
The 10-lookup limit
SPF processing must not exceed 10 DNS lookups. Exceeding this causes a permerror and SPF fails for all messages.
What counts as a lookup:
- Each
include:= 1 lookup + recursive lookups inside the included record - Each
a:= 1 lookup - Each
mx:= 1 lookup + 1 per MX record returned - Each
redirect== 1 lookup - Each
exists:= 1 lookup ip4:andip6:= 0 lookups (no DNS query needed)
How to count your lookups:
# Check your SPF record
dig TXT example.com +short | grep spf
# Use an online tool to count recursive lookups
# dmarcian.com/spf-survey or mxtoolbox.com/spf.aspxSPF flattening resolves all include: mechanisms to their underlying IP
addresses at publish time, replacing DNS lookups with ip4:/ip6: entries.
This reduces lookup count but requires re-flattening when ESPs change their IPs.
Automate flattening with a cron job or use a service like AutoSPF.
Common SPF errors
| Error | Cause | Fix |
|---|---|---|
| permerror | > 10 lookups or syntax error | Flatten includes or remove unused mechanisms |
| temperror | DNS timeout during lookup | Check DNS server health, reduce lookup count |
| Multiple SPF records | Two TXT records starting with v=spf1 |
Merge into one record |
| Too long (> 450 chars) | Record exceeds practical TXT limit | Split into include: sub-records or flatten |
Subdomain SPF
SPF is evaluated per envelope sender (Return-Path) domain. If you send from
news@marketing.example.com, the SPF record at marketing.example.com is
checked, not example.com. Publish SPF records on every subdomain you send from.
For subdomains you do NOT send from, publish a restrictive SPF to prevent spoofing:
nosend.example.com. IN TXT "v=spf1 -all"2. DKIM - DomainKeys Identified Mail
How DKIM works
- Sending server computes a hash of specified headers + body
- Hash is signed with a private key
- Signature is added as the
DKIM-Signatureheader - Receiving server fetches the public key from DNS and verifies the signature
DKIM-Signature header anatomy
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed;
d=example.com; s=selector1;
h=from:to:subject:date:message-id;
bh=base64_body_hash;
b=base64_signature| Tag | Meaning | Notes |
|---|---|---|
v= |
Version | Always 1 |
a= |
Algorithm | rsa-sha256 (required), ed25519-sha256 (emerging) |
c= |
Canonicalization | relaxed/relaxed recommended (header/body) |
d= |
Signing domain | Must align with From domain for DMARC |
s= |
Selector | Identifies which key to fetch from DNS |
h= |
Signed headers | Must include from; recommended: to, subject, date, message-id |
bh= |
Body hash | Base64-encoded hash of the canonicalized body |
b= |
Signature | Base64-encoded signature of the header hash |
l= |
Body length | AVOID - allows appending content to signed messages |
DNS record format
selector1._domainkey.example.com. IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqhki..."| Tag | Meaning | Notes |
|---|---|---|
v= |
Version | DKIM1 |
k= |
Key type | rsa (default) or ed25519 |
p= |
Public key | Base64-encoded; empty p= revokes the key |
t= |
Flags | t=s restricts to exact domain (no subdomains); t=y testing mode |
Key management best practices
- Use 2048-bit RSA keys minimum (1024-bit is cryptographically weak)
- Use a unique selector per sending service (e.g.,
sg1for SendGrid,gm1for Gmail) - Rotate keys annually with zero-downtime process:
- Generate new key pair with a new selector name
- Publish new public key in DNS
- Wait 48-72 hours for DNS propagation
- Switch signing to the new key
- Keep old public key in DNS for 7 days (inflight messages)
- Remove old public key from DNS
DKIM troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
dkim=fail in headers |
Key mismatch or body modified in transit | Verify public key matches private key; check for content rewriting (mailing lists, AV scanners) |
dkim=temperror |
DNS lookup for key failed | Check DNS propagation of the DKIM TXT record |
| Key not found | Wrong selector or DNS not propagated | Verify dig TXT selector._domainkey.example.com returns the key |
| Signature covers wrong domain | d= in signature doesn't match From domain |
Configure ESP to sign with your domain, not theirs |
3. DMARC - Domain-based Message Authentication, Reporting, and Conformance
How DMARC works
DMARC validates that at least one of SPF or DKIM passes AND aligns with the From header domain. "Alignment" means the domain in the From header matches the domain authenticated by SPF (envelope sender) or DKIM (d= tag).
Message passes DMARC if:
(SPF passes AND SPF aligns with From domain)
OR
(DKIM passes AND DKIM d= aligns with From domain)DMARC record syntax
_dmarc.example.com. IN TXT "v=DMARC1; p=reject; sp=reject; rua=mailto:dmarc-agg@example.com; ruf=mailto:dmarc-forensic@example.com; adkim=s; aspf=s; pct=100; ri=86400; fo=1"| Tag | Values | Default | Purpose |
|---|---|---|---|
v= |
DMARC1 |
required | Version identifier |
p= |
none, quarantine, reject |
required | Policy for the domain |
sp= |
none, quarantine, reject |
inherits p= |
Policy for subdomains |
rua= |
mailto: URI |
none | Aggregate report destination |
ruf= |
mailto: URI |
none | Forensic report destination |
adkim= |
r (relaxed), s (strict) |
r |
DKIM alignment mode |
aspf= |
r (relaxed), s (strict) |
r |
SPF alignment mode |
pct= |
0-100 | 100 | Percentage of messages to apply policy to |
ri= |
seconds | 86400 | Aggregate report interval |
fo= |
0, 1, d, s |
0 |
Forensic report options |
Alignment modes explained
Relaxed alignment (adkim=r, aspf=r):
- Organizational domain must match (e.g.,
mail.example.comaligns withexample.com) - Recommended during initial deployment
Strict alignment (adkim=s, aspf=s):
- Exact domain match required (e.g.,
mail.example.comdoes NOT align withexample.com) - Recommended for production after confirming all senders align
DMARC deployment roadmap
Phase 1 - Monitor (weeks 1-4):
_dmarc.example.com. IN TXT "v=DMARC1; p=none; rua=mailto:dmarc@example.com; fo=1"- Collect reports, identify all legitimate sending sources
- Use a DMARC report analyzer (dmarcian, Valimail, Postmark) to parse XML reports
Phase 2 - Quarantine (weeks 5-8):
_dmarc.example.com. IN TXT "v=DMARC1; p=quarantine; pct=25; rua=mailto:dmarc@example.com"- Start at 25%, increase to 50%, then 100% over 3-4 weeks
- Monitor reports for legitimate mail being quarantined
Phase 3 - Reject (week 9+):
_dmarc.example.com. IN TXT "v=DMARC1; p=reject; rua=mailto:dmarc@example.com; adkim=s; aspf=s"- Full enforcement with strict alignment
- Continue monitoring reports permanently
DMARC aggregate report structure
Reports are XML files sent daily. Key fields:
<feedback>
<report_metadata>
<org_name>google.com</org_name>
<date_range><begin>1234567890</begin><end>1234654290</end></date_range>
</report_metadata>
<record>
<row>
<source_ip>203.0.113.5</source_ip>
<count>150</count>
<policy_evaluated>
<disposition>none</disposition>
<dkim>pass</dkim>
<spf>fail</spf>
</policy_evaluated>
</row>
<identifiers>
<header_from>example.com</header_from>
</identifiers>
<auth_results>
<dkim><domain>example.com</domain><result>pass</result></dkim>
<spf><domain>bounce.example.com</domain><result>fail</result></spf>
</auth_results>
</record>
</feedback>4. BIMI - Brand Indicators for Message Identification
BIMI displays your brand logo next to authenticated emails in supported mailbox providers (Gmail, Yahoo, Apple Mail).
Prerequisites
- DMARC policy must be
p=quarantineorp=reject(notnone) - A Verified Mark Certificate (VMC) from a certificate authority (DigiCert, Entrust)
- Logo in SVG Tiny PS format
DNS record
default._bimi.example.com. IN TXT "v=BIMI1; l=https://example.com/logo.svg; a=https://example.com/vmc.pem"| Tag | Purpose |
|---|---|
l= |
URL to SVG Tiny PS logo file (HTTPS required) |
a= |
URL to VMC certificate in PEM format |
BIMI is a reward for doing authentication right. It requires DMARC at enforcement level, which means SPF and DKIM must already be solid.
5. Verifying authentication from email headers
When troubleshooting, check the Authentication-Results header in a received
message:
Authentication-Results: mx.google.com;
dkim=pass header.i=@example.com header.s=selector1;
spf=pass (google.com: domain of bounce@example.com designates 203.0.113.5 as permitted sender) smtp.mailfrom=bounce@example.com;
dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=example.comWhat to look for:
dkim=passwith correctheader.i=domainspf=passwith correctsmtp.mailfrom=domaindmarc=passwith expected policy- If any show
fail, check the specific domain and IP in the result
Quick diagnostic commands:
# Check SPF record
dig TXT example.com +short | grep spf
# Check DKIM public key
dig TXT selector1._domainkey.example.com +short
# Check DMARC record
dig TXT _dmarc.example.com +short
# Check BIMI record
dig TXT default._bimi.example.com +short
# Test with a real message - send to a Gmail account and view
# "Show Original" to see full Authentication-Results header warm-up-and-reputation.md
Warm-up and Reputation Reference
Detailed warm-up schedules for different volume tiers, reputation monitoring playbooks, and blocklist delisting procedures.
1. IP warm-up schedules
Why warm-up matters
Mailbox providers track sender reputation per IP and per domain. A new IP has zero history - providers treat it as suspicious by default. Warm-up builds a track record of legitimate sending behavior. Skipping warm-up is the most common cause of deliverability failure for new senders.
Low volume (target: < 25K emails/day)
| Day | Daily volume | Notes |
|---|---|---|
| 1-3 | 50 | Most engaged recipients only (opened in last 14 days) |
| 4-7 | 100-200 | Expand to opened in last 30 days |
| 8-14 | 500-1,000 | Expand to opened in last 60 days |
| 15-21 | 2,000-5,000 | Expand to opened in last 90 days |
| 22-28 | 10,000-25,000 | Full active list |
Medium volume (target: 25K-100K emails/day)
| Day | Daily volume | Notes |
|---|---|---|
| 1-3 | 100 | Most engaged only |
| 4-7 | 500 | Opened in last 30 days |
| 8-14 | 2,000-5,000 | Opened in last 60 days |
| 15-21 | 10,000-25,000 | Opened in last 90 days |
| 22-35 | 25,000-100,000 | Gradually include full list |
High volume (target: 100K+ emails/day)
| Day | Daily volume | Notes |
|---|---|---|
| 1-3 | 200 | Most engaged only |
| 4-7 | 1,000-2,000 | Opened in last 30 days |
| 8-14 | 5,000-15,000 | Opened in last 60 days |
| 15-28 | 15,000-75,000 | Opened in last 90 days |
| 29-42 | 75,000-250,000+ | Full list, increase 25-50% per day |
High-volume senders should warm up over 6 weeks, not 4. The stakes are higher and recovery from a failed warm-up takes longer.
Warm-up rules (all tiers)
- Start with your most engaged recipients - high open rates prove to providers that people want your mail
- Send at consistent times - same time each day, same days each week
- Do not skip days - gaps in sending reset the trust you have built
- Monitor daily:
- Hard bounce rate must stay under 2%
- Complaint rate must stay under 0.1%
- If either threshold is exceeded, pause for 24h, clean list, resume at the previous day's volume
- Separate streams - warm up transactional and marketing IPs independently
- Avoid weekends initially - some providers have stricter weekend filtering
Domain warm-up
Domain reputation is increasingly more important than IP reputation (especially for Gmail). When warming a new sending domain:
- The domain warm-up schedule mirrors the IP warm-up schedule above
- Subdomains inherit partial reputation from the parent domain
- Use subdomains to isolate streams:
transactional.example.com,marketing.example.com,notifications.example.com - Each subdomain needs its own SPF, DKIM, and DMARC configuration
2. Reputation monitoring
Provider-specific tools
Google Postmaster Tools (Gmail):
- URL: https://postmaster.google.com
- Shows: domain reputation (High/Medium/Low/Bad), spam rate, authentication results, encryption percentage, delivery errors
- Requires DNS TXT verification of domain ownership
- Data appears only for domains sending > ~200 messages/day to Gmail
- Domain reputation levels:
- High: good standing, mail delivered to inbox
- Medium: some filtering, watch for decline
- Low: significant filtering, investigate immediately
- Bad: most mail going to spam, urgent action needed
Microsoft SNDS (Outlook/Hotmail):
- URL: https://sendersupport.olc.protection.outlook.com/snds/
- Shows: IP reputation (Green/Yellow/Red), complaint rate, spam trap hits
- Requires IP ownership verification
- Data is per-IP, not per-domain
Sender Score (Validity):
- URL: https://senderscore.org
- Third-party IP reputation score from 0-100
- Score > 80: good, 70-80: needs attention, < 70: deliverability problems
Key metrics dashboard
Track these metrics per sending IP and per sending domain:
| Metric | Source | Frequency | Healthy | Action trigger |
|---|---|---|---|---|
| Bounce rate | Your MTA logs | Per send | < 1% | > 2% pause and clean |
| Complaint rate | FBL reports / Postmaster Tools | Daily | < 0.05% | > 0.1% investigate |
| Spam trap hits | Blocklist monitors | Daily | 0 | Any hit: investigate source |
| Inbox placement | Seed list testing | Weekly | > 95% | < 85% full audit |
| Domain reputation | Google Postmaster Tools | Daily | High | Medium or below: investigate |
| IP reputation | Microsoft SNDS | Daily | Green | Yellow: watch; Red: act |
| Authentication rate | DMARC aggregate reports | Daily | > 99% pass | < 95%: fix auth config |
Engagement metrics that affect reputation
Mailbox providers (especially Gmail) use engagement signals to determine inbox placement:
| Signal | Positive | Negative |
|---|---|---|
| Opens | High open rate (> 20%) | Low open rate (< 5%) |
| Clicks | Users click links | No engagement |
| Replies | Users reply to your emails | Never any replies |
| Move to inbox | Users move from spam to inbox | Users never rescue from spam |
| Mark as spam | Rare (< 0.05%) | Frequent (> 0.1%) |
| Delete without reading | Rare | Frequent (suggests unwanted mail) |
3. Reputation recovery
When reputation is damaged
Signs of reputation damage:
- Google Postmaster Tools shows "Low" or "Bad" domain reputation
- Inbox placement drops below 85%
- Bounce rates spike above 5%
- You appear on one or more blocklists
Recovery playbook
Step 1 - Stop the bleeding (Day 1):
- Reduce sending volume to 10% of normal
- Send only to your most engaged segment (opened in last 14 days)
- Verify all authentication (SPF, DKIM, DMARC) is passing
Step 2 - Clean your list (Days 2-3):
- Remove all hard bounces permanently
- Suppress addresses that have not engaged in 180+ days
- Run your list through an email verification service (ZeroBounce, NeverBounce, BriteVerify) to catch invalid addresses and known spam traps
- Remove role-based addresses (info@, admin@, support@) unless they opted in
Step 3 - Identify root cause (Days 3-5):
- Review DMARC aggregate reports for authentication failures
- Check if a specific campaign or list segment caused the spike
- Look for spam trap sources (often purchased lists or scraped addresses)
- Review recent content changes that might trigger content filters
Step 4 - Rebuild (Weeks 2-6):
- Follow the warm-up schedule as if starting from scratch
- Send only to engaged recipients for the first 2 weeks
- Gradually expand to the full (cleaned) list
- Monitor daily - if metrics degrade, reduce volume again
Step 5 - Prevent recurrence:
- Implement double opt-in for all new subscribers
- Add sunset policies: auto-suppress after 90 days of no engagement
- Set up automated alerts on bounce rate, complaint rate, and reputation score
- Schedule quarterly list hygiene reviews
4. Blocklist handling
Major blocklists
| Blocklist | Impact | Check URL |
|---|---|---|
| Spamhaus SBL | Severe - widely used by enterprise receivers | https://check.spamhaus.org |
| Spamhaus XBL | Severe - compromised hosts / botnets | https://check.spamhaus.org |
| Barracuda BRBL | Moderate - used by Barracuda appliance users | http://www.barracudacentral.org/lookups |
| SURBL | Moderate - domain-based (checks URLs in email body) | https://surbl.org/surbl-analysis |
| Spamcop | Moderate - complaint-driven | https://www.spamcop.net/bl.shtml |
| UCE Protect | Low-Moderate | https://www.uceprotect.net/en/ |
Delisting procedures
General process:
- Identify which blocklist you are on (use MXToolbox Blacklist Check)
- Fix the underlying cause FIRST (sending to traps, compromised server, etc.)
- Submit a delisting request through the blocklist's self-service portal
- Wait - processing time varies from hours to days
- Monitor to ensure you do not get relisted
Spamhaus delisting:
- Self-service removal: https://check.spamhaus.org (lookup your IP, follow removal link)
- Fix the issue first - Spamhaus will relist immediately if the problem persists
- SBL listings require explanation of what happened and what you changed
- XBL listings are usually automatic (compromised host) - secure the server first
Barracuda delisting:
- Self-service: http://www.barracudacentral.org/lookups/lookup-reputation
- Requires that your IP has no negative activity for 12+ hours before requesting
- Generally processes within 12-24 hours
Preventing blocklisting
- Never send to purchased or scraped lists (spam traps are embedded)
- Process hard bounces immediately (repeated hits to dead addresses flag you)
- Honor unsubscribe requests within 24 hours (not the 10-day CAN-SPAM maximum)
- Monitor for compromised accounts sending spam through your infrastructure
- Use feedback loops to catch complaint spikes early
- Implement rate limiting to prevent abuse if your system allows user-generated email
5. Dedicated vs shared IP strategy
| Factor | Shared IP | Dedicated IP |
|---|---|---|
| Volume threshold | < 50K emails/month | > 50K emails/month |
| Reputation control | Shared with other senders | Fully in your control |
| Warm-up required | No (pre-warmed by ESP) | Yes (must warm up yourself) |
| Cost | Lower (included in ESP plan) | Higher (additional IP cost) |
| Risk | Neighbor's bad behavior affects you | Only your behavior matters |
| Best for | Small senders, startups | High-volume or reputation-sensitive senders |
When to move to a dedicated IP:
- Volume exceeds 50K emails/month consistently
- You need full control over sender reputation
- Your industry has strict deliverability requirements (finance, healthcare)
- You are experiencing deliverability issues on shared IPs despite good practices
Multiple dedicated IPs:
- Separate transactional mail (receipts, password resets) from marketing
- Consider separate IPs per mail stream if volume justifies it
- Each IP needs its own warm-up schedule
- PTR records must be configured for each IP (reverse DNS)
Frequently Asked Questions
What is email-deliverability?
Use this skill when optimizing email deliverability, sender reputation, or authentication. Triggers on SPF record setup, DKIM signing configuration, DMARC policy deployment, IP warm-up planning, bounce handling strategy, sender reputation monitoring, inbox placement troubleshooting, email infrastructure hardening, DNS TXT record configuration for email, and diagnosing why emails land in spam. Acts as a senior email infrastructure advisor for engineers and marketers managing transactional or marketing email.
How do I install email-deliverability?
Run npx skills add AbsolutelySkilled/AbsolutelySkilled --skill email-deliverability in your terminal. The skill will be immediately available in your AI coding agent.
What AI agents support email-deliverability?
email-deliverability works with claude-code, gemini-cli, openai-codex, mcp. Install it once and use it across any supported AI coding agent.