# SPF, DKIM and DMARC for developers

What each record proves, what it looks like in DNS, how receivers combine them, and what Gmail and Yahoo require from bulk senders since 2024.

Date: 2026-09-03

SPF says which servers may send mail for a domain, DKIM signs each message so a receiver can prove it was not altered and came from the signing domain, and DMARC tells receivers what to do when neither check lines up with the address the recipient sees. All three are DNS TXT records, all three are checked on every delivery by Gmail, Yahoo and Microsoft, and since February 2024 the large mailbox providers refuse bulk mail that lacks them.

## What does SPF prove?

SPF, defined in [RFC 7208](https://www.rfc-editor.org/rfc/rfc7208), lists the hosts allowed to send mail using a domain in the SMTP envelope sender, the `MAIL FROM` address. The record is a TXT record at the domain itself.

```text
acme.com.  IN TXT  "v=spf1 ip4:203.0.113.0/24 include:_spf.google.com -all"
```

| Mechanism | Matches |
| --- | --- |
| `ip4:` / `ip6:` | A literal address or range |
| `a` / `mx` | The domain's own A records or MX hosts |
| `include:` | The SPF record of another domain, typically a sending service |
| `all` | Everything else; its qualifier decides the default |

| Qualifier | Result for a non-matching sender |
| --- | --- |
| `+` (default) | pass |
| `~` | softfail: accept but mark |
| `-` | fail: reject or quarantine |
| `?` | neutral: no opinion |

Two limits catch people out. A domain may publish only one SPF record; two records mean SPF fails for everyone. And evaluation may perform at most ten DNS lookups, counting every `include:`, `a`, `mx` and `redirect`. Large stacks of third-party senders hit that limit and silently break.

SPF checks the envelope sender, not the `From:` header the recipient sees. Forwarding breaks it, because the forwarding server is not in the original domain's record. Both weaknesses are why DKIM and DMARC exist.

## What does DKIM prove?

DKIM, defined in [RFC 6376](https://www.rfc-editor.org/rfc/rfc6376), adds a cryptographic signature to each message. The sending server signs selected headers and a hash of the body with a private key, and publishes the public key in DNS under a selector.

```text
DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=acme.com; s=mail2026;
    h=from:to:subject:date:message-id; bh=…; b=…
```

```text
mail2026._domainkey.acme.com.  IN TXT  "v=DKIM1; k=rsa; p=MIIBIjANBgkq…"
```

The receiver fetches `selector._domainkey.domain`, verifies the signature, and learns two things: the signed parts were not modified in transit, and whoever holds the private key for `d=acme.com` vouched for the message. DKIM survives forwarding, which SPF does not, as long as the forwarder leaves the signed headers alone. Rotate keys by publishing a new selector and switching signing to it; the old selector can be removed once mail in transit has cleared.

## What does DMARC add?

DMARC, defined in [RFC 7489](https://www.rfc-editor.org/rfc/rfc7489), ties SPF and DKIM to the visible `From:` domain and gives receivers a policy. The record lives at `_dmarc.domain`.

```text
_dmarc.acme.com.  IN TXT  "v=DMARC1; p=reject; rua=mailto:dmarc@acme.com; adkim=r; aspf=r; pct=100"
```

A message passes DMARC when at least one of SPF or DKIM passes **and** its domain aligns with the `From:` header domain. Relaxed alignment (`r`) accepts subdomains; strict (`s`) requires an exact match.

| Policy | Receiver action on failure |
| --- | --- |
| `p=none` | Deliver normally, send reports |
| `p=quarantine` | Deliver to spam or hold |
| `p=reject` | Refuse the message |

The `rua` address receives daily aggregate XML reports listing every source that sent mail as your domain and whether it passed. Start at `p=none`, read the reports until every legitimate sender aligns, then move to `quarantine` and `reject`. A domain that stays at `p=none` for years has told receivers it does not mind being spoofed.

## What do Gmail and Yahoo require?

Since February 1, 2024, Google's [sender guidelines](https://support.google.com/a/answer/81126) require anyone sending more than 5,000 messages a day to Gmail accounts to authenticate with SPF and DKIM, publish a DMARC policy, support one-click unsubscribe with the `List-Unsubscribe` headers, and keep the spam rate reported in Postmaster Tools below 0.10% and never at 0.30% or above. Yahoo's [sender requirements](https://senders.yahooinc.com/best-practices/) ask the same of bulk senders: both SPF and DKIM, a DMARC policy of at least `p=none` that passes, one-click unsubscribe, and a spam rate below 0.3%. Yahoo also asks senders to monitor bounces and remove invalid recipients promptly.

For a developer the practical checklist is short: every sending service you use appears in SPF, every one of them signs with DKIM under your domain, `_dmarc` exists with a policy and a reporting address, and marketing mail carries the unsubscribe headers.

## How does Spaw use these records?

Every email verification answer reports `has_spf` and `dmarc_policy` for the address's domain, and the domain endpoint returns the raw records alongside MX hosts, provider and registration age.

```bash
curl https://spaw.co/api/v1/email/domain/acme.com \
  -H "Authorization: Bearer sk_live_…"
```

```json
{
  "success": true,
  "data": {
    "domain": "acme.com",
    "mx_found": true,
    "mx_provider": "google",
    "has_spf": true,
    "dmarc_policy": "reject",
    "domain_registered_at": "1998-03-12",
    "// 6 more fields": "see the endpoint reference"
  },
  "meta": { "credits_used": 1, "credits_remaining": 8, "cache_hit": false }
}
```

The records also feed the scores. A business domain without SPF adds 10 to the risk score, since a domain nobody bothered to authenticate is less likely to be a well-run mailbox provider for real people. In the mailbox confidence estimate for catch-all domains, a DMARC policy of `reject` or `quarantine` adds 15, `none` adds 5, an SPF record adds 10 and a missing one subtracts 10. Free consumer providers are exempt from the SPF penalty, because Gmail's records say nothing about the person using it.

## Which mistakes come up most?

| Mistake | Effect | Fix |
| --- | --- | --- |
| Two SPF records | Permanent SPF failure | Merge into one record |
| More than ten DNS lookups | SPF permerror | Flatten includes or drop unused senders |
| `+all` at the end | Everyone passes; the record is useless | Use `~all` or `-all` |
| DKIM key never rotated | A leaked key signs forever | Publish a new selector each year |
| Third-party sender not aligned | DMARC fails for newsletters | Sign with your own domain at the provider |
| `p=none` forever | No protection, receivers notice | Move to `quarantine`, then `reject` |
| No `rua` address | Failures are invisible | Add a mailbox or a reporting service |

## What to do next

- Check any domain's live records in the [SPF and DMARC checker](/tools/spf-dmarc-checker); each result has a permalink you can send to whoever runs the DNS.
- Pull the records programmatically from the [domain intelligence endpoint](/docs/api/domain-intelligence).
- See exactly how SPF and DMARC move the numbers in [how Spaw computes the risk score](/guides/how-spaw-computes-the-risk-score).
- If a receiver answers `550 5.7.26`, read [SMTP bounce codes explained](/guides/smtp-bounce-codes-explained): that reply is about authentication, not the recipient.

Reference: https://spaw.co/guides/spf-dkim-dmarc-for-developers
