The cheapest way to check if a domain can receive email is an MX record check, and it costs nothing. We ran one across 80,590 distinct domains on a client's prospect list last week. 10,884 of them, about 13.5%, had no mail server published at all.
Every address on those 10,884 domains was a guaranteed hard bounce before anyone wrote a single line of copy. Nobody had checked, because the list came out of an enrichment pipeline and enrichment pipelines are trusted by default.
The short version
- An MX record check tells you whether a domain can receive mail at all, and who hosts the mailbox if it can.
- Across 80,590 domains, 10,884 (~13.5%) published no mail server. All of them were guaranteed hard bounces.
- Google's public DNS-over-HTTPS endpoint does the lookup for free: no key, no signup, ~70 lookups per second, 19 minutes for the whole list.
- The bounce filter mattered more than the provider labels, and neither one tells you whether the mailbox itself exists.
What an MX record check actually tells you
An MX record is the domain's published answer to the question "which server handles mail for me". It is public, it is free to query, and it is the only part of a prospect list you can verify without touching the recipient.
No MX record means no mail server. Not a slow one, not a strict one: nothing accepts mail for that domain, so the message bounces at the first hop.
That makes the check a hard filter, and hard filters are rare in list building. Most list quality signals are probabilistic. This one is closer to arithmetic.
The second thing it tells you is who hosts the mailbox. The MX hostname is where the routing lives, and the string is usually unambiguous: Microsoft, Google, a regional host, or something a system administrator set up themselves.
The build: a free DNS endpoint and a derived column
We resolved every distinct domain against Google's public DNS-over-HTTPS endpoint, which returns JSON over plain HTTPS with no API key and no account.
How the classification runs
Collapse to distinct domains
Contacts on the same domain resolve once. 80,590 unique lookups instead of one per row.
Resolve MX over HTTPS
Google's public DNS JSON endpoint, ~70 lookups per second, no key required.
Label the provider
Substring match the MX hostname against a known-host list (google, outlook, aruba, siteground); anything unmatched falls through to self-hosted.
Flag the empty answers
No MX record means the domain cannot receive mail. Those rows never reach the sender.
Two columns get written back onto the list: the raw mx_record and a derived email_provider label. Both are stored, not computed at send time, so the next campaign inherits the work.
The full backfill took 19 minutes. That number is not a benchmark of the endpoint, it is the pace we chose to stay polite; DNS answers are tiny and cached, so the constraint is manners rather than money.
What the distribution looked like
The provider split was regional in a way no generic list-hygiene tool would have predicted: roughly 29,500 domains ran self-hosted mail, with the rest spread across the large platforms and country-specific hosts like Aruba (~2,500) and SiteGround (~1,700).
Self-hosted mail on that scale changes how you send. Big platforms have published, well-understood filtering behaviour; a self-run server in a small company is more likely to greylist, to enforce odd rate limits, or to be quietly misconfigured.
Insight
That ordering surprised us. We built the provider labels first, because that was the interesting engineering problem, and found the boring byproduct was worth more.
Why we stored the raw MX string, not just the label
Provider labels drift. A domain that reads as self-hosted today can move to a hosted platform next quarter, and a label alone gives you no way to notice the change or to audit how the label was assigned.
Keeping the raw MX hostname next to the label means three things. Re-labelling never requires re-resolving the list, which matters when the rules change and the list has tens of thousands of rows. Disputes about a bad label get settled by reading the string rather than re-running the pipeline. And new host patterns can be spotted by grouping the raw strings, which is how the country-specific hosts showed up in the first place: not because we went looking for them, but because the same unfamiliar hostname appeared several thousand times.
The cost of storing both is one text column. The cost of storing only the label is a re-resolve every time the classification rules move.
The honest limit: MX presence is not mailbox existence
An MX record proves the domain accepts mail. It proves nothing about the specific person at that domain.
marco@hotelexample.it can fail on a domain with perfect MX configuration, because that mailbox was closed two years ago. The check removes guaranteed bounces; it does not confirm the remaining addresses are live, and it is not a replacement for verification.
The right way to read it is as a free pre-filter that runs before the paid one. Verification tools bill per address, so removing 10,884 dead domains before verification also removes their share of the verification bill.
It is also worth saying that a domain with no MX record is not always a dead business. Small operators sometimes run their entire correspondence through a personal free mailbox and never configure their own domain for mail. The business is real, the domain address is not.
What to do with this on Monday
Run the check on your current list before your next send. It needs one script, no vendor, and the answer arrives in minutes.
If a meaningful share of your domains come back empty, the interesting question is not the list, it is the pipeline that produced it. Ours was silently passing through unmailable domains because nothing in the chain had ever been asked to look.
Key takeaways
- A domain with no MX record cannot receive mail, so every address on it is a hard bounce you can remove for free before sending.
- MX lookups over public DNS-over-HTTPS need no API key and no vendor, which makes list hygiene a script rather than a purchase.
- Store the raw MX hostname alongside the provider label so re-classification never requires re-resolving the list.
- MX presence is not mailbox existence: this filter runs before paid verification, it does not replace it.
- Check the pipeline, not just the list. Dead domains reaching a sender usually means nothing upstream was ever asked to validate them.
Related reading: the technical foundation for cold email deliverability covers the sending side of this, and how to build a lead list that converts covers what happens before the domains ever reach a validation step. If you want this kind of check running inside your own operations rather than as a one-off, that is the sort of thing we build into companies.
Common questions
How do you check if a domain can receive email?
Look up the domain's MX records. If a domain returns no MX record, no mail server is published for it and every message sent to an address on that domain will hard-bounce. Google's public DNS-over-HTTPS endpoint answers this for free, with no key and no signup.
What does an MX record tell you about a prospect list?
Two things. Whether the domain can receive mail at all, and who hosts the mailbox: Microsoft 365, Google Workspace, a regional host, or a self-run server. The first is a bounce filter, the second decides how you route and pace the sending.
How long does an MX record check take on a large list?
We resolved 80,590 distinct domains at roughly 70 lookups per second, which finished in 19 minutes. DNS answers are small and cacheable, so throughput is limited by politeness, not by cost.