Whether a message is delivered, sent to spam or rejected depends to a large degree on a handful of DNS records published by the sender's and the recipient's domains. This guide explains what each one does and how receiving servers use it. The Email DNS check reads all of them for a domain and applies the rules described here.
MX: where mail for a domain goes
An MX record names a host that accepts mail for the domain, with a priority number. Senders try the lowest number first and fall back to higher ones when a host does not answer; hosts with the same number share the load.
example.com. 3600 IN MX 10 mx1.example.com.
example.com. 3600 IN MX 20 mx2.example.com.
Rules worth knowing:
- The target must be a host name with its own A or AAAA record. An IP address is not allowed, and RFC 2181 (section 10.3) forbids pointing an MX at an alias (CNAME).
- Without any MX record, senders deliver to the A/AAAA address of the domain itself (RFC 5321, section 5.1). This works only if that host runs a mail server.
- A domain that never receives mail should publish a null MX, a single record
0 .(RFC 7505). Mail to it is rejected at once instead of being retried for days.
SPF: who may send as the domain
SPF (RFC 7208) is a TXT record at the domain that lists the servers allowed to send mail with that domain in the envelope sender (the MAIL FROM address, also called Return-Path).
example.com. IN TXT "v=spf1 ip4:192.0.2.0/24 include:_spf.provider.example ~all"
The receiver compares the connecting server's IP address with the terms from left to right and stops at the first match. The qualifier in front of a term decides the result: + pass (the default), - fail, ~ softfail, ? neutral.
| Term | Matches |
|---|---|
ip4:, ip6: | an address inside the given network |
a, a:host | the A/AAAA addresses of the domain or of host |
mx, mx:host | the addresses of the domain's MX hosts |
include:domain | whatever the SPF record of domain allows |
exists:name | if name has an address record (used with macros) |
all | everything; it belongs at the end |
redirect=domain | use another domain's record if nothing matched |
The limit of 10 DNS lookups
The terms include, a, mx, ptr, exists and the redirect modifier each cause DNS queries. RFC 7208 (section 4.6.4) caps them at 10 for the whole evaluation, nested includes included. A receiver that reaches the 11th returns permerror, and DMARC treats that as a failure. The count is easy to exceed without noticing, because every provider's include brings its own includes. The checker follows the whole tree and adds them up.
Two further limits from the same section: an mx term may not return more than 10 MX records, and no more than two lookups may come back empty ("void lookups": NXDOMAIN or no data).
Common SPF mistakes
- Two SPF records. A domain must publish exactly one TXT record starting with
v=spf1; with two, every check ends in permerror. Merge them. +allauthorises every server on the Internet.?allsays nothing. Use~allor-all.ptris slow and unreliable and should not be used (RFC 7208, section 5.5).- Terms after
allare never evaluated. - A domain that sends no mail at all should publish
v=spf1 -all.
DKIM: a signature that survives forwarding
DKIM (RFC 6376) lets the sending server sign parts of each message with a private key. The signature header names a selector (s=) and a domain (d=); the receiver fetches the public key from selector._domainkey.domain and verifies that the signed headers and body were not changed.
s1._domainkey.example.com. IN TXT "v=DKIM1; k=rsa; p=MIIBIjANBgkqh..."
- Selectors cannot be listed. DNS has no way to enumerate them, so a checker can only try common names. If none is found, look at the
s=value in theDKIM-Signatureheader of a real message and check that selector. - Key size. RFC 8301 requires verifiers to reject RSA keys under 1024 bits and recommends at least 2048 bits for signers.
t=ymarks a key as in testing: receivers may treat failed signatures as if the message were unsigned.- An empty
p=means the key has been revoked. - Ed25519 keys (
k=ed25519, RFC 8463) are smaller, but not every receiver verifies them yet, so they are usually published alongside an RSA key.
DMARC: what to do when checks fail
DMARC (RFC 7489) ties SPF and DKIM to the address people see, the From: header. A message passes DMARC when SPF or DKIM passes and the domain it authenticated is aligned with the From domain. The record at _dmarc.domain tells receivers what to do with mail that fails, and where to send reports.
_dmarc.example.com. IN TXT "v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com"
| Tag | Meaning |
|---|---|
p= | policy for the domain: none (report only), quarantine (treat as suspicious), reject |
sp= | policy for subdomains; if absent, p= applies |
pct= | percentage of failing mail the policy applies to (default 100) |
rua= | where aggregate reports go |
ruf= | where failure reports for single messages go; few receivers send them |
adkim=, aspf= | alignment: r relaxed (subdomains match, the default) or s strict |
How a policy is usually rolled out:
- Publish
p=nonewith arua=address and read the reports for a few weeks. - Fix every legitimate source that fails (a newsletter service without DKIM, a server missing from SPF).
- Move to
p=quarantine, then top=reject.
Things that go wrong:
- No
rua=: there are no reports, so you cannot see who sends as your domain. - Reports to another domain: if
rua=points outside your domain, that domain must publishyourdomain._report._dmarc.theirdomainwithv=DMARC1, or receivers will not send the reports (RFC 7489, section 7.1). Report services normally do this for you. - More than one DMARC record: receivers then apply no DMARC at all.
- Subdomains: with no record of its own, a subdomain is covered by the parent domain's record and its
sp=policy.
MTA-STS: make senders insist on TLS
Mail between servers is usually encrypted with STARTTLS, but an attacker on the path can remove the offer and read the traffic. MTA-STS (RFC 8461) lets a domain declare that senders must use TLS with a valid certificate, and only towards listed MX hosts. It has two parts: a TXT record at _mta-sts.domain with a version and an id, and a policy file served over HTTPS at https://mta-sts.domain/.well-known/mta-sts.txt:
version: STSv1
mode: enforce
mx: mx1.example.com
mx: *.example.net
max_age: 1209600
mode: testingreports problems but still delivers;enforcerefuses delivery that does not meet the policy.- Every MX host must match an
mx:line, where*.stands for exactly one label. An MX added without updating the policy stops receiving mail from enforcing senders. - The policy must be answered with HTTP 200, without redirects, and over a valid certificate for
mta-sts.domain. max_ageis at most 31557600 seconds (one year); RFC 8461 expects values of weeks or more.- Change the
idin the TXT record whenever the policy changes, so senders fetch it again.
TLS-RPT: hear about TLS failures
With a TXT record at _smtp._tls.domain (RFC 8460), sending servers send you a daily report of failed TLS connections to your servers.
_smtp._tls.example.com. IN TXT "v=TLSRPTv1; rua=mailto:tls-reports@example.com"
It is optional on its own, but with MTA-STS in enforce mode it is the way to learn that an expired certificate is blocking mail.
BIMI: a logo next to authenticated mail
BIMI lets mailboxes that support it show a brand logo next to messages that pass DMARC. The record lives at default._bimi.domain; l= points to the logo, an SVG file in the SVG Tiny Portable/Secure profile, and a= to a mark certificate that several large mailbox providers require.
default._bimi.example.com. IN TXT "v=BIMI1; l=https://example.com/logo.svg; a=https://example.com/vmc.pem"
BIMI is only processed when the DMARC policy is enforced: not p=none, not sp=none, and with pct at 100 (draft-brand-indicators-for-message-identification, section 7.1).