A throwaway address shows up in your signup form. Someone wants the free tier, the download, or the trial, and they have no intention of reading a single email you send. You only find out later, when your open rates sink and your bounce complaints climb. The fix most teams reach for first is manual review. A human scans the address, guesses whether it looks temporary, and decides. That approach does not survive contact with real traffic.
This is the disposable email domain problem. A disposable (or temporary) provider runs a domain whose only purpose is to hand out inboxes that delete themselves after a few minutes. Guessing these by eye does not scale, and it is inconsistent from one reviewer to the next.
What list-based detection actually does
The reliable approach is a list. You maintain a set of known disposable domains and check every address against it. MailProbe ships with a curated set of roughly 1,400 of these domains and matches the domain part of each address on every request. The check is a local lookup, which means it is fast and it costs no network round trip.
The numbers matter here. A human reviewer can hold maybe a few dozen suspicious domains in their head. A list of 1,400 covers the providers that account for the overwhelming majority of throwaway signups. When a new popular temp-mail site appears, you update the list once, and every caller benefits. Manual review would mean retraining every reviewer, every time.
The response makes the result plain:
curl "https://mailprobe.kevin-c0319.workers.dev/v1/verify?email=test@mailinator.com"
{
"email": "test@mailinator.com",
"valid": false,
"deliverable": false,
"reason": "disposable",
"score": 75,
"checks": { "syntax": true, "disposable": true, "free": false, "role": false },
"suggestion": null,
"provider": "self-hosted"
}
The disposable flag is true and reason is disposable. You can reject the signup or route it to a slower verification path without a second thought.
Where the check belongs in the pipeline
A verification call does several things: it checks syntax, looks up MX records over DNS, flags disposable and role addresses, and detects free providers. The disposable check is special because it needs no network. It is a dictionary lookup against a fixed set. That makes it cheap to run first.
The practical ordering is to clear the cheap, local checks (syntax, disposable, role, free) before spending a DNS query on the MX lookup. If the domain is on the disposable list, there is no reason to resolve its mail servers. You already know the answer. MailProbe returns the disposable flag in the same response as the MX data, so the caller gets the full picture in one call, but the local check is the one that should short-circuit the work.
A small wrapper keeps this readable in application code:
async function isDisposable(email) {
const res = await fetch(
"https://mailprobe.kevin-c0319.workers.dev/v1/verify?email=" +
encodeURIComponent(email)
);
const data = await res.json();
return data.checks?.disposable === true;
}
Keeping the list current is the real work
The code is the easy part. The set of disposable providers churns constantly. A site that is the popular choice this month is gone next month, and two new ones appear to take its place. A list of 1,400 domains is only useful if it is refreshed on a schedule, not committed once and forgotten.
The maintenance cost is low. Pull a diff against a maintained source once a week, and have a human review it so a legitimate domain is never added by mistake. The payoff is that the cheap check stays cheap. You are not spending a DNS query or an API call to catch an address the list would have flagged in microseconds. A stale list, by contrast, lets the newest temp-mail provider straight through until someone notices the signups piling up.
What list-based detection cannot catch
The honest part is that a list is only as good as its coverage, and there are three holes worth naming.
First, subaddressing defeats nothing here but is worth separating in your mind. user+tag@gmail.com is a real Gmail inbox, not a throwaway. The disposable list will not flag it, and it should not. It is a legitimate address that happens to use a plus tag.
Second, self-hosted throwaways are invisible to any static list. A determined user can register a fresh domain, point it at a tiny mail server that auto-expires inboxes, and your list will not contain it until someone adds it. This is rare and takes effort, so the volume is low, but it is a real gap.
Third, catch-all domains accept every recipient at the domain. A catch-all is not disposable, but it behaves oddly under verification, and conflating the two leads to mistakes. Catch-all handling is its own subject.
The point is not that list detection is perfect. It is that it removes the bulk of the problem for near-zero cost, and it does so consistently. Anything the list misses is either rare, or it is a different category of address that needs a different check. Combine the list with MX and syntax validation and you cover most of what matters.
I used MailProbe for the examples above because it returns the disposable flag, the MX records, and the provider fingerprint in one response. The endpoint is at https://mailprobe.kevin-c0319.workers.dev/. If you run your own verifier, the same principle applies: keep the disposable list local, check it early, and treat a miss as unknown rather than safe.
Top comments (0)