Cloudflare-fronted disposable detection


When a disposable-mail provider sits behind Cloudflare, the classical MX-fingerprint detection approach breaks. The MX record points at Cloudflare’s Email Routing infrastructure, not at the operator’s own back-end, so the MX hostname is route1.mx.cloudflare.net — a real Cloudflare-hosted MX that legitimate domains also use. You can’t blocklist Cloudflare. You can’t safely return disposable based on a Cloudflare MX hostname alone, because half the privacy-conscious indie-blog operators on the internet also use Cloudflare Email Routing for their personal forwarding.

This is the problem behind the weighted-disposable verdict. In our production database, 5,258 domains carry this verdict: domains we have strong reason to believe are disposable based on signals other than MX, but where we won’t return a hard result: undeliverable because the MX layer can’t confirm it. Real domains in this bucket include temp-mail.org, mail.tm, 33mail.com, simplelogin.io, and a few thousand smaller operators using Cloudflare’s infrastructure to host their disposable services without exposing their own MX servers.

This post: why Cloudflare is a detection problem, what signals we use instead, and how the weighted-disposable verdict differs from the standard disposable one.

Why MX-fingerprinting breaks at Cloudflare

The Tier-2 detection on our disposable email checker API does two things:

  1. Exact MX hostname match — if dig MX example.com returns gourmet.spamgourmet.com, that hostname matches a known operator MX backend and the domain is flagged.
  2. Parent-domain MX pattern match — if the MX is mx99.add5000.com, the parent add5000.com matches a regex pattern and the domain is flagged.

Both rely on the MX record exposing operator-specific infrastructure. Cloudflare’s Email Routing inverts that. The MX records look like:

$ dig +short MX temp-mail.org
1 route1.mx.cloudflare.net.
2 route2.mx.cloudflare.net.
3 route3.mx.cloudflare.net.

route1.mx.cloudflare.net is Cloudflare’s MX server. It hosts mail routing for millions of legitimate domains — small businesses, personal blogs, privacy enthusiasts forwarding to their main inbox. Treating “MX points at Cloudflare” as evidence of disposable would over-block by several orders of magnitude.

The fix isn’t a better MX rule. It’s a different signal layer.

Signals that survive Cloudflare

Five signals stack to produce the weighted-disposable verdict:

  1. Domain in known disposable blocklists. Even if MX detection fails, a brand new domain a public blocklist already lists is a strong signal. temp-mail.org is on every disposable list ever published.
  2. HTML scrape revealing temp-mail UI. The Playwright probe visits the apex domain, looks for keywords like “temporary email,” “disposable inbox,” “no signup,” and identifying UI patterns (the address-dropdown widget, inbox-by-URL pattern). If it scrapes as a temp-mail site, that’s a strong signal independent of MX.
  3. Fingerprint cluster match. If the apex shares AdSense, GA4, or GTM IDs with a known disposable operator, it joins that cluster. Detailed in our fingerprint-clustering post.
  4. Operator-self-reference. If the apex’s HTML lists multiple “available” mail domains in a dropdown, those domains are recorded as mail domains for that operator. The apex itself often qualifies.
  5. Customer-consensus. When ≥3 distinct vrfymail customers report bounces on a domain within 30 days, the domain promotes to a global flag. This works on Cloudflare-fronted domains the same as anywhere else — the MX layer doesn’t matter for bounce-feedback signals.

A domain scoring on 3+ of those 5 signals goes into the weighted-disposable bucket. The naming reflects the underlying uncertainty: we’re confident it’s disposable based on multi-signal evidence, but we can’t reach the same MX-corroborated confidence as a Tier-1 or Tier-2 hit, so we tag the verdict to reflect that.

What the verdict looks like at the API

A typical /v1/check response on a weighted-disposable domain:

{
  "result": "undeliverable",
  "reason": "disposable",
  "reason_message": "This email provider doesn't deliver mail reliably. Please use a real address.",
  "disposable": true,
  "score": 0.15,
  "trap": { "listed": false, "lists": [], "code": null }
}

A few notes. The top-level result is still undeliverable — your form’s primary handling path doesn’t change. The score field carries the underlying confidence: a Tier-1 hit returns score: 0.0 (highest confidence it’s bad), a weighted-disposable returns score: 0.15 (high confidence with a small uncertainty margin). If your handler wants finer control — accept anything with score > 0.5, flag 0.15-0.5, block ≤ 0.15 — the score is the lever.

The Cloudflare-fronted operators we’ve identified

A sample of weighted-disposable domains from the production table:

The full list extends to over 5,000 domains, dominated by the long tail of one-or-two-domain operators using Cloudflare’s free Email Routing tier as their MX layer. The big-name brands (temp-mail family, mail.tm, mailinator’s secondary domains) are the visible top.

Why Cloudflare doesn’t help us with their own infrastructure

This question comes up a lot. Cloudflare offers Email Routing as a free feature; abuse of it for disposable-mail providers is something they could in principle filter, but in practice doesn’t get tackled at scale. Our experience: Cloudflare-fronted disposable operators stay up indefinitely unless they trip a separate abuse signal (DMCA, phishing, fraud reports targeting another tenant). For our detection, the practical assumption is that any Cloudflare MX could be hosting a temp-mail product, and we need orthogonal signals to confirm.

What this changes for your signup form

The handling is the same as for a Tier-1 hit. The only difference is internal: how confident we are in the verdict. Your code doesn’t need to branch on score unless you want to:

if (verdict.result === "undeliverable") {
  // Includes both Tier-1 disposable hits and weighted-disposable hits.
  // reason_message is end-user copy already mapped per reason.
  return { error: verdict.reason_message };
}

If you want finer control — e.g., you’re running a free educational product where you’d rather accept a borderline case than reject a legitimate user — branch on score:

if (verdict.score < 0.05) {
  // High confidence undeliverable — block.
  return { error: verdict.reason_message };
}
if (verdict.score < 0.3) {
  // Weighted-disposable. Block in B2B, allow in B2C with soft warning.
  return { warning: verdict.reason_message };
}
// Accept.

Most signup flows ship the simpler version. The score is there for the cases that need it.

How the bucket grows

The weighted-disposable table grows from three sources, in order of contribution:

The bucket reaches ~5,300 net entries per month and growth tracks Cloudflare’s own adoption curve — every quarter, more disposable operators move behind Cloudflare’s free Email Routing instead of standing up their own MX infrastructure.

FAQ

Why have a separate verdict category at all? Just return disposable if you’re confident enough.

Two reasons. First, the score gives sophisticated handlers a lever — some customers want a softer block on edge cases. Second, the verdict category drives our internal monitoring; we want to know what percentage of “disposable hits” came from MX-corroborated detection vs evidence-stack inference. Those have different operational implications.

Are weighted-disposable verdicts more likely to be false positives?

Slightly. Our calibration target is <0.5% false positives across the whole verdict family. Tier-1 (disposable) hits run lower than that; weighted-disposable (weighted-disposable) runs at the high end of that envelope. If you’re customer-support-allergic to any false-block, branch on score and let weighted hits flow through with a flag instead of a hard reject.

Do Cloudflare-fronted alias-forwarders also use this verdict?

No — alias-forwarders get the alias-forwarder verdict regardless of MX provider. The verdict reflects mechanical behavior, not the hosting layer. The alias forwarder post walks through the mechanism.

Can a domain move from weighted-disposable to disposable?

Yes. If the operator stops fronting their service with Cloudflare and exposes a unique MX, the next refresh re-classifies the domain into the appropriate Tier-2 cluster. Movement in the other direction (Tier-1 to weighted-disposable) is rarer but happens when a previously-fingerprinted operator switches their MX to Cloudflare and we lose the original signal.

What if I want to allow legitimate Cloudflare Email Routing users without allowing temp-mail.org?

That’s already the behavior of the verdict. A legitimate personal domain on Cloudflare Email Routing has no other signals — no disposable blocklist entry, no temp-mail UI, no fingerprint cluster, no customer-consensus reports. It returns result: deliverable with no flag. The weighted-disposable verdict requires the multi-signal stack to fire, not just a Cloudflare MX.

Detect Cloudflare-fronted disposables in 50ms

The signal-stack approach runs on every /v1/check call. Free tier covers 5,000 verifies/month with no card. Get an API key →