npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

bouncevalidator

v0.0.2

Published

A completely local email validation service - alternative to ZeroBounce, Bouncify, and Debounce

Readme

BounceValidator

A completely local email validation service for Node.js. An alternative to cloud-based services like ZeroBounce, Bouncify, and Debounce - with zero external API dependencies.

Features

  • 100% Local - No external API calls, all validation happens on your machine
  • Syntax Validation - RFC 5322 compliant email format validation
  • DNS/MX Verification - Verifies domain has valid mail exchange records
  • SMTP Verification - Connects to mail servers to verify mailbox existence
  • Disposable Email Detection - Identifies temporary/throwaway email addresses
  • Role Account Detection - Flags role-based emails (admin@, support@, etc.)
  • Free Provider Detection - Identifies emails from free providers (Gmail, Yahoo, etc.)
  • Typo Suggestions - Suggests corrections for common domain typos
  • Catch-All Detection - Identifies domains that accept all addresses
  • Bulk Validation - Process multiple emails with configurable concurrency
  • DNS Caching - Improves performance for repeated lookups
  • CLI & Programmatic API - Use from command line or as a library

Installation

npm install bouncevalidator

Or with yarn:

yarn add bouncevalidator

Quick Start

Programmatic Usage

import { validate } from 'bouncevalidator';

const result = await validate('[email protected]');

console.log(result.isReachable);  // 'safe', 'invalid', 'risky', or 'unknown'
console.log(result.syntax.isValidSyntax);  // true/false
console.log(result.mx.acceptsMail);  // true/false
console.log(result.smtp.isDeliverable);  // true/false
console.log(result.misc.isDisposable);  // true/false

CLI Usage

# Validate a single email
npx bouncevalidator [email protected]

# Validate with pretty output
npx bouncevalidator -p [email protected]

# Quick validation (skip SMTP)
npx bouncevalidator -q [email protected]

# Validate from file
npx bouncevalidator -f emails.txt -o results.json

API Reference

validate(email, options?)

Validates a single email address through the full verification pipeline.

Parameters:

  • email (string) - The email address to validate
  • options (ValidationOptions) - Optional configuration

Returns: Promise<ValidationResult>

import { validate } from 'bouncevalidator';

const result = await validate('[email protected]', {
  smtpTimeout: 15000,
  checkGravatar: true
});

validateBulk(emails, options?)

Validates multiple email addresses with configurable concurrency.

Parameters:

  • emails (string[]) - Array of email addresses
  • options (BulkValidationOptions) - Optional configuration

Returns: Promise<ValidationResult[]>

import { validateBulk } from 'bouncevalidator';

const results = await validateBulk([
  '[email protected]',
  '[email protected]',
  '[email protected]'
], {
  concurrency: 10,
  onProgress: (completed, total, result) => {
    console.log(`${completed}/${total}: ${result.input} - ${result.isReachable}`);
  }
});

validateQuick(email)

Quick validation that only checks syntax and MX records (skips SMTP verification).

Parameters:

  • email (string) - The email address to validate

Returns: Promise<ValidationResult>

import { validateQuick } from 'bouncevalidator';

const result = await validateQuick('[email protected]');

Individual Validators

You can use individual validators for more control:

import {
  validateSyntax,
  verifyMx,
  verifySmtp,
  checkMisc,
  checkDisposable,
  checkRoleAccount,
  checkFreeProvider
} from 'bouncevalidator';

// Syntax validation only
const syntax = validateSyntax('[email protected]');

// MX verification only
const mx = await verifyMx('example.com');

// Check if domain is disposable
const isDisposable = checkDisposable('tempmail.com');

// Check if email is role-based
const isRole = checkRoleAccount('admin');

Utility Functions

import {
  normalizeEmail,
  extractParts,
  getSuggestion,
  getEmailSuggestion
} from 'bouncevalidator';

// Normalize email
const normalized = normalizeEmail('[email protected]');  // '[email protected]'

// Extract parts
const parts = extractParts('[email protected]');
// { username: 'user', domain: 'example.com' }

// Get domain typo suggestion
const suggestion = getSuggestion('gmial.com');  // 'gmail.com'

// Get full email suggestion
const emailSuggestion = getEmailSuggestion('[email protected]');
// '[email protected]'

Configuration Options

ValidationOptions

| Option | Type | Default | Description | |--------|------|---------|-------------| | smtpTimeout | number | 10000 | SMTP connection timeout in milliseconds | | verifySmtp | boolean | true | Whether to perform SMTP verification | | checkDisposable | boolean | true | Check for disposable email domains | | checkRoleAccount | boolean | true | Check for role-based accounts | | checkFreeProvider | boolean | true | Check for free email providers | | checkGravatar | boolean | false | Check for Gravatar existence | | heloHost | string | hostname | Custom HELO/EHLO hostname | | senderAddress | string | '' | Custom MAIL FROM address | | dnsCacheTtl | number | 300000 | DNS cache TTL in milliseconds | | useDnsCache | boolean | true | Whether to use DNS caching | | detectCatchAll | boolean | true | Detect catch-all domains |

BulkValidationOptions

Extends ValidationOptions with:

| Option | Type | Default | Description | |--------|------|---------|-------------| | concurrency | number | 5 | Maximum concurrent validations | | delayBetween | number | 0 | Delay between batches in milliseconds | | onProgress | function | - | Progress callback function |

ValidationResult Structure

interface ValidationResult {
  input: string;              // Original email input
  isReachable: Reachability;  // 'safe' | 'invalid' | 'risky' | 'unknown'

  syntax: {
    address: string;          // Original address
    domain: string;           // Domain part
    username: string;         // Local part
    isValidSyntax: boolean;   // Syntax validity
    normalizedEmail: string;  // Normalized version
    suggestion: string | null; // Typo suggestion
  };

  mx: {
    acceptsMail: boolean;     // Has valid MX records
    records: string[];        // List of MX hostnames
  };

  smtp: {
    canConnectSmtp: boolean;  // Could connect to server
    isDeliverable: boolean;   // Mailbox exists
    isCatchAll: boolean;      // Domain is catch-all
    error: {
      type: string;           // Error type
      message: string;        // Error message
    } | null;
  };

  misc: {
    isDisposable: boolean;    // Disposable domain
    isRoleAccount: boolean;   // Role-based account
    isFreeProvider: boolean;  // Free email provider
    gravatarUrl: string | null; // Gravatar URL if exists
  };
}

Reachability Status

| Status | Description | |--------|-------------| | safe | Email is verified to exist and can receive mail | | invalid | Email has invalid syntax, domain doesn't exist, or mailbox not found | | risky | Email might be valid but couldn't be verified (catch-all, greylisted, etc.) | | unknown | Verification was inconclusive due to server issues |

CLI Reference

bouncevalidator - Local email validation service

USAGE:
  bouncevalidator [OPTIONS] <email>...
  bouncevalidator -f <file> [OPTIONS]

ARGUMENTS:
  <email>...              Email addresses to validate

OPTIONS:
  -h, --help              Show help message
  -v, --version           Show version number
  -f, --file <path>       Read emails from file (one per line)
  -o, --output <path>     Write results to file
  -q, --quick             Quick mode (skip SMTP verification)
  -p, --pretty            Pretty print JSON output
  --verbose               Show detailed progress

VALIDATION OPTIONS:
  -t, --timeout <ms>      SMTP timeout (default: 10000)
  -c, --concurrency <n>   Max concurrent validations (default: 5)
  --no-smtp               Skip SMTP verification
  --no-disposable         Skip disposable email check
  --no-role               Skip role account check
  --no-free-provider      Skip free provider check
  --gravatar              Check for Gravatar

EXIT CODES:
  0  All emails are valid (safe)
  1  One or more emails are invalid
  2  One or more emails are risky or unknown
  3  Error occurred during validation

Examples

Basic Validation

import { validate } from 'bouncevalidator';

async function checkEmail(email: string) {
  const result = await validate(email);

  if (result.isReachable === 'safe') {
    console.log('Email is valid and deliverable');
  } else if (result.isReachable === 'invalid') {
    console.log('Email is invalid:', result.smtp.error?.message);
  } else {
    console.log('Email status uncertain:', result.isReachable);
  }
}

Bulk Validation with Progress

import { validateBulk } from 'bouncevalidator';
import fs from 'fs';

async function validateEmailList(filePath: string) {
  const emails = fs.readFileSync(filePath, 'utf-8')
    .split('\n')
    .map(e => e.trim())
    .filter(e => e.length > 0);

  const results = await validateBulk(emails, {
    concurrency: 10,
    onProgress: (completed, total, result) => {
      const pct = Math.round((completed / total) * 100);
      process.stdout.write(`\r[${pct}%] Validating emails...`);
    }
  });

  const valid = results.filter(r => r.isReachable === 'safe');
  const invalid = results.filter(r => r.isReachable === 'invalid');

  console.log(`\nValid: ${valid.length}, Invalid: ${invalid.length}`);

  return results;
}

Custom Validation Pipeline

import {
  validateSyntax,
  verifyMx,
  checkDisposable,
  checkRoleAccount
} from 'bouncevalidator';

async function customValidation(email: string) {
  // Step 1: Check syntax
  const syntax = validateSyntax(email);
  if (!syntax.isValidSyntax) {
    return { valid: false, reason: 'Invalid syntax' };
  }

  // Step 2: Check if disposable
  if (checkDisposable(syntax.domain)) {
    return { valid: false, reason: 'Disposable email' };
  }

  // Step 3: Check if role account
  if (checkRoleAccount(syntax.username)) {
    return { valid: false, reason: 'Role-based account' };
  }

  // Step 4: Verify MX records
  const mx = await verifyMx(syntax.domain);
  if (!mx.acceptsMail) {
    return { valid: false, reason: 'Domain does not accept mail' };
  }

  return { valid: true, domain: syntax.domain, mx: mx.records };
}

Express.js Integration

import express from 'express';
import { validate, validateBulk } from 'bouncevalidator';

const app = express();
app.use(express.json());

// Single email validation endpoint
app.post('/api/validate', async (req, res) => {
  const { email } = req.body;

  if (!email) {
    return res.status(400).json({ error: 'Email is required' });
  }

  try {
    const result = await validate(email);
    res.json(result);
  } catch (err) {
    res.status(500).json({ error: 'Validation failed' });
  }
});

// Bulk validation endpoint
app.post('/api/validate/bulk', async (req, res) => {
  const { emails } = req.body;

  if (!Array.isArray(emails)) {
    return res.status(400).json({ error: 'Emails array is required' });
  }

  try {
    const results = await validateBulk(emails, { concurrency: 5 });
    res.json(results);
  } catch (err) {
    res.status(500).json({ error: 'Validation failed' });
  }
});

app.listen(3000);

How It Works

1. Syntax Validation

The first step validates the email format against RFC 5322 standards:

  • Checks for valid characters in local and domain parts
  • Validates domain structure and TLD
  • Enforces length limits (254 chars total, 64 chars local part)

2. DNS/MX Verification

Next, we query DNS to verify the domain can receive email:

  • Looks up MX (Mail Exchange) records
  • Falls back to A/AAAA records if no MX exists (per RFC 5321)
  • Detects null MX records (RFC 7505)
  • Caches results for performance

3. SMTP Verification

The most reliable check - we connect to the mail server:

  1. Connect to the highest priority MX host
  2. Send EHLO/HELO greeting
  3. Initiate MAIL FROM command
  4. Send RCPT TO with the target email
  5. Interpret the server's response

Response codes:

  • 250: Mailbox exists
  • 550: Mailbox not found
  • 450/451: Greylisted or temporary failure
  • 552: Mailbox disabled

4. Additional Checks

Finally, we perform supplementary checks:

  • Disposable detection: Compares domain against 500+ known disposable email services
  • Role account detection: Checks for common role-based prefixes (admin, support, info, etc.)
  • Free provider detection: Identifies free email services (Gmail, Yahoo, Outlook, etc.)
  • Catch-all detection: Tests if domain accepts any random address

Limitations

  • SMTP verification may be blocked: Some mail servers block or rate-limit SMTP verification attempts
  • Greylisting: Some servers use greylisting which causes temporary rejections
  • Catch-all domains: Cannot definitively verify addresses on catch-all domains
  • Network dependent: Requires network access for DNS and SMTP operations
  • No DMARC/SPF checks: Does not validate sending reputation

Performance Tips

  1. Use DNS caching: Enabled by default, reduces repeated DNS lookups
  2. Adjust concurrency: Higher concurrency for bulk operations, but be mindful of rate limits
  3. Use quick mode: Skip SMTP verification when you only need syntax/MX validation
  4. Batch operations: Use validateBulk instead of multiple validate calls

Contributing

Contributions are welcome! Please feel free to submit issues and pull requests.

Author

Developed and maintained by HyScaler Node.js Team.

HyScaler is a software development company specializing in building scalable, high-performance applications. We help businesses scale their technology with expert development services.

License

MIT