Email deliverability for small teams: SPF, DKIM and DMARC without breaking mail

Deliverability sounds like a marketing problem, which is why small teams never check it until it's an operations problem. Then the pattern is always the same: a customer says "I never got the invoice," a password reset goes to spam, a two-factor code doesn't arrive, and someone spends a day blaming the mail provider when the real issue is a DNS record nobody has read since the company was three people. This is the 45-minute audit that keeps your mail landing — and the runbook for the morning it stops.

1. Why this is an ops problem, not a marketing problem

2. The 45-minute audit, step by step

  1. Inventory every service that sends as your domain. One list: mail provider (Google Workspace, Microsoft 365, Fastmail), billing (Stripe, QuickBooks), helpdesk, newsletter, CRM, e-sign, CI. Ask "who emailed a customer last week?" — every answer is a sender. If a tool isn't on the list, its mail is either failing or about to.
  2. Look up all three records in parallel. From any terminal: dig +short TXT yourdomain.com (SPF lives here), dig +short TXT _dmarc.yourdomain.com, and dig +short TXT s1._domainkey.yourdomain.com (DKIM selectors vary: google, selector1/selector2, k1, fm1). Five minutes, no admin panel required — DNS is the ground truth, not the vendor's dashboard.
  3. Count your SPF lookups. SPF has a hard limit of 10 DNS lookups per evaluation, counting every include:, a, mx, and exists mechanism — including the nested ones inside your vendors' own includes. Over 10, some receivers treat the whole record as broken. If you're at 7+, pruning is a this-quarter task, not a someday task.
  4. Verify DKIM validates for every sender, not just mail. Send yourself a message from each system (billing test invoice, helpdesk ticket reply, newsletter proof) and view the original headers: Authentication-Results should read spf=pass dkim=pass dmarc=pass. A tool sending unsigned mail has been coasting on SPF alone — that's a finding.
  5. Check where DMARC reports go — if anywhere. A DMARC record with no rua= address means you published a policy but blinded yourself: you'll never see who's spoofing you or which legitimate tool is misfiring. A free aggregate-report parser turns the XML into "these four services send as you; one fails alignment."

3. SPF: one record, ten lookups, and the -all question

4. DKIM: 2048-bit keys and two live selectors

5. DMARC: the road from p=none to p=reject

  1. Day 0 — publish v=DMARC1; p=none; rua=mailto:dmarc@yourdomain.com. p=none changes nothing about delivery; it only switches on the reporting firehose. It costs nothing and blocks nothing — publish it today even if you do nothing else from this checklist.
  2. Weeks 1–4 — read the aggregate reports. Raw XML is unreadable; free parsers aren't. You're looking for three things: legitimate senders you forgot (add them to SPF/DKIM), services failing alignment (fix or kill them), and volume you don't recognize (someone is spoofing you — the reason DMARC matters even if you never send marketing mail).
  3. Week 5 — p=quarantine; pct=25, only after a clean month. pct=25 sends a quarter of failing mail to spam: a controlled burn instead of a bonfire. Bump 50 → 100 over two weeks while watching your own inbox and one friendly customer's.
  4. Then p=reject, and set sp= for subdomains. Reject makes spoofed mail from your domain die on arrival. While you're there: subdomains inherit the policy unless sp= says otherwise, and attackers love subdomains precisely because nobody configured them.
  5. The one place tighter is worse: mailing lists and forwarders. Old-school forwarding and lists break DKIM signatures, and strict DMARC then bounces mail your customers asked for. If your audience lives on lists, hold at quarantine or relax alignment (adkim=s/aspf=s). "Tighter" is not automatically "better."

6. Monday-morning runbook: mail stopped arriving

  1. Scope the blast radius first. Test mail from your domain to Gmail, Outlook, and one small provider — and check the spam folders, not just the inbox. All receivers failing = your domain or provider. One receiver failing = reputation with that receiver. Same rule as the opening minutes of any incident: measure before you change.
  2. Diff DNS against last-known-good. What changed in 7 days? New marketing tool, new billing provider, a second SPF record someone added to "fix" things, a lapsed domain renewal (whois — expired domains stop sending permanently). Keep a copy of your records in your ops docs so the diff is one dig apart; the record-saving habit belongs in your DNS runbook.
  3. Check blacklists — then hunt the reason you're on them. Spamhaus, Barracuda, Microsoft SNDS. The listing is a symptom; the disease is usually a compromised mailbox, an open relay, or a script sending through your domain. Delist without fixing the source and you're back by Thursday — and if the source is a stolen credential, that's an exposed-key incident, not a deliverability problem.
  4. Check the provider's status page before touching anything. Gmail, Outlook, and bulk-mail vendors all publish sender-facing incidents. If the vendor is degraded, your job is to delay the send and tell the team — every DNS edit made during someone else's outage is a second incident queued behind the first.
  5. Tell the humans early, with the template. "Invoice delivery is degraded for some recipients; today's invoices are being re-sent manually; next update 2pm" beats silence. Use the status update template: customers forgive delivery problems, not discovering them from their own bank statement.

7. Keep it from drifting back

The whole discipline fits one line: your domain's right to send mail is maintained, not owned. Every new tool spends it, every DMARC report shows the balance, and the 45 minutes a quarter you spend reading both is the cheapest insurance your invoices will ever be seen.