SPF, DKIM and DMARC
These three DNS-based checks tell the world which servers may send mail for your domain, and let Mailocity tell real mail from forged mail when it arrives. This article covers both directions: the records your domain publishes, and the checks Mailocity runs on mail it receives.
Your domain's records
Each domain's DNS checklist (GET /v1/tenants/{id}/domains/{domain}/dns, and the domain screen in the admin panel from M2) lists an SPF record, one DKIM record per key and a DMARC record. The SPF and DMARC records are built from the domain's settings, so change the settings first, then copy the new values into your DNS.
| Setting | Default | What it does |
|---|---|---|
spfExtra | none | Other services allowed to send for the domain, such as a newsletter or CRM tool: include:<domain>, ip4:<address>[/bits], ip6:<address>[/bits], a, mx, a:<domain>, mx:<domain>. Up to 10 entries, of which at most 8 can be include, a or mx. |
spfAll | -all | -all tells receivers to fail mail from other servers; ~all asks them only to treat it with suspicion. Use ~all while you find every service that sends for you. |
dmarcPolicy | quarantine | What receivers do with mail that claims your domain but fails both SPF and DKIM: none (just report), quarantine (spam folder) or reject. |
dmarcSubdomainPolicy | same as policy | The policy for subdomains such as news.example.com. |
dmarcPercent | 100 | Apply the policy to only this share of failing mail while you roll it out. |
dmarcDkimAlignment, dmarcSpfAlignment | strict | Strict needs the signing or envelope domain to equal the From domain. Relaxed also accepts other names under the same registered domain, which some sending services need. |
dmarcCollect | on | Ask for daily aggregate reports at dmarc-reports@<domain> and keep them in Zappocity. See DMARC reports. |
dmarcReports | none | Up to 5 more addresses that receive daily aggregate reports. |
dmarcFailureReports | none | Up to 5 addresses for reports about single failing messages. Few receivers send these. |
Example: allow a newsletter service and move to reject:
PATCH /v1/tenants/{id}/domains/example.com
{"spfExtra": ["include:_spf.example-newsletters.com"], "dmarcPolicy": "reject",
"dmarcReports": ["dmarc@example.com"]}
A safe way to tighten DMARC
- Start with
dmarcPolicy: nonefor a couple of weeks while reports arrive (report collection is on by default). - Read the report summary and add any legitimate senders to
spfExtra(and set up DKIM with those services). - Move to
quarantine, optionally withdmarcPercentbelow 100, then toreject.
Reports sent to an address on another domain only arrive if that domain agrees to take them: it must publish a TXT record named example.com._report._dmarc.<its-domain> with the value v=DMARC1. The reports collected at dmarc-reports@<domain> need nothing extra; see DMARC reports.
Checks on incoming mail
Every message that arrives from another server on port 25 is checked before it is delivered:
- SPF: is the connecting server allowed to send for the envelope sender's domain (or, for bounces, for the name it introduced itself with)?
- DKIM: do the message's signatures verify against the keys in DNS? Up to five signatures are checked.
- DMARC: does SPF or DKIM pass for a domain that matches the visible From address, as the From domain's policy requires? If the From domain has no DMARC record, its registered domain's subdomain policy applies.
- ARC: if forwarders or mailing lists sealed the message, does their chain verify? See ARC.
The results are added to the message as an Authentication-Results header naming this server. Any header of that name that already claims to come from this server is removed first, so senders cannot forge a pass.
What happens when DMARC fails depends on the recipient domain's inboundAuth setting:
inboundAuth | Sender's policy is reject | Sender's policy is quarantine |
|---|---|---|
enforce (default) | Refused with 550 5.7.1 | Delivered to Junk |
junk | Delivered to Junk | Delivered to Junk |
tag | Delivered to the inbox | Delivered to the inbox |
More details:
- A message with no From address, or one that cannot be read, is handled like a quarantine failure.
- When a message has several From addresses, each one's domain is checked and the strictest result counts.
- If a DNS lookup fails temporarily, the message is delivered and the header says
temperror. - When one message is for several domains and only some of them would refuse it, it is accepted and those domains get it in Junk, because SMTP gives one answer per message.
- An SPF failure on its own, without a DMARC policy, is recorded but does not move the message. Spam scoring with Rspamd (planned for M1) will use it.
- Mail that your own users send through submission is not checked: signing in already proves who they are.
Not yet
- Letting a passing ARC chain from a trusted forwarder override a DMARC failure (planned with spam scoring).
- Report pages in the admin panels (M2); the API has them now.
- Settings screens in the admin panels (M2).