# Check email records

> Check MX, SPF and its DNS lookups, DKIM and DMARC as public resolvers see them, and set up a mail provider's records in one change.

The **email check** looks at a domain's mail records as public resolvers see them right now and reports what is wrong:
missing or duplicated SPF, too many SPF lookups, weak DKIM keys, no DMARC, proxied mail names and more. It works for
delegated and external zones and changes nothing. Reading it needs the `readonly` role; forcing a fresh check needs
`tech`.

## Run the check

**Dashboard**

Open the domain's **DNS › Email**. **Public check** shows the result; **Check again** runs it now. The domain's
**Overview** has an **Email** card with the worst status.
**API**

```sh
curl "https://dash.openwaf.dev/v1/orgs/$ORG/zones/$ZONE/email/check?refresh=1" \
  -H "Authorization: Bearer $OPENWAF_TOKEN"
```
`selectors=s1,s2` adds DKIM selectors to look for (up to 10). Without `refresh=1`, a result from the last minute is
reused.
**MCP**

Ask your assistant to check the email of example.com. It calls `email_check` (`zone`, optional `selectors` and
`refresh`) and summarises what is not `ok`.


The report has a `summary.status` (the worst of all checks) and one entry per check, each with a `status` (`ok`,
`warn`, `fail` or `info`), a stable `code` and its `params`. It also lists the providers detected from the MX
records, the SPF includes and the DKIM selectors.

## What is checked

| Check | Codes |
|---|---|
| `mx` | `mx_ok`, `mx_missing` (fail), `mx_null` (info: the domain declares it receives no mail), `mx_mixed` (warn: MX of several providers), `mx_no_address` (fail), `mx_cname` (warn) |
| `spf_record` | `spf_ok`, `spf_missing` (fail), `spf_multiple` (fail: more than one SPF record), `spf_syntax` (fail) |
| `spf_lookups` | `spf_lookups_ok`, `spf_lookups_exceeded` (more than 10 DNS lookups, nested includes counted), `spf_void_exceeded` (more than 2 lookups with no answer), `spf_loop`, `spf_include_missing`, `spf_include_invalid` |
| `spf_policy` | `spf_all_strict` (`-all`), `spf_all_soft` (`~all`), `spf_all_pass` (fail: `+all`), `spf_all_neutral` (warn: `?all`), `spf_ptr` (warn) |
| `dkim` | `dkim_ok`, `dkim_weak`, `dkim_invalid`, `dkim_revoked`, `dkim_missing` |
| `dmarc` | `dmarc_enforced`, `dmarc_monitoring` (info: `p=none`), `dmarc_missing` (fail), `dmarc_multiple`, `dmarc_invalid`, `dmarc_rua_unauthorized` (warn) |
| `proxied` | `proxied_ok`, `proxied_mail_name` (fail: `mail`, `smtp`, `imap`, `pop`, `mx`, `autodiscover`, `autoconfig` or an MX target of the zone is proxied), `mx_target_proxied` (fail: an MX resolves to the OpenWAF edge) |
| `conflicts` | `conflicts_ok`, `conflict_cname` (fail: a CNAME next to other records, or the domain itself is a CNAME in public DNS) |
| `world` | `world_ok`, `world_mismatch` (warn: the zone's MX, SPF, DMARC or DKIM differ from what the world sees), `world_external` (info) |

Any check can also carry `lookup_error` (warn) when a resolver did not answer.

### SPF lookups

SPF allows at most 10 DNS lookups when a receiver evaluates the record (RFC 7208). `include`, `a`, `mx`, `ptr`,
`exists` and `redirect` cost one lookup each, wherever they appear in the include tree; `ip4`, `ip6` and `all` cost
none. The dashboard shows the include tree with the lookups of each branch.

### DKIM selectors

OpenWAF looks for DKIM keys at the selectors you pass, the `*._domainkey` names of the zone, the selectors of known
providers and common ones (`default`, `selector1`, `k1`, `s1`, `dkim`, `mail`…). RSA keys under 1024 bits are invalid;
under 2048 bits they are reported as weak.

## Set up a mail provider

**DNS › Email › Set up email** generates the records of a mailbox provider (Google Workspace, Microsoft 365, Zoho Mail,
Proton Mail, Fastmail, iCloud+ or another) and of sending services (Amazon SES, Resend, Mailgun, SendGrid, Brevo,
MailerLite):

1. **Providers.** Choose one mailbox (where mail is received) and any number of sending services.
2. **Details.** Paste the values each provider shows: DKIM key, verification code, region…
3. **Records.** Review the exact records to create, update, keep or delete, and the DMARC policy. OpenWAF keeps a
   single SPF record that merges your providers, counts its lookups and never tightens an existing `~all` without
   asking.
4. **Apply.** In a delegated zone, the records are applied as **one** version, which you can revert from the history.
   In an external zone, create them at your DNS provider by hand.


Start DMARC with `p=none` and a reporting address: after 2–4 weeks, when the reports show only your own services, move
to `p=quarantine` and then `p=reject`. The check reminds you while the policy is still `none`.

> **Caution**
>
> Never proxy mail names. Mail does not go through the edge, and proxying `mail`, `smtp` or an MX target breaks delivery.
> See [Proxied and DNS-only records](https://developers.openwaf.dev/fundamentals/proxied-and-dns-only/).
