Email Validation Methods — How mailtester Works
@mailtester/core includes 5 validators that work together to comprehensively validate email addresses in Node.js.
Overview
| Validator | Purpose | Speed | Network |
|---|---|---|---|
| Regex | Format validation | Instant | No |
| Typo | Detect typos | Instant | No |
| Disposable | Block temp emails | Instant | No |
| MX | Verify mail servers | ~50ms | Yes |
| SMTP | Verify mailbox | ~100ms | Yes |
Regex Validator
Validates email format according to RFC 5322 standards.
What it Checks
- Valid email format (local@domain)
- Proper character usage
- Domain structure
- Internationalized domain names (IDN)
Configuration
await validate('user@example.com', {
validators: {
regex: { enabled: true } // Default: true
}
});Examples
| Result | Reason | |
|---|---|---|
user@example.com | Valid | Standard format |
user+tag@example.com | Valid | Plus addressing |
user.name@example.com | Valid | Dots in local |
user@example.co.jp | Valid | IDN support |
invalid | Invalid | Missing @ symbol |
@example.com | Invalid | Missing local part |
user@ | Invalid | Missing domain |
Typo Validator
Detects common domain typos and suggests corrections.
What it Checks
- Common domain misspellings
- TLD typos
- Keyboard proximity errors
Configuration
await validate('user@gmaill.com', {
validators: {
typo: { enabled: true } // Default: true
}
});Examples
| Input | Suggestion |
|---|---|
user@gmaill.com | gmail.com |
user@yahooo.com | yahoo.com |
user@hotmal.com | hotmail.com |
user@outlok.com | outlook.com |
user@gogle.com | google.com |
Accessing Suggestions
const result = await validate('user@gmaill.com');
if (result.validators.typo?.details?.suggestion) {
console.log(`Did you mean: ${result.validators.typo.details.suggestion}?`);
// Output: "Did you mean: gmail.com?"
}Disposable Validator
Blocks temporary / disposable email services used for fake signups.
What it Checks
- ~167,000 known disposable domains via
detect-disposable-email(exact match) - 399 wildcard base domains (any subdomain of a base is disposable, e.g.
x.y.10mail.org) - Pattern-based heuristics (
tempmail*,10minutemail*,throwaway*, …) - Custom blacklist / whitelist you configure
Data source (v1.2.0+)
| Item | Detail |
|---|---|
| Package | detect-disposable-email |
| Replaces | Unmaintained disposable-email-domains |
| Matching | Exact + wildcard parent walk + IDN/punycode |
| Updates | Data refreshed upstream; mailtester depends on ^1.1.0 |
Configuration
await validate('user@mailinator.com', {
validators: {
disposable: {
enabled: true, // Default: true
customBlacklist: ['spam.example'], // Always treat as disposable
customWhitelist: ['partner.com'], // Always allow (even if in list)
enablePatternDetection: true // Default: true
}
}
});| Option | Type | Default | Description |
|---|---|---|---|
enabled | boolean | true | Run disposable checks |
customBlacklist | string[] | [] | Domains always blocked |
customWhitelist | string[] | [] | Domains always allowed (overrides list + patterns) |
enablePatternDetection | boolean | true | Heuristic name patterns |
Priority order: whitelist → blacklist → known list (exact/wildcard) → patterns.
Blocked Services (Examples)
- mailinator.com
- guerrillamail.com
- 10minutemail.com
- tempmail.com
- throwaway.email
- Wildcard subdomains such as
anything.10mail.org - And 160,000+ more...
Example
const result = await validate('test@mailinator.com');
console.log(result.valid); // false
console.log(result.reason); // "disposable"
console.log(result.validators.disposable?.error?.details);
// { domain: 'mailinator.com', reason: 'known_disposable' }False positives
If a legitimate domain is blocked, allow it locally:
await validate('user@legit-corp.com', {
validators: {
disposable: {
enabled: true,
customWhitelist: ['legit-corp.com']
}
}
});Or open an issue on detect-disposable-email for a data fix.
MX Validator
Verifies domain has valid mail exchange (MX) servers.
What it Checks
- MX records exist
- DNS resolution works
- Fallback to A records if no MX
Configuration
await validate('user@example.com', {
validators: {
mx: { enabled: true } // Default: true
}
});How it Works
- Queries DNS for MX records
- If no MX found, checks for A records (fallback)
- Validates at least one mail server exists
Example
const result = await validate('user@nonexistent-domain-xyz.com');
if (!result.validators.mx?.valid) {
console.log('Domain has no mail servers');
}Performance
MX validation requires DNS lookup (~50ms). For faster validation, use the balanced or permissive preset.
SMTP Validator
Verifies mailbox exists by connecting to the mail server.
What it Checks
- SMTP connection to port 25
- HELO/EHLO handshake
- MAIL FROM command
- RCPT TO verification
- Mailbox existence
Configuration
await validate('user@example.com', {
validators: {
smtp: { enabled: true } // Default: true
}
});How it Works
- Resolves MX records for domain
- Connects to mail server on port 25
- Performs SMTP handshake
- Sends RCPT TO command to verify mailbox
- Checks response code
Example
const result = await validate('nonexistent-user@gmail.com');
if (!result.validators.smtp?.valid) {
console.log('Mailbox does not exist');
}Limitations
- Some mail servers block SMTP verification
- Corporate firewalls may block port 25
- Gmail and other providers may rate limit
Consider using balanced preset if you experience timeouts.
Validation Order
Validators run in this order:
- Regex - Quick format check (stops if invalid)
- Typo - Check for domain typos
- Disposable - Check if disposable
- MX - Verify mail servers exist
- SMTP - Verify mailbox exists
With earlyExit: true (default), validation stops at the first failure.
Disabling Validators
Disable validators you don't need:
// Fast validation (no network calls)
await validate('user@example.com', {
validators: {
regex: { enabled: true },
typo: { enabled: true },
disposable: { enabled: true },
mx: { enabled: false },
smtp: { enabled: false }
}
});Or use a preset:
// Balanced: No SMTP
await validate('user@example.com', { preset: 'balanced' });
// Permissive: Regex only
await validate('user@example.com', { preset: 'permissive' });