Research

Blocking disposable email domains is the easy half

Alex MugoFounder, Kaidn
5 min readRevised
A list of throwaway domains catches the lazy attempt. The one that costs you money uses a real Gmail address, six times, and every heuristic you would reach for first is wrong.

We keep a list of throwaway email domains. It has 162,587 entries in it right now, refreshed hourly from several public sources plus our own reports, and it is the least interesting thing we do with email.

The list catches someone who could not be bothered. The signup that actually costs you money uses a real address at a real provider, and it does it six times.

What the list is genuinely good for#

It is worth being precise about what a disposable-domain check buys you, because it does buy something. Run four addresses through the checker and the difference is stark:

addressdisposableon an abuse listvalid MXscore
a@guerrillamail.comyesyesyes70
b@mailinator.comyesyesyes95
c@10minutemail.comyesnono80
d@proton.menonoyes0

That is a real filter and it costs one lookup. If you take nothing else from this, take the list: it removes a meaningful slice of low-effort abuse before it reaches your funnel.

The heuristic everyone reaches for, which does not work#

Ask most people how they would catch a throwaway domain without a list and they will suggest domain age. New domain, high risk. It sounds obviously right.

Here is the actual registration age of the three throwaway domains above:

domainage
mailinator.com23.1 years
guerrillamail.com19.7 years
10minutemail.com19.7 years

These are some of the oldest domains your signup form will ever see. They predate most legitimate SaaS companies. A domain-age rule does not merely miss them, it actively vouches for them, and it will penalise the genuinely new startup whose employee is trying to sign up.

Domain age is a useful signal for other things. It is close to useless for this one.

The half that actually matters#

The interesting problem is not "is this domain disposable." It is "have I seen this person before, wearing a different address."

Every major provider hands users several ways to write the same mailbox. Gmail ignores dots entirely. Anything after a + is a label, not an address. googlemail.com is the same service as gmail.com. Case never mattered. Stack those and one inbox produces effectively unlimited unique looking addresses, all of which pass every validity check you can throw at them, because they are all real.

  • ada.lovelace@gmail.comdots
  • a.d.a.lovelace@gmail.comdots
  • adalovelace+shop@gmail.complus tag
  • adalovelace+shop2@googlemail.complus + domain
  • AdaLovelace@Gmail.comcase
  • adalovelace@gmail.comthe actual inbox
arrow_forward
One identity key
adalovelace@gmail.com

Six accounts that looked unrelated are one person.

Six signups, six different addresses, one mailbox

None of those six is disposable. None is malformed. All of them deliver. Every one would sail through a signup form, and to a database keyed on the raw string they are six different customers claiming six welcome bonuses.

The check that matters reduces the address to its canonical form before it ever looks at the domain:

six addresses, one mailbox
ada.lovelace@gmail.com            →  adalovelace@gmail.com
a.d.a.lovelace@gmail.com          →  adalovelace@gmail.com
adalovelace+shop@gmail.com        →  adalovelace@gmail.com
adalovelace+shop2@googlemail.com  →  adalovelace@gmail.com
AdaLovelace@Gmail.com             →  adalovelace@gmail.com

One identity key. Six accounts that looked unrelated are one person, and you can see it at signup rather than at payout.

The rules are provider-specific, which is why doing it properly is more work than it looks. Dots are meaningless at Gmail and meaningful nearly everywhere else. Strip them globally and you will merge two genuinely different people at a provider that treats them as distinct, which is a worse failure than missing a duplicate.

Doing it without building it#

Every one of the checks above runs on a single lookup, and there is a standalone email endpoint so you do not have to spend a scoring event to see one:

Terminal
curl -s -X POST https://api.kaidn.io/v1/check/email \
  -H "x-api-key: $KAIDN_API_KEY" \
  -H "content-type: application/json" \
  -d '{"email":"a.d.a.lovelace+shop@googlemail.com"}'
response
{
  "email": {
    "fraud_score": 12,
    "canonical": "adalovelace@gmail.com",
    "is_aliased": true,
    "alias_tricks": ["dot_trick", "plus_tag", "domain_alias"],
    "has_plus_tag": true,
    "is_disposable": false,
    "mx_valid": true,
    "catch_all": false,
    "looks_gibberish": false,
    "is_malformed": false
  },
  "reputation": { "recent_abuse": false, "network_risk": 0 },
  "summary": "Real Gmail mailbox reached through three aliasing tricks. Not disposable."
}

canonical is the field to key your accounts on. Everything else is evidence about the domain; that one line is the identity.

On a scored event the same work shows up as two separate checks, which is the point of the section below: emailRisk reports what the address IS, and emailReuse reports how many accounts the canonical mailbox is already behind.

the two email checks on a verdict
const r = await kaidn.score({ event: "signup", user_id, ip, email, device_id });

// "This mailbox is behind 4 accounts" is the finding. The aliasing is how it hid.
const reuse = r.checks.find((c) => c.check === "emailReuse");
if (reuse) console.log(reuse.message, reuse.evidence);

What else the inbox tells you#

Beyond disposability and aliasing, an address carries infrastructure that is much harder to fake than the address itself:

  • MX records. A domain with none cannot receive mail. 10minutemail.com above has no valid MX and still accepts signups everywhere.
  • SPF and DMARC. Whether the domain publishes sender authentication at all.
  • Catch-all. A domain that accepts every address means the local part tells you nothing, so anything@theirdomain.com is infinite free addresses.
  • Mail host. Where the MX actually points. A "company" domain whose mail is served from a VPS the same operator rents is a different proposition to one on Google Workspace.
  • Role accounts. info@, support@, admin@. Not a person.
  • Gibberish. Machine-generated local parts, scored on the canonical form so aliasing cannot hide them.

The mistake we made ourselves#

Here is one worth admitting, because it is easy to get wrong in the same direction.

We used to score every one of those signals independently and add them up. That seems obviously correct until you notice that a throwaway domain trips several of them at once: it is on the disposable list and on an abuse list and frequently has no MX. One fact, counted three times, and the score inflates accordingly.

Worse, it inflated in the wrong direction on legitimate users too. A real customer who signs up with adalovelace+shop@gmail.com was scored for plus-addressing and for aliasing. Two penalties for one entirely reasonable habit that plenty of careful people have.

Correlated signals now collapse: within a cluster only the strongest scores, while every detection is still reported as evidence. Our labelled fixtures did not move at all on the fraud cases. The only thing that changed was that legitimate plus-addressed user, whose score dropped by 40%.

If you are building scoring of your own, that is the trap. Adding more signals feels like adding more accuracy. If the signals are correlated you are mostly adding confidence to a number that has not learned anything new.

What to actually do#

If you are starting from nothing, in order of return on effort:

  1. Canonicalize before you store. Even if you do nothing else, key your accounts on the canonical address. This is the one that catches repeat signups.
  2. Check the disposable list. Cheap, and it clears out the low-effort attempts.
  3. Check MX. A domain that cannot receive mail is not a customer.
  4. Do not use domain age for this. It fails on the exact cases you care about.
  5. Watch for correlation in whatever you score, so one fact does not become three.

You can run any address through the free email checker with no account. It returns the same report the API does, canonical form included.

Frequently asked questions

Should I block disposable email addresses outright?

Usually not. Block on evidence rather than on a single flag. Throwaway domains do correlate with abuse, but a score that combines the inbox with the device, the IP and the account history will be right more often than a hard rule on one field, and a hard rule costs you the legitimate users who happen to use a privacy provider.

Why not just block plus-addressing?

Because plenty of legitimate, privacy-conscious people use it deliberately, and blocking them costs you real customers. Collapse aliases to one canonical identity so you can count them, then decide based on how many accounts that single inbox has actually opened. Counting is the useful operation; refusing is not.

Does domain age work as a disposable-email signal?

No, and it fails in the worst possible direction. mailinator.com is 23.1 years old, guerrillamail.com and 10minutemail.com are both 19.7 years old. These are among the oldest domains a signup form will ever see, so a domain-age rule does not merely miss them, it actively vouches for them while penalising the genuinely new startup whose employee is trying to sign up.

Does email checking work without a device fingerprint?

It helps on its own, but the inbox is one entity among several. In practice the strongest duplicate-account signal is usually the device, and the inbox is what confirms it. Two accounts sharing a device is ambiguous (a household, an office); two accounts sharing a canonical mailbox is not, because the person who receives the mail is the same person.

Why is canonicalisation provider-specific?

Because the rules genuinely differ. Dots are meaningless at Gmail and meaningful nearly everywhere else, so stripping them globally merges two different people at a provider that treats them as distinct. That is a worse failure than missing a duplicate, which is why doing this properly is more work than the one-line regex it looks like.

How large is the disposable-domain list, and how often does it change?

162,587 entries at the time of writing, refreshed hourly from several public sources plus first-party reports. The number matters less than the refresh: public lists lag new domains by weeks, which is precisely why the list is the easy half and identity resolution is the half that catches anybody who is trying.

emaildisposable emailidentityfraud signals

Score your own traffic

10,000 events a month on the free tier, no card. One POST to /v1/score and you get a verdict with the evidence behind it.

Read next