Technology Aug 23, 2026 · 5 min read

How to Block Disposable Email Signups Without SMTP Verification

Disposable email services make it easy to create temporary addresses that disappear shortly after signup. They can be useful for privacy, but they also create problems for applications that rely on email for account recovery, trial limits, community moderation, or fraud prevention. In this article...

DE
DEV Community
by nProejct
How to Block Disposable Email Signups Without SMTP Verification

Disposable email services make it easy to create temporary addresses that disappear shortly after signup.

They can be useful for privacy, but they also create problems for applications that rely on email for account recovery, trial limits, community moderation, or fraud prevention.

In this article, I will show a lightweight way to screen an email address before accepting a signup.

What should we check?

A practical pre-signup check can answer a few separate questions:

  1. Is the email address syntactically valid?
  2. Does the domain belong to a disposable email provider?
  3. Is it a common free email provider?
  4. Does the domain publish DNS MX records?
  5. Was the result conclusive?

These signals should remain separate. For example, a Gmail address is from a free provider, but that alone does not make it suspicious.

Why not verify the mailbox directly?

It is important to distinguish domain screening from mailbox verification.

An MX lookup can confirm that a domain advertises mail-handling infrastructure, but it cannot prove that:

  • The mailbox exists
  • The mailbox belongs to the user
  • The server will accept a message
  • The user can receive future messages

SMTP probing can also be slow, unreliable, and rejected by mail servers.

For account ownership, the correct solution is still a confirmation email or one-time code.

The checks in this article are intended as an early risk filter, not as proof of mailbox ownership.

A simple risk model

I use three possible risk levels:

  • LOW: The lightweight checks passed
  • HIGH: A definite validation problem was found
  • UNKNOWN: A DNS error or timeout prevented a reliable conclusion

This distinction matters because an infrastructure error should not automatically be treated as a fraudulent user.

A possible signup policy is:

function decideSignup(result) {
  switch (result.riskLevel) {
    case "LOW":
      return "ALLOW";

    case "HIGH":
      return "BLOCK";

    case "UNKNOWN":
      return "RETRY_OR_REVIEW";

    default:
      return "REVIEW";
  }
}

Calling the API from Node.js

The example below uses fetch, available in modern Node.js versions.

Keep the RapidAPI key on the server. Do not expose it in frontend JavaScript.

async function inspectEmail(email) {
  const response = await fetch(
    "https://disposable-email-validator2.p.rapidapi.com/email/v1/verify",
    {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        "X-RapidAPI-Key": process.env.RAPIDAPI_KEY,
        "X-RapidAPI-Host":
          "disposable-email-validator2.p.rapidapi.com"
      },
      body: JSON.stringify({ email })
    }
  );

  if (!response.ok) {
    throw new Error(`Email inspection failed: ${response.status}`);
  }

  return response.json();
}

Usage:

const result = await inspectEmail("user@temp-mail.org");

console.log(result);

Example response:

{
  "email": "user@temp-mail.org",
  "validSyntax": true,
  "disposable": true,
  "freeProvider": false,
  "hasMxRecords": true,
  "riskLevel": "HIGH",
  "reason": "Disposable email detected"
}

Notice that the domain can have valid MX records and still be disposable. That is why MX lookup alone is not enough.

Connecting it to an Express signup route

Here is a simplified server-side integration:

import express from "express";

const app = express();

app.use(express.json());

app.post("/signup", async (request, response) => {
  const { email } = request.body;

  if (typeof email !== "string" || email.trim() === "") {
    return response.status(400).json({
      error: "Email is required"
    });
  }

  try {
    const inspection = await inspectEmail(email);

    if (inspection.riskLevel === "HIGH") {
      return response.status(422).json({
        error: "This email address cannot be accepted",
        reason: inspection.reason
      });
    }

    if (inspection.riskLevel === "UNKNOWN") {
      return response.status(503).json({
        error: "Email verification is temporarily unavailable",
        retryable: true
      });
    }

    // Continue with account creation.
    // A confirmation email should still be sent here.

    return response.status(201).json({
      message: "Signup accepted. Please confirm your email."
    });
  } catch (error) {
    console.error("Email inspection error:", error);

    return response.status(503).json({
      error: "Unable to inspect the email address",
      retryable: true
    });
  }
});

In a production application, you should decide whether a temporary verification failure should block signup, trigger a retry, or allow signup with additional restrictions.

Understanding the response

The API returns individual signals instead of only one boolean:

{
  "validSyntax": true,
  "disposable": false,
  "freeProvider": true,
  "hasMxRecords": true,
  "riskLevel": "LOW",
  "reason": "Valid email"
}

This allows the application to create its own policy.

For example:

  • A community site might allow all free providers
  • A B2B trial might request additional verification for free providers
  • A promotion system might block disposable domains
  • An inconclusive DNS result might be queued for retry

freeProvider should be treated as classification data, not proof of abuse.

Important limitations

This type of API should not be used as the only anti-fraud mechanism.

It does not replace:

  • Email ownership confirmation
  • Rate limiting
  • CAPTCHA or bot detection
  • IP reputation checks
  • Device or account-abuse monitoring
  • Application-specific fraud rules

Domain lists also change over time, so disposable-domain detection requires regular data updates.

Try it

I built the API used in this tutorial and published a free testing plan on RapidAPI:

https://rapidapi.com/cloud-partners-n-project/api/disposable-email-validator2

This is my first public API, and I would appreciate feedback on the response design.

In particular:

  1. Is LOW, HIGH, and UNKNOWN clear enough?
  2. Would a separate recommendedAction field be useful?
  3. Should DNS timeouts return UNKNOWN, or would you handle them differently?
  4. What additional signal would make this easier to integrate into a signup flow?
DE
Source

This article was originally published by DEV Community and written by nProejct.

Read original article on DEV Community
Back to Discover

Reading List