Zero-dependency disposable/burner email detector
Project description
burner-bouncer
Detect disposable / burner email addresses instantly. Zero runtime dependencies. Ships as both an npm package (TypeScript, ESM + CJS), a JSR package (Deno/Bun), and a Python package, backed by a single shared blocklist of 500+ real disposable-email domains.
Why Burner Bouncer?
- No external requests — the blocklist is bundled at install time; nothing is phoned home at runtime.
- Dual ecosystem — identical API surface in JavaScript/TypeScript and Python so you can use the same library across your stack.
- Always typed — full TypeScript types and a typed Python dataclass result, no
anyguessing. - Tiny — the entire JS bundle is under 10 kB gzipped.
- 500+ domains — covers Mailinator, Guerrilla Mail, YOPmail, 10MinuteMail, Temp-Mail, Maildrop, and hundreds more.
- CLI included — run
npx burner-bouncer check <email>with no install. - Weekly auto-sync — a GitHub Actions workflow opens PRs to keep the blocklist fresh from upstream sources.
JavaScript / TypeScript
Installation
npm install burner-bouncer
# or
pnpm add burner-bouncer
# or
yarn add burner-bouncer
Deno / JSR
deno add @grocerysushi/burner-bouncer
CLI (no install required)
npx burner-bouncer check user@mailinator.com
npx burner-bouncer check a@mailinator.com b@gmail.com
npx burner-bouncer check user@company.com --dns # also verify MX record
npx burner-bouncer blocklist # print all blocked domains
Usage
import {
isDisposable, check, checkMany, getDomain, getBlocklist,
isFreeProvider, isRoleAddress, suggest, getFreeProviders, checkWithDns,
} from 'burner-bouncer';
// Quick boolean check
isDisposable('user@mailinator.com'); // true
isDisposable('user@gmail.com'); // false
isDisposable('notanemail'); // false
// Free provider detection (Gmail, Yahoo, Hotmail, etc.)
isFreeProvider('user@gmail.com'); // true
isFreeProvider('user@company.com'); // false
// Role address detection (admin, noreply, support, etc.)
isRoleAddress('admin@example.com'); // true
isRoleAddress('john@example.com'); // false
// Typo suggestion
suggest('user@gmial.com'); // 'user@gmail.com'
suggest('user@gmail.com'); // null (already correct)
// Full result object
check('test@mailinator.com');
// {
// email: 'test@mailinator.com',
// domain: 'mailinator.com',
// isDisposable: true,
// isFreeProvider: false,
// isRoleAddress: false,
// reason: 'blocklist'
// }
check('admin@gmail.com');
// { ..., isDisposable: false, isFreeProvider: true, isRoleAddress: true, reason: null }
check('notanemail');
// { email: 'notanemail', domain: null, isDisposable: false, ..., reason: 'invalid_email' }
// Batch check
checkMany(['a@mailinator.com', 'b@gmail.com', 'bad']);
// MX record validation (async, requires network)
const result = await checkWithDns('user@gmail.com');
result.hasMx; // true
// Retrieve lists
getBlocklist(); // ['10minutemail.com', ...]
getFreeProviders(); // ['aol.com', 'gmail.com', ...]
JS API Reference
| Function | Signature | Description |
|---|---|---|
isDisposable |
(email: string) => boolean |
Returns true if the email's domain is on the blocklist. |
isFreeProvider |
(email: string) => boolean |
Returns true if the domain is a known free email provider (Gmail, Yahoo, etc.). |
isRoleAddress |
(email: string) => boolean |
Returns true if the local part is a role prefix (admin, noreply, support, etc.). |
suggest |
(email: string) => string | null |
Returns a corrected email if the domain looks like a typo, otherwise null. |
check |
(email: string) => CheckResult |
Returns a full result object. |
checkMany |
(emails: string[]) => CheckResult[] |
Runs check on each email. |
checkWithDns |
(email: string) => Promise<DnsCheckResult> |
Like check but also verifies MX records via DNS. |
getDomain |
(email: string) => string | null |
Extracts and lowercases the domain. Returns null for invalid emails. |
getBlocklist |
() => string[] |
Returns a sorted copy of all blocked domains. |
getFreeProviders |
() => string[] |
Returns a sorted copy of all known free provider domains. |
CheckResult interface
interface CheckResult {
email: string;
domain: string | null;
isDisposable: boolean;
isFreeProvider: boolean;
isRoleAddress: boolean;
reason: 'blocklist' | 'invalid_email' | null;
}
interface DnsCheckResult extends CheckResult {
hasMx: boolean | null; // null when email is invalid
}
Python
Installation
pip install burner-bouncer
Usage
from burner_bouncer import (
is_disposable, check, check_many, get_domain, get_blocklist,
is_free_provider, is_role_address, suggest, get_free_providers,
check_with_dns,
)
# Quick boolean checks
is_disposable("user@mailinator.com") # True
is_free_provider("user@gmail.com") # True
is_role_address("admin@example.com") # True
suggest("user@gmial.com") # 'user@gmail.com'
# Full result dataclass
result = check("test@mailinator.com")
result.is_disposable # True
result.is_free_provider # False
result.is_role_address # False
result.reason # 'blocklist'
result.to_dict()
# MX validation
result = check_with_dns("user@gmail.com")
result.has_mx # True
# Batch check
results = check_many(["a@mailinator.com", "b@gmail.com", "bad"])
# Retrieve lists
get_blocklist() # ['10minutemail.com', ...]
get_free_providers() # ['aol.com', 'gmail.com', ...]
Python API Reference
| Function | Signature | Description |
|---|---|---|
is_disposable |
(email: str) -> bool |
Returns True if the email's domain is on the blocklist. |
is_free_provider |
(email: str) -> bool |
Returns True if the domain is a known free email provider. |
is_role_address |
(email: str) -> bool |
Returns True if the local part is a role prefix. |
suggest |
(email: str) -> Optional[str] |
Returns a corrected email for likely typos, otherwise None. |
check |
(email: str) -> CheckResult |
Returns a CheckResult dataclass instance. |
check_many |
(emails: List[str]) -> List[CheckResult] |
Runs check on each email. |
check_with_dns |
(email: str) -> DnsCheckResult |
Like check but also verifies MX records. |
get_domain |
(email: str) -> Optional[str] |
Extracts and lowercases the domain. |
get_blocklist |
() -> List[str] |
Returns a sorted list of all blocked domains. |
get_free_providers |
() -> List[str] |
Returns a sorted list of all free provider domains. |
CheckResult dataclass
@dataclass
class CheckResult:
email: str
domain: Optional[str]
is_disposable: bool
is_free_provider: bool
is_role_address: bool
reason: Optional[str] # 'blocklist' | 'invalid_email' | None
def to_dict(self) -> dict: ...
@dataclass
class DnsCheckResult:
# all CheckResult fields +
has_mx: Optional[bool] # None when email is invalid
Repository Structure
burner-bouncer/
├── data/
│ └── disposable_domains.json # Shared blocklist (500+ domains)
├── js/
│ ├── src/
│ │ ├── index.ts # JS/TS library source
│ │ └── cli.ts # CLI entrypoint (npx burner-bouncer)
│ ├── tests/
│ │ └── index.test.ts # Jest test suite
│ ├── jest.config.js
│ ├── package.json
│ └── tsconfig.json
├── python/
│ ├── burner_bouncer/
│ │ └── __init__.py # Python library source
│ ├── tests/
│ │ └── test_burner_bouncer.py
│ └── pyproject.toml
├── scripts/
│ └── sync-blocklist.js # Auto-sync blocklist from upstream sources
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ └── submit-domain.yml # "Submit a domain" form
│ └── workflows/
│ ├── ci.yml # CI: test JS + Python on every push/PR
│ ├── publish.yml # Publish to npm + JSR + PyPI on version tag
│ └── sync-blocklist.yml # Weekly blocklist sync
├── jsr.json # JSR (Deno registry) config
├── CONTRIBUTING.md
├── .gitignore
├── LICENSE
└── README.md
Contributing
See CONTRIBUTING.md for full details. The short version:
- Add domains to
data/disposable_domains.json(sorted, deduplicated, lowercase) - Run
cd js && npm testandcd python && pytest - Open a pull request — use the Submit a domain issue template for new domains
License
MIT © 2025 burner-bouncer contributors
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file burner_bouncer-1.1.1.tar.gz.
File metadata
- Download URL: burner_bouncer-1.1.1.tar.gz
- Upload date:
- Size: 6.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d2eaa9a63d602f76c9c36a49754c5ea5f747c8b7a69cc023a4c7f72cca9b95ee
|
|
| MD5 |
e6d35963af0977da9f4d9a1ae8d1e0ee
|
|
| BLAKE2b-256 |
4a8855f790232ddfbb09b6f9101713887bb20f4c7424e593fd41e27dc578c6cb
|
Provenance
The following attestation bundles were made for burner_bouncer-1.1.1.tar.gz:
Publisher:
publish.yml on grocerysushi/burner-bouncer
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
burner_bouncer-1.1.1.tar.gz -
Subject digest:
d2eaa9a63d602f76c9c36a49754c5ea5f747c8b7a69cc023a4c7f72cca9b95ee - Sigstore transparency entry: 1438879388
- Sigstore integration time:
-
Permalink:
grocerysushi/burner-bouncer@76bd10d62da2dc605f4da24a48aafdeec3930076 -
Branch / Tag:
refs/tags/v1.1.1 - Owner: https://github.com/grocerysushi
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@76bd10d62da2dc605f4da24a48aafdeec3930076 -
Trigger Event:
push
-
Statement type:
File details
Details for the file burner_bouncer-1.1.1-py3-none-any.whl.
File metadata
- Download URL: burner_bouncer-1.1.1-py3-none-any.whl
- Upload date:
- Size: 6.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
eb2f568d14c783975646f09184861db11e869c9b3df277e2200d3f6aac9fd622
|
|
| MD5 |
4b0afa80aa9ef18e269254a3025479be
|
|
| BLAKE2b-256 |
569efd8fb8641cf3d1d59a513b3b2616ae6663a5fdb9ff0ca157a9bef5f223c8
|
Provenance
The following attestation bundles were made for burner_bouncer-1.1.1-py3-none-any.whl:
Publisher:
publish.yml on grocerysushi/burner-bouncer
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
burner_bouncer-1.1.1-py3-none-any.whl -
Subject digest:
eb2f568d14c783975646f09184861db11e869c9b3df277e2200d3f6aac9fd622 - Sigstore transparency entry: 1438879394
- Sigstore integration time:
-
Permalink:
grocerysushi/burner-bouncer@76bd10d62da2dc605f4da24a48aafdeec3930076 -
Branch / Tag:
refs/tags/v1.1.1 - Owner: https://github.com/grocerysushi
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@76bd10d62da2dc605f4da24a48aafdeec3930076 -
Trigger Event:
push
-
Statement type: