
Node Email Verifier
Node Email Verifier is an email validation library for Node.js that checks if an email address has a
valid format and optionally verifies the domain's MX (Mail Exchange) records to ensure it can
receive emails. It also includes disposable email detection and detailed validation results.
π Hosted API Available
Need email verification without managing servers? Check out ValidKit - a
hosted API built on this library with:
- β‘ Sub-500ms response times
- π€ Native AI agent support (ChatGPT, Zapier, MCP)
- π 3,000+ disposable domains (vs 600+ in OSS)
- π Continuous updates & 99.9% uptime
- π Free tier available (no credit card required)
curl -X POST https://api.validkit.com/api/v1/verify \
-H "Content-Type: application/json" \
-H "X-API-Key: vk_beta_test_key_123456789" \
-d '{"email": "test@example.com"}'
Get your free API key β
node-email-verifier serves 50,000+ weekly downloads on npm and is actively maintained.
If you find it helpful or use it in production, consider sponsoring to support continued
development, security updates, and new features.
Sponsor on GitHub β
Features
- RFC 5322 Format Validation: Validates email addresses against the standard email formatting
rules.
- MX Record Checking: Verifies that the domain of the email address has valid MX records
indicating that it can receive emails. This check can be disabled using a parameter.
- Disposable Email Detection: Identify and optionally block temporary/throwaway email services
like 10minutemail, guerrillamail, etc.
- Detailed Validation Results: Get comprehensive validation information including specific
failure reasons and validation metadata.
- Customizable Timeout: Allows setting a custom timeout for MX record checking.
- TypeScript Support: Written in TypeScript with full type definitions for better developer
experience and IDE support.
- ES Modules: Modern ESM support with backward compatibility.
- Zero Breaking Changes: All new features are opt-in and maintain full backward compatibility.
- MX Record Caching: Built-in TTL-based caching with LRU eviction for improved performance in
high-volume scenarios.
Requirements
- Node.js: Version 18.0.0 or higher
Installation
Install the package using npm:
npm install node-email-verifier --save
Usage
This package supports both ES modules and CommonJS:
import emailValidator from 'node-email-verifier';
const emailValidator = require('node-email-verifier');
Note: When using CommonJS require()
, the function returns a promise that resolves with the
validation result.
const emailValidator = require('node-email-verifier');
(async () => {
const isValid = await emailValidator('test@example.com');
console.log('Email is valid:', isValid);
})();
emailValidator('test@example.com')
.then((isValid) => console.log('Email is valid:', isValid))
.catch((error) => console.error('Validation error:', error));
Here's how to use Node Email Verifier in both JavaScript and TypeScript:
JavaScript
ES Modules
import emailValidator from 'node-email-verifier';
async function validateEmail(email) {
try {
const isValid = await emailValidator(email);
console.log(`Is "${email}" valid?`, isValid);
} catch (error) {
console.error('Validation error:', error);
}
}
CommonJS
const emailValidator = require('node-email-verifier');
async function validateEmail(email) {
try {
const isValid = await emailValidator(email);
console.log(`Is "${email}" valid?`, isValid);
} catch (error) {
console.error('Validation error:', error);
}
}
async function validateWithDisposableCheck(email) {
try {
const isValid = await emailValidator(email, {
checkDisposable: true,
});
console.log(`Is "${email}" valid (blocking disposable)?`, isValid);
} catch (error) {
console.error('Validation error:', error);
}
}
async function getDetailedValidation(email) {
try {
const result = await emailValidator(email, {
detailed: true,
checkDisposable: true,
});
console.log('Detailed validation result:', result);
} catch (error) {
console.error('Validation error:', error);
}
}
async function validateWithCustomOptions(email) {
try {
const isValid = await emailValidator(email, {
checkMx: true,
checkDisposable: true,
timeout: '500ms',
});
console.log(`Is "${email}" valid with all checks?`, isValid);
} catch (error) {
if (error.message === 'DNS lookup timed out') {
console.error('Timeout on DNS lookup.');
} else {
console.error('Validation error:', error);
}
}
}
async function validateFormatOnly(email) {
try {
const isValid = await emailValidator(email, { checkMx: false });
console.log(`Is "${email}" format valid?`, isValid);
} catch (error) {
console.error('Validation error:', error);
}
}
validateEmail('test@example.com');
validateWithDisposableCheck('test@10minutemail.com');
getDetailedValidation('invalid-email');
validateFormatOnly('test@example.com');
TypeScript
ES Modules
import emailValidator, {
EmailValidatorOptions,
ValidationResult,
ErrorCode,
} from 'node-email-verifier';
import { isEmailValidationError } from 'node-email-verifier';
async function validateEmailTyped(email: string): Promise<boolean> {
const options: EmailValidatorOptions = {
checkMx: true,
checkDisposable: true,
timeout: 5000,
};
try {
const isValid = await emailValidator(email, options);
console.log(`Is "${email}" valid?`, isValid);
return isValid;
} catch (error) {
console.error('Validation error:', error);
return false;
}
}
async function getDetailedValidationTyped(email: string): Promise<ValidationResult> {
const result = await emailValidator(email, {
detailed: true,
checkMx: true,
checkDisposable: true,
});
if (!result.valid) {
console.log('Validation failed:');
if (!result.format.valid) {
console.log('- Format issue:', result.format.reason);
}
if (result.disposable && !result.disposable.valid) {
console.log('- Disposable email from:', result.disposable.provider);
}
if (result.mx && !result.mx.valid) {
console.log('- MX issue:', result.mx.reason);
}
}
return result;
}
async function handleValidationErrors(email: string): Promise<void> {
try {
const result = await emailValidator(email, {
detailed: true,
checkMx: true,
checkDisposable: true,
timeout: 5000,
});
if (!result.valid && result.errorCode === ErrorCode.INVALID_EMAIL_FORMAT) {
throw new Error('Please enter a valid email address');
}
if (result.disposable?.errorCode === ErrorCode.DISPOSABLE_EMAIL) {
throw new Error('Disposable email addresses are not allowed');
}
} catch (error) {
if (isEmailValidationError(error) && error.code === ErrorCode.DNS_LOOKUP_TIMEOUT) {
throw new Error('Email verification timed out. Please try again.');
}
throw error;
}
}
async function quickValidation(email: string): Promise<boolean> {
const result = await emailValidator(email, {
checkMx: false,
checkDisposable: true,
timeout: 2000,
});
return result;
}
function createValidator(options: EmailValidatorOptions) {
return (email: string) => emailValidator(email, options);
}
const fastValidator = createValidator({
checkMx: false,
checkDisposable: false,
});
const businessValidator = createValidator({
checkMx: true,
checkDisposable: true,
timeout: 10000,
});
const detailedValidator = createValidator({
detailed: true,
checkMx: true,
checkDisposable: true,
});
CommonJS
When using CommonJS with TypeScript, you can still get full type support:
import type { EmailValidatorOptions, ValidationResult } from 'node-email-verifier';
const emailValidator = require('node-email-verifier');
async function validateEmailCJS(email: string): Promise<boolean> {
const options: EmailValidatorOptions = {
checkMx: true,
checkDisposable: true,
timeout: 5000,
};
try {
const isValid = await emailValidator(email, options);
console.log(`Is "${email}" valid?`, isValid);
return isValid;
} catch (error) {
console.error('Validation error:', error);
return false;
}
}
async function getDetailedValidationCJS(email: string): Promise<ValidationResult> {
const result = await emailValidator(email, {
detailed: true,
checkMx: true,
checkDisposable: true,
});
if (!result.valid) {
console.log('Validation failed:');
if (!result.format.valid) {
console.log('- Format issue:', result.format.reason);
}
if (result.disposable && !result.disposable.valid) {
console.log('- Disposable email from:', result.disposable.provider);
}
if (result.mx && !result.mx.valid) {
console.log('- MX issue:', result.mx.reason);
}
}
return result;
}
async function validateWithDynamicImport(email: string): Promise<boolean> {
const { default: emailValidator } = await import('node-email-verifier');
return emailValidator(email, {
checkMx: true,
checkDisposable: true,
});
}
Examples
For more comprehensive examples, check out the examples directory:
Run any example:
node examples/basic-validation.js
New Features (v3.1.0)
Disposable Email Detection
Block temporary and throwaway email services to improve data quality:
const isValid = await emailValidator('test@10minutemail.com', {
checkDisposable: true,
});
const isValid = await emailValidator('test@10minutemail.com', {
checkDisposable: false,
});
Supported disposable providers: 600+ domains including 10minutemail, guerrillamail, yopmail,
tempmail, mailinator, and many more.
Detailed Validation Results
Get comprehensive validation information with specific failure reasons:
const result = await emailValidator('test@10minutemail.com', {
detailed: true,
checkMx: true,
checkDisposable: true,
});
console.log(result);
if (!result.valid) {
if (!result.format.valid) {
console.log('Invalid email format:', result.format.reason);
}
if (result.disposable && !result.disposable.valid) {
console.log('Disposable email detected:', result.disposable.provider);
}
if (result.mx && !result.mx.valid) {
console.log('MX validation failed:', result.mx.reason);
}
}
Error Codes (v3.2.0+)
Detailed validation results now include error codes for programmatic error handling:
const result = await emailValidator('invalid-email', {
detailed: true,
checkMx: true,
checkDisposable: true,
});
if (!result.valid) {
if (result.errorCode) {
console.log('Top-level error:', result.errorCode);
}
switch (result.format.errorCode) {
case ErrorCode.EMAIL_MUST_BE_STRING:
console.log('Email must be a string');
break;
case ErrorCode.EMAIL_CANNOT_BE_EMPTY:
console.log('Email cannot be empty');
break;
case ErrorCode.INVALID_EMAIL_FORMAT:
console.log('Invalid email format');
break;
}
if (result.mx?.errorCode) {
switch (result.mx.errorCode) {
case ErrorCode.NO_MX_RECORDS:
console.log('No mail server found');
break;
case ErrorCode.DNS_LOOKUP_FAILED:
console.log('DNS lookup error');
break;
case ErrorCode.DNS_LOOKUP_TIMEOUT:
console.log('DNS lookup timed out');
break;
case ErrorCode.MX_SKIPPED_DISPOSABLE:
console.log('MX check skipped due to disposable email');
break;
}
}
if (result.disposable?.errorCode === ErrorCode.DISPOSABLE_EMAIL) {
console.log('Disposable email detected');
}
}
import emailValidator, { ErrorCode } from 'node-email-verifier';
try {
await emailValidator('test@example.com', { timeout: -1 });
} catch (error) {
if (error.code === ErrorCode.INVALID_TIMEOUT_VALUE) {
console.log('Invalid timeout configuration');
}
}
Available Error Codes:
EMAIL_MUST_BE_STRING
- Email is not a string
EMAIL_CANNOT_BE_EMPTY
- Email string is empty
INVALID_EMAIL_FORMAT
- Email format is invalid
NO_MX_RECORDS
- No MX records found for domain
DNS_LOOKUP_FAILED
- DNS lookup encountered an error
DNS_LOOKUP_TIMEOUT
- DNS lookup timed out
MX_SKIPPED_DISPOSABLE
- MX check was skipped because email is disposable
MX_LOOKUP_FAILED
- MX record lookup failed for unknown reason
DISPOSABLE_EMAIL
- Email is from a disposable provider
INVALID_TIMEOUT_VALUE
- Invalid timeout parameter
UNKNOWN_ERROR
- An unknown error occurred
AI Debug Mode (v3.3.0+)
Enable structured logging for debugging and observability:
const result = await emailValidator('test@example.com', {
debug: true,
checkMx: true,
checkDisposable: true,
detailed: true,
});
Debug Mode Features:
- Structured JSON logs: MCP-compatible format for AI tooling
- Timing information: Track duration of each validation phase
- Memory usage: Monitor heap and RSS memory for each operation
- Error tracking: Detailed error logs with stack traces
- Phase tracking: See the flow through format check, disposable check, and MX validation
Example: Production Debug Wrapper
const debugLogs = [];
const originalLog = console.log;
console.log = (message) => {
try {
const parsed = JSON.parse(message);
if (parsed.type === 'email-validator-debug') {
debugLogs.push(parsed);
}
} catch (e) {
originalLog(message);
}
};
const result = await emailValidator(email, { debug: true });
console.log = originalLog;
console.log(`Validation took ${debugLogs.length} steps`);
See the debug mode example for more advanced usage patterns.
MX Record Caching (v3.4.0+)
Improve performance for high-volume email validation with built-in MX record caching:
const isValid = await emailValidator('test@example.com', {
checkMx: true,
});
const result = await emailValidator('test@example.com', {
checkMx: true,
detailed: true,
cache: {
enabled: true,
defaultTtl: 600000,
maxSize: 5000,
},
});
console.log(result.cacheStats);
if (result.mx?.cached) {
console.log('MX records were served from cache');
}
Cache Management:
import { globalMxCache } from 'node-email-verifier';
globalMxCache.flush();
globalMxCache.delete('example.com');
const stats = globalMxCache.getStatistics();
console.log(`Cache hit rate: ${stats.hitRate}%`);
globalMxCache.resetStatistics();
Performance Benefits:
- Dramatic Performance Improvement: Real-world benchmarks show significant speedup over no
caching
- 7.7x faster with realistic DNS latency (25ms per lookup)
- 87%+ cache hit rate in typical usage patterns with mixed domain popularity
- 872 DNS lookups avoided out of 1000 requests (87.2% reduction)
- LRU Eviction Strategy: Intelligent cache management that keeps frequently accessed domains in
memory longer than less popular ones
- Bulk Validation: Eliminates redundant DNS lookups for repeated domains
- Each DNS lookup typically takes 50-200ms depending on network conditions
- 65+ seconds saved in real DNS lookup time per 1000 validations
- Performance improvement scales with network latency
- Rate Limiting: Reduces DNS queries to external servers
- Memory Efficient: LRU eviction with automatic cleanup of expired entries
- TTL Respect: Honors DNS TTL semantics
Combining Features
const result = await emailValidator(email, {
checkMx: true,
checkDisposable: true,
detailed: true,
timeout: '5s',
debug: true,
});
const isBusinessEmail = await emailValidator(email, {
checkMx: true,
checkDisposable: true,
timeout: '10s',
});
Package Configuration
This package supports both ES modules and CommonJS through the exports
field in package.json
.
Key configuration details:
"type": "module"
: Designates this as an ES module package
"main"
: Points to ./dist/index.js
for legacy compatibility
"types"
: TypeScript definitions at ./dist/index.d.ts
for both module systems
"exports"
: Modern Node.js module resolution with conditional exports:
"import"
: ES module entry point (./dist/index.js
)
"require"
: CommonJS entry point (./dist/index.cjs
)
"types"
: Shared TypeScript definitions (./dist/index.d.ts
)
- Node Version: Requires Node.js 18.0.0 or higher
- Build Process: TypeScript compilation + automatic CommonJS wrapper generation
For the complete configuration, see the package.json file.
This configuration ensures the package works correctly with:
import emailValidator from 'node-email-verifier'
(ES modules)
const emailValidator = require('node-email-verifier')
(CommonJS)
- TypeScript projects using either module system
- Bundlers like webpack, Rollup, and Vite
- Modern Node.js versions (18+) with proper module resolution
API
emailValidator(email, [opts]): Promise<boolean | ValidationResult>
Validates the given email address with comprehensive validation options including format checking,
MX record verification, disposable email detection, and detailed results.
Handling Return Types
async function handleValidation(email) {
const result = await emailValidator(email, {
checkDisposable: true,
detailed: true,
});
if (typeof result === 'object') {
console.log('Detailed validation:');
console.log('Valid:', result.valid);
if (!result.valid) {
if (!result.format.valid) {
console.log('Format error:', result.format.reason);
}
if (result.disposable && !result.disposable.valid) {
console.log('Disposable provider:', result.disposable.provider);
}
}
return result.valid;
}
console.log('Simple validation:', result);
return result;
}
const detailedResult = await emailValidator(email, { detailed: true });
const booleanResult = await emailValidator(email, { detailed: false });
Parameters
email
(unknown
): The email address to validate. Can be any type, but only strings will be
considered valid.
opts
(EmailValidatorOptions | boolean
, optional): Configuration options or a boolean for
backward compatibility.
Options (EmailValidatorOptions
)
interface EmailValidatorOptions {
checkMx?: boolean;
checkDisposable?: boolean;
detailed?: boolean;
timeout?: string | number;
debug?: boolean;
cache?: MxCacheOptions;
}
checkMx
(boolean
, optional): Whether to check for MX records. Defaults to true
.
checkDisposable
(boolean
, optional): Whether to check for disposable email providers.
Defaults to false
.
detailed
(boolean
, optional): Return detailed validation results instead of boolean.
Defaults to false
.
timeout
(string | number
, optional): The timeout for the DNS MX lookup. Can be:
- A number in milliseconds (e.g.,
5000
)
- A string in ms format (e.g.,
'5s'
, '2000ms'
, '1m'
)
- Defaults to
'10s'
(10 seconds)
debug
(boolean
, optional): Enable debug mode for structured logging. When true, logs
detailed timing and memory usage information to console.log as JSON. Defaults to false
.
cache
(MxCacheOptions
, optional): Configure MX record caching behavior. Caching is enabled
by default with a 5-minute TTL. Options:
enabled
(boolean
): Enable/disable caching. Default: true
defaultTtl
(number
): TTL in milliseconds. Default: 300000
(5 minutes)
maxSize
(number
): Maximum cache entries. Default: 1000
Backward Compatibility
For backward compatibility, you can also pass a boolean as the second parameter:
true
: Enable MX checking (equivalent to { checkMx: true }
)
false
: Disable MX checking (equivalent to { checkMx: false }
)
Returns
Promise<boolean | ValidationResult>
: A promise that resolves to:
boolean
(when detailed: false
or not specified):
true
if the email address passes all enabled validations
false
if the email address fails any enabled validation
ValidationResult
(when detailed: true
):
- Comprehensive validation information including specific failure reasons
- Always includes
format
validation results
- Includes
mx
results only when checkMx: true
- Includes
disposable
results only when checkDisposable: true
Throws
Error
: When DNS lookup times out, the error message will be "DNS lookup timed out"
TypeScript Benefits
This library is written in TypeScript and provides several benefits for TypeScript users:
- Type Safety: Full type checking for all parameters and return values
- IntelliSense: Rich autocomplete and documentation in your IDE
- Interface Exports: Import and use the
EmailValidatorOptions
interface in your own code
- Compile-time Error Detection: Catch mistakes before runtime
Type Definitions
The library exports the following types:
import type {
ErrorCode,
MxRecord,
ValidationResult,
EmailValidatorOptions,
CacheStatistics,
MxCacheOptions,
} from 'node-email-verifier';
import { EmailValidationError, isEmailValidationError } from 'node-email-verifier';
declare function emailValidator(
email: unknown,
opts?: EmailValidatorOptions | boolean
): Promise<boolean | ValidationResult>;
export interface EmailValidatorOptions {
checkMx?: boolean;
checkDisposable?: boolean;
detailed?: boolean;
timeout?: string | number;
debug?: boolean;
cache?: MxCacheOptions;
}
export interface MxCacheOptions {
enabled?: boolean;
defaultTtl?: number;
maxSize?: number;
}
export interface CacheStatistics {
hits: number;
misses: number;
size: number;
evictions: number;
hitRate: number;
}
export interface MxRecord {
exchange: string;
priority: number;
}
export interface ValidationResult {
valid: boolean;
email: string;
errorCode?: ErrorCode;
format: {
valid: boolean;
reason?: string;
errorCode?: ErrorCode;
};
mx?: {
valid: boolean;
records?: MxRecord[];
reason?: string;
errorCode?: ErrorCode;
cached?: boolean;
};
disposable?: {
valid: boolean;
provider?: string | null;
reason?: string;
errorCode?: ErrorCode;
};
cacheStats?: CacheStatistics;
}
export class EmailValidationError extends Error {
code: ErrorCode;
constructor(code: ErrorCode, message?: string);
}
export function isEmailValidationError(error: unknown): error is EmailValidationError;
Production Usage
When using this library in production environments, especially with MX record checking enabled, it's
important to consider DNS rate limiting. For detailed guidance on:
- Implementing request throttling
- Adding retry logic with exponential backoff
- Caching MX records
- Monitoring DNS failures
See our API Best Practices Guide.
Development
Available Scripts
npm run build
- Compile TypeScript to JavaScript
npm run test
- Run the test suite
npm run lint
- Check JavaScript/TypeScript code for linting issues
npm run lint:fix
- Automatically fix JavaScript/TypeScript linting issues
npm run lint:md
- Check Markdown files for linting issues
npm run lint:md:fix
- Automatically fix Markdown linting issues
npm run lint:yaml
- Check YAML files for validity
npm run lint:all
- Run all linters (JS/TS, Markdown, YAML)
npm run format
- Format code with Prettier
npm run format:check
- Check if code is properly formatted
npm run check
- Run all linting, formatting, and tests
npm run precommit
- Fix linting, format code, and run tests
npm run benchmark
- Run performance benchmarks for disposable domain lookups
npm run benchmark:init
- Run initialization and memory usage benchmarks
npm run benchmark:all
- Run all benchmarks
Code Quality
This project uses:
- ESLint for JavaScript/TypeScript linting
- Markdownlint for Markdown file linting
- yaml-lint for YAML file validation
- Prettier for code formatting (JS/TS, JSON, Markdown, YAML)
- Jest for testing with TypeScript integration
Before committing, run npm run precommit
to ensure code quality.
Git Hooks
This project uses husky and
lint-staged to maintain code quality:
- Pre-commit: Automatically fixes linting issues and formats staged files
- Pre-push: Runs the full test suite to prevent pushing broken code
These hooks are installed automatically when you run npm install
.
Project Structure
node-email-verifier/
βββ src/ # Source TypeScript files
βββ dist/ # Built JavaScript files and CommonJS wrapper
βββ test/ # Test files (unit and integration tests)
βββ scripts/ # Build scripts and performance benchmarks
βββ docs/ # Additional documentation
β βββ AI_WORKFLOW.md # AI-assisted PR workflow guide
β βββ API_BEST_PRACTICES.md # Rate limiting and production usage
β βββ ESM_COMMONJS_COMPATIBILITY.md # Module compatibility guide
β βββ INTEGRATION_TESTING.md # Integration testing guide
β βββ PERFORMANCE.md # Performance benchmarks and analysis
βββ examples/ # (Coming soon) Example usage scripts
Roadmap
Check out our Feature Enhancement Roadmap to see what's coming next and
what we're working on. We welcome feedback and contributions on these planned features!
Contributing
Contributions are always welcome! Please see our Contributing Guide for detailed
information about:
- Development setup
- Code quality standards
- Available npm scripts
- Testing guidelines
- Commit message format
Quick start:
npm install
npm run check
Feel free to submit a PR!
Support This Project
If you find Node Email Verifier useful, please consider supporting its development:
Your support helps maintain this project and fund new features. Thank you! π
License
This project is licensed under the MIT License.