DEV Community

kevinc0319-prog
kevinc0319-prog

Posted on

Catch-all email domains and the false positives they cause

A catch-all domain is one whose mail server accepts messages for every address at the domain, whether or not the local part was ever created. Send to ceo@bigco.com, asdfgh@bigco.com, or this-does-not-exist@bigco.com, and the server takes the mail. The mailbox may or may not be read by anyone. The server does not say.

This is a legitimate configuration. Small companies turn it on so they never miss a typo'd address, and it is common among firms that route everything to one inbox or to a ticketing system. The trouble starts when a verification service meets a catch-all domain and has to decide what to report.

Why catch-all breaks the usual checks

The two checks people lean on are syntax validation and MX lookup. Syntax confirms the address is well formed. MX confirms the domain runs a mail server. Neither can see inside the domain to learn whether a specific local part is a real inbox.

A catch-all domain passes both. Its MX records are present and valid, so a verifier that stops at "domain can receive mail" reports the address as deliverable. It is, in the weak sense that the server will accept the connection. But that tells you nothing about whether a human reads randomstring@bigco.com.

The false positive appears here. A service reports deliverable: true for an address that is, for all practical purposes, garbage, because the domain is configured to swallow everything. The report is not lying about the domain. It is overclaiming about the inbox.

curl "https://mailprobe.kevin-c0319.workers.dev/v1/verify?email=info@stripe.com"
Enter fullscreen mode Exit fullscreen mode
{
  "email": "info@stripe.com",
  "valid": true,
  "deliverable": true,
  "reason": "ok",
  "score": 85,
  "checks": {
    "syntax": true,
    "mx": {
      "ok": true,
      "records": [{ "exchange": "aspmx.l.google.com", "priority": 10 }],
      "source": "dns"
    },
    "role": true
  },
  "provider": "google-workspace"
}
Enter fullscreen mode Exit fullscreen mode

That response confirms the domain is real and accepts mail. What it cannot do, with an MX-only check, is confirm that info is the only valid local part, or that some other local part would bounce. On a catch-all domain, the same shape of response would come back for an address no one monitors.

The deeper problem with SMTP here

You might think SMTP probing settles it. Connect, ask the server if the inbox exists, read the code. On a catch-all domain the server answers "yes" to every probe, because accepting everything is the whole point. So SMTP does not rescue you. It returns the same misleading 250 for real and fake local parts alike.

Some verification vendors react by tagging catch-all domains as "risky" and lowering the score. That is a reasonable signal, but it is easy to overuse. A catch-all domain is not a disposable domain. The people using info@ and sales@ on a catch-all are often exactly the business leads you want. Flagging the whole domain as low quality throws those out with the noise.

The signal you do have is the score

When a verifier knows a domain is catch-all, the useful move is to lower confidence without binning the address. MailProbe does not expose a catch-all flag, but it reports role and free, and both overlap with catch-all use in practice. sales@ and info@ on a catch-all domain are exactly the business leads you most want to keep. Treating the domain as risky because of its catch-all configuration, rather than because of the specific address, is the error that costs you those leads.

The honest framing is that a catch-all domain is a confidence problem, not a validity problem. The domain is real and it accepts mail. What you lack is proof about the local part. Lower the score if you must, but route the address to confirmation rather than rejection. The confirmation step resolves the uncertainty for free, and it does so without ever guessing.

Handling catch-all without rejecting real customers

The fix is not a stricter check. It is a different decision at the signup boundary.

Do not hard-block on a domain you cannot fully resolve to a single inbox. Treat "domain accepts mail, specific inbox unconfirmed" as unknown, the same null state you would use for a network timeout. Then move the burden to a channel you control: send a confirmation email. If the user clicks the link, the inbox is real and monitored, catch-all or not. If they do not, you have lost nothing you would have kept.

A practical flow looks like this:

async function gateSignup(email) {
  const res = await fetch(
    "https://mailprobe.kevin-c0319.workers.dev/v1/verify?email=" +
      encodeURIComponent(email)
  );
  const data = await res.json();

  // Hard rejects are cheap and safe: bad syntax, disposable, no MX at all.
  if (data.reason === "disposable" || data.reason === "invalid_format") return "reject";
  if (data.reason === "no_mx") return "reject";

  // Everything else, including catch-all domains, goes through confirmation.
  return "send_confirmation";
}
Enter fullscreen mode Exit fullscreen mode

This keeps the false-positive rate on catch-all domains near zero, because you never silently accept an unconfirmed inbox, and you never silently reject a real business lead. The cost is one extra email, which you wanted to send anyway.

The wider lesson is that verification has two jobs. One is removing addresses that are definitely wrong. The other is sorting the rest into "confirmed" and "needs a confirmation step." Catch-all domains live entirely in that second bucket. Treat them as a reason to confirm, not as a reason to refuse.

I used MailProbe for the request shape above. Its hosted endpoint does MX, syntax, disposable, role, and free checks and is at https://mailprobe.kevin-c0319.workers.dev/. It does not claim to confirm individual inboxes on catch-all domains, which is the honest position. Pair it with a confirmation email and the catch-all problem stops being a problem.

Top comments (0)