Method
How the MailSetupCheck checker and calculator work
Every rule the email setup checker applies and the standard it comes from, what it can and cannot see from DNS, the DKIM selectors it tries, how it recognizes mail providers, and where the cost calculator's prices come from.
Principles
- Standards and providers' own pages, nothing else. Every rule cites an RFC or a mailbox provider's published requirement. Every price links to the vendor's own pricing page with the date it was read.
- Say what cannot be known. DNS shows what a domain publishes, not how its mail is actually sent. The checker says so wherever it matters, and never reports a guess as a finding.
- Unknown stays unknown. A failed lookup becomes "could not check", never "missing". A price the vendor does not publish shows as "Check vendor", never as zero.
- Tested before every deploy. The rules are a plain JavaScript module tested against recorded DNS answers (no network in the tests), including real records copied from live domains.
How a check runs
- Your browser normalizes what you typed (a URL or an email address becomes a bare domain; "www." is dropped; international names become their ASCII form).
- It asks Cloudflare's public DNS-over-HTTPS service (
cloudflare-dns.com) each question, and Google Public DNS (dns.google) if Cloudflare fails or answers SERVFAIL. Requests are sent without cookies or a referrer. MailSetupCheck has no server in this path. - Answers are cached for the length of the check, and the check stops after 150 distinct questions so that an enormous SPF tree cannot run forever. A typical domain needs 40 to 50.
- The results are turned into findings by fixed rules, below, and sorted into three tiers.
The rules
MX
- No MX records and no SPF or DKIM: the domain probably does not send mail, and the checker suggests locking it down (
v=spf1 -all,v=DMARC1; p=reject;, and a null MX, RFC 7505). - No MX records on a domain that sends mail: replies and bounces have nowhere to go (should fix).
- Providers are recognized by the end of each MX host name; the list is below.
SPF (RFC 7208)
- Exactly one
v=spf1TXT record; two or more is a permanent error (section 4.5). - Syntax: every mechanism and modifier, IPv4 and IPv6 addresses and prefix lengths, domain names. Unknown mechanisms are a permanent error.
- Every
includeandredirectis followed.include,a,mx,ptr,existsandredirectare counted against the limit of 10 across the whole tree, and lookups that return no records against the void limit of 2 (section 4.6.4). The count assumes the worst case, a sending server that matches nothing, because that is when every term is evaluated. Terms afterall, andredirectnext toall, are not counted because receivers never evaluate them (section 6.1). - An
mxterm whose domain has more than 10 MX hosts is a permanent error, since checking it takes more than 10 address lookups. - Terms with macros (
%{i}and the like) are counted but not resolved; they depend on each message. +allor a bareallis a must-fix;?allor noallis a should-fix;ptris a should-fix ("SHOULD NOT be published", section 5.5).
DMARC (RFC 9989, which replaced RFC 7489 in May 2026)
- Discovery:
_dmarc.<domain>, then the DNS tree walk of section 4.10 (each parent in turn, at most eight queries), choosing the Organizational Domain's record by thepsd=rules of section 4.10.2. A subdomain that inherits its policy getssp=(orp=). - Two or more records at one name are discarded (must fix).
- A record without
p=is read asp=none, as RFC 9989 specifies; an invalidp=without a report address makes the record invalid. pctis still read, because receivers that follow RFC 7489 apply it, but a value below 100 gets a note that RFC 9989 receivers ignore it.t=yis read as test mode.- Report addresses at another organization need an authorization record at
<policy domain>._report._dmarc.<report domain>(RFC 9990, section 4); the checker looks it up. Whether a report address belongs to another organization is decided with a short list of two-label public suffixes (such as co.uk) rather than the full Public Suffix List, which can misjudge rare suffixes.
DKIM (RFC 6376)
- Keys are looked up at
<selector>._domainkey.<domain>for the selector you enter and the 34 common selectors below. A selector that is a CNAME to a name with no key (typical when Microsoft 365 DKIM was set up in DNS but never switched on) is reported as such. - Key size is read from the key itself (the RSA modulus in the public key). Under 1024 bits is a must-fix (Gmail and Yahoo require 1024, as does RFC 8301); exactly 1024 is a should-fix (2048 is recommended). Ed25519 keys (RFC 8463) are recognized. An empty
p=is a retired key, normal during rotation if another key is live. - If no key turns up, the checker also asks for
_domainkey.<domain>itself. A correctly run DNS server answers "no such name" when nothing exists beneath it (RFC 8020), and "no data" when names exist below it. The checker reports that as a hint, not a verdict, because some DNS servers get it wrong.
MTA-STS, TLS-RPT and BIMI
- MTA-STS (RFC 8461): exactly one
v=STSv1record at_mta-stswith a validid, and a hostmta-sts.<domain>that resolves. The policy file itself cannot be fetched from a web page (browsers block cross-site reads, and this site's security policy allows connections only to the two DNS resolvers), so the checker links to it instead. - TLS-RPT (RFC 8460): one
v=TLSRPTv1record at_smtp._tlswith mailto: or https: report addresses. - BIMI (draft specification, BIMI Group): a record at
default._bimi, an https SVG logo, DMARC at quarantine or reject applied to all mail, and a certificate (a=), which Gmail requires. - MTA-STS and TLS-RPT are suggested only for domains that receive mail; BIMI only once DMARC is at enforcement.
The tiers
- Must fix to send to Gmail at volume: what Gmail, Yahoo or Microsoft require of bulk senders (SPF, DKIM, DMARC), and anything that breaks a record outright (two SPF records, more than 10 lookups,
+all, invalid DMARC, keys under 1024 bits). - Should fix: monitoring-only DMARC, missing reports, weak SPF endings,
ptr, 1024-bit keys, test modes, unprotected subdomains. - Nice to have: MTA-STS, TLS-RPT, BIMI, very long SPF records.
What the checker cannot see
Alignment of real messages, the reverse DNS and TLS of your sending servers, spam rate, unsubscribe headers, message content, and DKIM keys at selectors it did not try. The home page explains how to check each one yourself.
DKIM selectors tried
A selector is a name chosen by the provider or the domain's admin, so this list can only cover conventions. "dns:" means the convention was confirmed by looking up the provider's own domain on 7 October 2026. Amazon SES, HubSpot and Postmark use account-specific selectors that cannot be guessed.
| Selector | Usually used by | Source |
|---|---|---|
google |
Google Workspace (default) | provider documentation |
selector1 |
Microsoft 365 | provider documentation |
selector2 |
Microsoft 365 | provider documentation |
s1 |
SendGrid | provider documentation |
s2 |
SendGrid | provider documentation |
m1 |
SendGrid (without automated security) | dns:m1._domainkey.sendgrid.com |
k1 |
Mailchimp (older setups) | dns:k1._domainkey.mailchimp.com |
k2 |
Mailchimp | dns:k2._domainkey.mailchimp.com |
k3 |
Mailchimp | dns:k3._domainkey.mailchimp.com |
mte1 |
Mailchimp Transactional (Mandrill) | dns:mte1._domainkey.mailchimp.com |
mte2 |
Mailchimp Transactional (Mandrill) | dns:mte1._domainkey.mailchimp.com |
brevo1 |
Brevo | provider documentation |
brevo2 |
Brevo | provider documentation |
mail |
Brevo (older setups) and others | dns:mail._domainkey.brevo.com |
km1 |
Klaviyo (marketing) | provider documentation |
km2 |
Klaviyo (marketing) | provider documentation |
kt1 |
Klaviyo (transactional) | provider documentation |
kt2 |
Klaviyo (transactional) | provider documentation |
ctct1 |
Constant Contact | provider documentation |
ctct2 |
Constant Contact | provider documentation |
mailjet |
Mailjet | dns:mailjet._domainkey.mailjet.com |
resend |
Resend | dns:resend._domainkey.resend.com |
zoho |
Zoho Mail (the example name in Zoho's guide; admins choose their own) | provider documentation |
fm1 |
Fastmail | provider documentation |
fm2 |
Fastmail | provider documentation |
fm3 |
Fastmail | provider documentation |
protonmail |
Proton Mail | dns:protonmail._domainkey.proton.me |
protonmail2 |
Proton Mail | dns:protonmail2._domainkey.proton.me |
protonmail3 |
Proton Mail | dns:protonmail._domainkey.proton.me |
sig1 |
iCloud+ custom email domains | provider documentation |
x |
MXroute | provider documentation |
default |
cPanel and other hosting control panels | dns:default._domainkey.cpanel.net |
cf2024-1 |
Cloudflare Email Routing (signs forwarded mail) | provider documentation |
dkim |
Generic name some providers and admins use | generic convention |
Mail providers recognized
| Provider | Kind | MX host names ending in | SPF include suggested |
|---|---|---|---|
| Google Workspace | mailbox | google.com, googlemail.com | _spf.google.com |
| Microsoft 365 | mailbox | mail.protection.outlook.com, mx.microsoft | spf.protection.outlook.com |
| Zoho Mail | mailbox | zoho.com, zoho.eu, zoho.in, zoho.com.au, zoho.jp, zoho.sa, zohocloud.ca | zohomail.com |
| Fastmail | mailbox | messagingengine.com | spf.messagingengine.com |
| Proton Mail | mailbox | protonmail.ch | _spf.protonmail.ch |
| iCloud+ custom email domain | mailbox | mail.icloud.com | icloud.com |
| MXroute | mailbox | mxrouting.net | none (generic advice) |
| Yahoo | mailbox | yahoodns.net | none (generic advice) |
| GoDaddy email | mailbox | secureserver.net | none (generic advice) |
| Namecheap Private Email | mailbox | privateemail.com | none (generic advice) |
| Rackspace Email | mailbox | emailsrvr.com | none (generic advice) |
| Titan Email | mailbox | titan.email | none (generic advice) |
| IONOS | mailbox | ionos.com, ionos.de, ionos.co.uk, kundenserver.de | none (generic advice) |
| Migadu | mailbox | migadu.com | none (generic advice) |
| Amazon WorkMail or SES inbound | mailbox | amazonaws.com | none (generic advice) |
| Mimecast | gateway | mimecast.com, mimecast.co.za | none (generic advice) |
| Proofpoint | gateway | pphosted.com, ppe-hosted.com | none (generic advice) |
| Barracuda | gateway | barracudanetworks.com | none (generic advice) |
| Cisco Secure Email | gateway | iphmx.com | none (generic advice) |
| Cloudflare Email Routing | forwarding | mx.cloudflare.net | _spf.mx.cloudflare.net |
| ImprovMX | forwarding | improvmx.com | none (generic advice) |
An SPF include is suggested only where the provider's own setup page states it. A "gateway" filters mail before it reaches your real mailbox provider; "forwarding" services receive mail but cannot send it for you.
The cold email cost calculator
- Prices: US list prices from each vendor's own pricing page, read on the date shown next to each price (prices.json). Promotions are noted but not used. Where a page shows no price we could read, the calculator says "Check vendor" and leaves totals that depend on it blank.
- Plan choice: for each sequencer, the cheapest plan whose monthly email limit, contact limit and inbox limit cover your inputs; per-user plans are multiplied by the users needed for your inboxes.
- Verification: the cheaper of a monthly plan that covers every new prospect, or pay-as-you-go packs.
- Ramp: warmup weeks with no cold email, then 10 a day per inbox rising by 5 a week, from lemlist's published limits. Both numbers are editable.
- Re-reading: prices are re-read monthly and when a vendor announces a change; the SPF include costs on the SPF guide are re-measured with
data/mail/measure_spf_includes.mjs.
Conflicts of interest
MailSetupCheck may earn referral commissions from some vendors it mentions; the affiliate disclosure lists them. Commissions do not change the rules, the tiers, or the order of the calculator's table, which is sorted by price.
Also available as Markdown.