Detect temporary email addresses in Node.js
May 19, 2026 · 6 min read
A temporary (or “disposable”) email address is a throwaway inbox that expires within minutes. Users reach for them to grab a verification link without handing over a real address. If your Node.js backend accepts them, you end up with users you can never email again. This guide covers detecting them in any Node.js framework.
The naive approach — and why it fails
The obvious idea is to keep a hand-written list of bad domains:
const blocked = ['mailinator.com', 'tempmail.com'];
const domain = email.split('@')[1];
if (blocked.includes(domain)) reject();This breaks fast. There are over 160,000 disposable domains and dozens appear every week. A static three-line list catches almost none of them. You need a maintained list — and ideally one that updates itself.
Install isDisposable
@isdisposable/js bundles the full blocklist and exposes a synchronous check. It has zero dependencies and works in any Node.js runtime, including serverless and edge.
npm install @isdisposable/jsExpress
import express from 'express';
import { isDisposable } from '@isdisposable/js';
const app = express();
app.use(express.json());
app.post('/signup', (req, res) => {
if (isDisposable(req.body.email)) {
return res.status(422).json({
error: 'Disposable email addresses are not allowed.',
});
}
// ...create the user
});Fastify
import Fastify from 'fastify';
import { isDisposable } from '@isdisposable/js';
const app = Fastify();
app.post('/signup', async (req, reply) => {
const { email } = req.body;
if (isDisposable(email)) {
return reply.code(422).send({
error: 'Disposable email addresses are not allowed.',
});
}
// ...create the user
});NestJS — a reusable validator
In NestJS, wrap the check in a custom validation decorator so it works on any DTO with one annotation.
import { registerDecorator, ValidationOptions } from 'class-validator';
import { isDisposable } from '@isdisposable/js';
export function IsNotDisposable(options?: ValidationOptions) {
return (object: object, propertyName: string) => {
registerDecorator({
name: 'isNotDisposable',
target: object.constructor,
propertyName,
options,
validator: {
validate: (value: string) => !isDisposable(value),
defaultMessage: () => 'Disposable email addresses are not allowed.',
},
});
};
}Checking many addresses at once
Cleaning an existing user table? isDisposableBulk takes an array and returns a boolean for each entry, with no per-item overhead.
import { isDisposableBulk } from '@isdisposable/js';
const emails = users.map((u) => u.email);
const flags = isDisposableBulk(emails);
const suspicious = users.filter((_, i) => flags[i]);Want live detection?
The offline package catches known domains instantly. To also catch brand-new domains and verify MX records in real time, the isDisposable API adds those signals — same blocklist underneath, so upgrading is a drop-in change.