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

email-deliverability

v0.4.1

Published

Modern email validation and DNS deliverability checks for Node.js and Bun, with provider inference and SMTP diagnostics.

Readme

email-deliverability

npm version npm downloads TypeScript types Node.js runtime deps packed size license

Modern email validation and deliverability checks for Node.js and Bun.

Validate syntax, normalize addresses, check DNS MX/Null MX/A/AAAA fallback, infer mail providers, flag disposable and free-provider domains, suggest typo fixes, and run opt-in SMTP diagnostics without pretending SMTP proves mailbox existence.

Install

bun add email-deliverability
# or
npm install email-deliverability

Requirements:

  • Bun or Node.js >=22
  • ESM imports. CommonJS projects can use dynamic import().
  • No required runtime dependencies.
  • No API key, hosted verifier, quota, or remote email-verification service.

Quick Start

import { validateEmail } from "email-deliverability";

const result = await validateEmail("[email protected]");

if (result.recommendation === "accept" && result.parsed) {
  console.log(result.parsed.normalized);
} else {
  console.log(result.status, result.reason);
}

Use status, reason, and recommendation for product decisions. Use checks, issues, and decision.blockedBy for the audit trail.

valid and decision.accepted reflect the blocking policy you configured. They can stay true for diagnostic findings, such as SMTP rejection without policy.blockOnSmtpRejection. The top-level summary still surfaces those facts.

What This Checks

  • Syntax and normalization, including IDN domains.
  • DNS mail deliverability through MX, Null MX, A/AAAA fallback, and provider inference.
  • Optional disposable-domain and free-provider signals.
  • Optional conservative typo suggestions.
  • SMTP diagnostics for operators who understand the tradeoffs.

What This Cannot Prove

This package does not prove inbox placement, spam-folder placement, sender reputation, guaranteed mailbox existence, or that a message will not bounce. SMTP probing is unreliable: many providers tarp it, hide recipient status, block port 25, greylist, use catch-all domains, or return false answers to reduce abuse.

Common Flows

Signup/account creation:

await validateEmail(email, {
  checks: {
    dns: true,
    typo: true,
    disposable: true,
    freeProvider: true,
  },
  policy: {
    blockDisposable: true,
  },
});

Login:

await validateEmail(email, {
  checks: { dns: false },
});

Work email collection:

await validateEmail(email, {
  checks: { dns: true, freeProvider: true, disposable: true },
  policy: { requireBusinessEmail: true, blockDisposable: true },
});

DNS-only deliverability:

import { checkEmailDomainDeliverability } from "email-deliverability";

const dns = await checkEmailDomainDeliverability("[email protected]");

if (dns.deliverability === "deliverable") {
  console.log("Domain is configured to receive mail.");
}

Syntax-only validation:

import { isEmailSyntaxValid, parseEmail } from "email-deliverability/syntax";

isEmailSyntaxValid("User@例え.テスト"); // true

const parsed = parseEmail("Jane <[email protected]>", {
  syntax: { allowDisplayName: true },
});

Browser-safe helpers:

import {
  isDisposableEmailDomain,
  isFreeEmailDomain,
  parseEmail,
} from "email-deliverability/browser";

The browser export does not import DNS, TCP, or TLS modules.

SMTP Diagnostics

SMTP probing is opt-in and diagnostic. It should not be used as a default signup gate unless you fully understand the operational cost and false answers.

await validateEmail(email, {
  checks: { smtp: true },
  smtp: {
    sender: "[email protected]",
    heloName: "example.com",
    timeoutMs: 5_000,
  },
});

When SMTP is enabled, catch-all detection runs by default after the target recipient is accepted. Set smtp.detectCatchAll: false only when you are doing a low-level probe and do not want the extra randomized RCPT check.

SMTP rejection affects decision.accepted only when you explicitly ask for it:

await validateEmail(email, {
  checks: { smtp: true },
  policy: { blockOnSmtpRejection: true },
});

The SMTP implementation resolves MX/fallback hosts first, connects to vetted IPs, blocks private/reserved networks by default, supports STARTTLS, and treats catch-all/temporary/timeout states as inconclusive.

Batch Validation

import { validateEmails } from "email-deliverability";

const batch = await validateEmails(emails, {
  checks: { dns: true, disposable: true },
  policy: { blockDisposable: true },
  batch: {
    concurrency: 20,
    dnsConcurrency: 8,
    smtpConcurrency: 2,
  },
});

console.log(batch.summary);

Batch validation preserves result order and avoids unbounded DNS/SMTP fan-out.

Custom Resolver And Cache

import { createEmailValidator } from "email-deliverability";

const validator = createEmailValidator({
  checks: { dns: true },
  dns: {
    timeoutMs: 2_000,
    resolver: myResolver,
    cache: myCache,
  },
});

await validator.validateEmail("[email protected]");

Resolvers and caches are injectable so tests, serverless apps, and larger systems can control timeouts, retries, and DNS behavior.

Result Shape

Every result separates facts from policy:

const result = await validateEmail("[email protected]", {
  checks: { dns: true, freeProvider: true },
});

result.status; // "deliverable" | "undeliverable" | "risky" | "unknown"
result.reason; // "accepted" | "catch_all" | "no_mail_server" | ...
result.recommendation; // "accept" | "reject" | "verify"
result.checks.syntax.status; // "pass" | "fail"
result.checks.dns.deliverability; // "deliverable" | "undeliverable" | ...
result.checks.dns.provider?.id; // "google_workspace" | "cloudflare_email_routing" | ...
result.checks.freeProvider.freeProvider; // boolean | undefined
result.issues; // stable codes, stages, messages, paths
result.decision.blockedBy; // policy decisions only

DNS provider inference is MX-based and conservative. Unknown providers are unset; mixed known providers return provider.id: "mixed".

Machine-readable issue.code, issue.stage, issue.path, and issue.params are the integration surface. issue.message is display text.

Built-in message locales: en, es, fr, de, pt-BR, hi, ja, zh-CN.

await validateEmail("bad", { locale: "es" });

Runtime Boundaries

email-deliverability has no required runtime dependencies and does not call a remote verification API. DNS and SMTP are server-side only.

  • email-deliverability: full Node.js/Bun server API.
  • email-deliverability/syntax: parsing and normalization only.
  • email-deliverability/browser: browser-safe parsing and dataset helpers.
  • The package is ESM-only. CommonJS projects should use dynamic import().

Browsers, edge runtimes, serverless platforms, containers, and cloud hosts may block DNS APIs or outbound port 25. Disable DNS/SMTP checks when they do not fit your runtime.

Why Not Just Regex?

Regex can catch obvious typos, but it does not normalize IDN domains, handle Null MX, separate syntax from policy, expose structured failure reasons, or tell you whether a domain is configured to receive mail.

Why Not validator.js?

validator.js is useful for syntax-style checks. This package is for product flows that also need normalization, DNS deliverability, dataset signals, localized structured issues, and explicit runtime boundaries.

Why Not deep-email-validator?

deep-email-validator popularized DNS/SMTP checks in Node. This package keeps SMTP explicitly diagnostic, separates typo/disposable/free-provider signals from policy decisions, and documents serverless and port-25 limitations directly.

Why Not An API Verifier?

API-backed verifiers can be useful when you want a hosted score and are willing to send user emails to a third party. This package is local code: no API key, no quota, and no remote verification service.

Comparison

| Capability | email-deliverability | validator.js | deep-email-validator | API verifier | | --- | --- | --- | --- | --- | | Syntax and normalization | Yes | Syntax mostly | Yes | Usually | | DNS MX/Null MX/A fallback | Yes | No | Yes | Usually | | Disposable/free-provider signals | Yes | No | Disposable | Usually | | Optional SMTP diagnostics | Yes, explicit | No | Yes | Usually | | Claims mailbox existence | No | No | Risky in practice | Often implied | | Browser-safe subpath | Yes | Yes | No | Client call not recommended | | Requires API key | No | No | No | Yes | | Required runtime deps | None | None | Yes | SDK/client |

Package Size

The npm tarball target is under 100 KiB while shipping built-in free-provider and disposable-domain datasets. bun run release:check enforces the size budget and pack allowlist.

Maintainers

Release and maintenance process lives in the repo: