@isdisposable/js
v1.0.7
Published
Detect disposable and temporary email addresses. Open source, zero dependencies, 160k+ domains.
Downloads
10,089
Maintainers
Readme
Install
npm install @isdisposable/jspnpm add @isdisposable/jsyarn add @isdisposable/jsUsage
import { isDisposable } from '@isdisposable/js';
isDisposable('[email protected]'); // true
isDisposable('[email protected]'); // falseSynchronous. Offline. Zero config. That's it.
Bulk Check
import { isDisposableBulk } from '@isdisposable/js';
const results = isDisposableBulk([
'[email protected]',
'[email protected]',
'[email protected]',
]);
// [true, false, true]Domain Check
import { isDomainDisposable } from '@isdisposable/js';
isDomainDisposable('mailinator.com'); // true
isDomainDisposable('gmail.com'); // falseAPI Mode — Real-time Detection
For DNS/MX validation, risk scoring, and domain age analysis:
import { createIsDisposable } from '@isdisposable/js';
const client = createIsDisposable({
apiKey: 'isd_live_xxxxx', // Get one at https://isdisposable.com
});
const result = await client.check('[email protected]');
// {
// disposable: true,
// score: 95, ← risk score (0-100)
// reason: "blocklist_match",
// mx_valid: true,
// domain_age_days: 3,
// cached: false
// }The API adds signals that offline detection can't: MX record validation, self-referencing mail server detection, domain age via RDAP, and username entropy scoring. If the API is unreachable, it automatically falls back to offline detection — your app never breaks.
| Option | Type | Default | Description |
|--------|------|---------|-------------|
| apiKey | string | — | API key from isdisposable.com |
| apiUrl | string | https://isdisposable.com | API base URL |
| timeout | number | 5000 | Request timeout (ms) |
| cache | boolean | true | Cache API responses |
| cacheTTL | number | 3600 | Cache duration (seconds) |
const results = await client.checkBulk([
'[email protected]',
'[email protected]',
]);Framework Integrations
'use server';
import { isDisposable } from '@isdisposable/js';
export async function signup(formData: FormData) {
const email = formData.get('email') as string;
if (isDisposable(email)) {
return { error: 'Please use a real email address' };
}
// Continue with signup...
}import express from 'express';
import { isDisposable } from '@isdisposable/js';
const app = express();
app.use(express.json());
app.post('/signup', (req, res, next) => {
if (isDisposable(req.body.email)) {
return res.status(400).json({ error: 'Disposable emails not allowed' });
}
next();
});import { betterAuth } from 'better-auth';
import { isDisposable } from '@isdisposable/js';
export const auth = betterAuth({
databaseHooks: {
user: {
create: {
before: async (user) => {
if (isDisposable(user.email)) {
return false; // Block signup
}
return user;
},
},
},
},
});import { isDisposable } from '@isdisposable/js';
Deno.serve(async (req) => {
const { email } = await req.json();
if (isDisposable(email)) {
return new Response(
JSON.stringify({ error: 'Disposable emails not allowed' }),
{ status: 400, headers: { 'Content-Type': 'application/json' } }
);
}
return new Response(JSON.stringify({ ok: true }));
});import { Injectable, CanActivate, ExecutionContext, BadRequestException } from '@nestjs/common';
import { isDisposable } from '@isdisposable/js';
@Injectable()
export class DisposableEmailGuard implements CanActivate {
canActivate(context: ExecutionContext): boolean {
const request = context.switchToHttp().getRequest();
if (isDisposable(request.body?.email)) {
throw new BadRequestException('Disposable emails not allowed');
}
return true;
}
}import Fastify from 'fastify';
import { isDisposable } from '@isdisposable/js';
const app = Fastify();
app.addHook('preHandler', async (request, reply) => {
const email = (request.body as any)?.email;
if (email && isDisposable(email)) {
return reply.status(400).send({ error: 'Disposable emails not allowed' });
}
});How It Works
Email input
│
▼
┌──────────────┐ ┌─────────────────────┐
│ Blocklist │────▶│ 160k+ domains │
│ (offline) │ │ O(1) Set lookup │
└──────┬───────┘ │ < 1ms │
│ not found └─────────────────────┘
▼
┌──────────────┐ ┌─────────────────────┐
│ API Mode │────▶│ DNS/MX validation │
│ (optional) │ │ Domain age (RDAP) │
└──────────────┘ │ Username entropy │
│ Risk score 0-100 │
└─────────────────────┘Offline mode checks against a bundled blocklist of 160,000+ domains. Instant, synchronous, zero network calls.
API mode adds real-time signals: MX record validation, self-referencing mail server detection, domain age analysis, suspicious MX infrastructure matching, and username entropy scoring.
Comparison
| | isDisposable | mailchecker | disposable-email-domains | |---|:---:|:---:|:---:| | Domains | 160,000+ | 55,000 | 5,000 | | Boolean API | ✅ | ✅ | ❌ (raw list) | | Zero deps | ✅ | ❌ | N/A | | TypeScript | ✅ | Partial | N/A | | Hosted API | ✅ | ❌ | ❌ | | Risk scoring | ✅ | ❌ | ❌ | | DNS/MX checks | ✅ | ❌ | ❌ | | Maintained | ✅ | Sporadic | Sporadic |
SDKs
| Language | Package | Status |
|----------|---------|--------|
| JavaScript/TypeScript | @isdisposable/js | ✅ Stable |
| Python | isdisposable | 🔜 Coming soon |
| Go | isdisposable-go | 🔜 Coming soon |
API Reference
isDisposable(email: string): boolean
Synchronous. Returns true if the email is from a disposable provider.
isDisposableBulk(emails: string[]): boolean[]
Synchronous. Returns array of booleans matching input order.
isDomainDisposable(domain: string): boolean
Check a domain directly without an email address.
extractDomain(email: string): string | null
Extract and validate the domain from an email address.
createIsDisposable(config): ApiClient
Create an API client with .check(email), .checkBulk(emails), and .clearCache().
Score Calculation (API Mode)
| Signal | Score Impact | |--------|:-----------:| | Domain in blocklist (160k+) | +95 | | Self-referencing MX server | +50 | | MX points to known disposable infra | = 90 | | Suspicious MX IP match | +45 | | No valid MX records | +40 | | Domain registered < 7 days | +30 | | MX pattern match | +20 | | Domain registered < 30 days | +15 | | Username entropy (bot-generated) | +15 | | Plus-addressing detected | +10 | | Valid MX + old domain + clean | = 5 |
Score ≥ 50 = disposable. Capped at 100.
Contributing
Found a domain that should be blocked? Open an issue with the domain name. We review and update the blocklist regularly.
License
MIT — use it in any project, commercial or open-source.
