Email Verification
How to Block Disposable Emails at Signup (Without Losing Real Users)
To block disposable emails at signup, check the domain of each submitted address against a maintained list of temporary-inbox domains, on the server, before you create the account. If it matches, show a clear message asking for a permanent address. Refresh the list on a schedule, keep an allowlist for false positives, and pair the check with email confirmation so throwaway addresses that slip through never become active accounts.
This guide walks through the full setup: where the check belongs, sample code, wording that doesn’t annoy real users, and the edge cases that catch most teams.
Why block disposable emails at signup
Signup is the cheapest place to stop a throwaway address. Once it’s in your database it costs you money: trial resources, onboarding emails that bounce, and skewed activation metrics.
The usual reasons teams add this check:
- Free-trial and promo abuse. One person, many accounts.
- Bot registrations. OWASP catalogs bulk account creation as OAT-019, where attackers create accounts through your normal signup flow and later use them for spam, fraud, or manipulating reviews.
- Bounce control. Temporary inboxes expire, and the next email you send them bounces. Most email platforms watch bounce rates closely. Amazon SES puts accounts under review at 5% (AWS docs).
- Reachability. Password resets, receipts, and security notices have to arrive.
Large platforms do this too. PyPI blocks known throwaway domains at registration, using the open-source disposable-domains list together with its own internal list (PyPI blog). HubSpot forms reject some disposable domains even when the customer hasn’t turned on free-email blocking (HubSpot Knowledge Base).
If you need a primer on the kinds of throwaway addresses first, start with what is a disposable email address.
Step-by-step: blocking disposable email domains
1. Pick a data source
You have three realistic options:
| Source | Pros | Cons |
|---|---|---|
| Open-source list (disposable-email-domains) | Free, CC0 license, widely used, easy to audit | Community-maintained; new domains lag; you handle updates |
| Commercial verification API | Updated continuously, often combines other signals | Cost, vendor dependency, data leaves your system |
| Your own internal list | Catches domains specific to your abuse | Needs someone to maintain it |
Most teams start with the open-source list and add their own entries as abuse shows up. The project’s blocklist file had close to 10,000 domains when we checked in October 2026. The maintainers accept removal requests if you can give a reason, and they ask for proof (a screenshot of the service generating addresses) before adding a domain.
2. Normalize the address
Before checking, normalize the input:
- Trim whitespace.
- Lowercase the domain. Domains aren’t case-sensitive.
- Split on the last
@, not the first. Quoted local parts can technically contain@. - Convert internationalized domains to their ASCII (punycode) form so they match list entries.
3. Check the domain and its parent domains
Some disposable services hand out addresses on subdomains, such as user@abc.tempservice.example. The open-source list stores registrable domains, so check every parent level:
// Node.js — load once at startup, refresh on a schedule
import { readFileSync } from "node:fs";
let blocklist = new Set(
readFileSync("disposable_email_blocklist.conf", "utf8")
.split("\n").map(s => s.trim().toLowerCase()).filter(Boolean)
);
const allowlist = new Set(["example-partner.com"]); // your overrides
export function isDisposable(email) {
const domain = email.trim().slice(email.lastIndexOf("@") + 1).toLowerCase();
if (allowlist.has(domain)) return false;
const parts = domain.split(".");
for (let i = 0; i < parts.length - 1; i++) {
if (blocklist.has(parts.slice(i).join("."))) return true;
}
return false;
}
4. Run the check on the server
Client-side checks are good for instant feedback, but anyone can skip them by calling your API directly. The authoritative check has to run on the server, in the same handler that creates the account. A sensible flow:
- Browser: basic syntax check and a quick “did you mean?” typo hint.
- Server: syntax, disposable-domain lookup, optionally an MX lookup.
- Server: create the account in an unverified state.
- Send a confirmation email. Unlock the account (or the trial) only after the user clicks.
Step 4 matters. OWASP’s bot-management guidance recommends gating features behind email verification instead of just sending a confirmation, and checking signups against disposable-domain lists that you refresh weekly (OWASP Cheat Sheet).
5. Write a helpful error message
Compare two messages:
- Bad: “Invalid email address.”
- Better: “This looks like a temporary inbox. Please use an email address you’ll keep, so you can receive your login link and receipts.”
The second tells an honest user exactly what to do and doesn’t accuse anyone. Don’t reveal which list you use or exactly how detection works.
6. Keep the list fresh
Schedule a job (daily or weekly) that pulls the latest list, validates it isn’t empty or truncated, and swaps it in atomically. If the download fails, keep the old copy. Log every block with the domain so you can spot new domains that need adding to your internal list.
7. Watch for false positives
Track how many signups get blocked and on which domains. If a domain that real customers use shows up on the list, add it to your allowlist and report it upstream with your reasons.
What not to block
A blanket “block anything that isn’t a corporate domain” rule loses real customers. Be careful with these:
- Forwarding aliases like Apple’s Hide My Email. These forward to the person’s real inbox until they deactivate them (Apple Support). Blocking them mostly punishes privacy-conscious users, and in many apps they arrive through “Sign in with Apple.”
- Plus addresses like
jane+app@gmail.com. They deliver to a permanent inbox. More on this in plus addressing and email aliases. - Free providers such as Gmail, Outlook, and Yahoo. These are personal addresses, not disposable ones. Whether to accept them is a separate business question, covered in free email providers vs business domains.
One caution about mainstream providers: PyPI eventually stopped new Outlook and Hotmail registrations after a wave of bot signups using those domains (PyPI blog). That was a targeted response to a specific attack on a high-value target. It isn’t a sensible default for a typical SaaS or store.
A proportionate policy by use case
| Signup type | Temporary inboxes | Forwarding aliases | Plus addresses |
|---|---|---|---|
| Newsletter | Allow + confirm, or block | Allow | Allow |
| Gated content download | Block or warn | Allow | Allow |
| Free trial with real cost | Block | Allow, monitor | Allow, normalize for one-trial checks |
| Ecommerce checkout | Warn, don’t block | Allow | Allow |
| Marketplace / community with spam issues | Block | Allow, add rate limits | Allow |
Two notes on the table:
- “Normalize for one-trial checks” means stripping the
+tagfrom the local part when you check whether this person has already had a trial. Store the address exactly as the user entered it, but compare on the normalized form. - Checkout is the one place to avoid hard blocks. A warning (“you won’t receive your receipt at this address”) lets the customer decide, and you keep the sale.
Blocking disposable emails is one layer, not the whole defense
A domain list stops casual abuse. Determined attackers will register fresh domains, use real free-provider accounts, or rotate aliases. Combine the disposable check with:
- Rate limits per IP, network, and device on the signup endpoint.
- Bot challenges that are invisible for most users, such as risk-scoring CAPTCHAs.
- Confirmed opt-in, which Spamhaus calls the gold standard because traps, typos, and bots can’t click a confirmation link (Spamhaus FAQ).
- Behavioral signals after signup, such as accounts that never verify, or that verify and then immediately do something abusive.
We go deeper on these in how to stop fake signups and bot registrations and email signals for detecting signup fraud.
Test addresses before you write code
If you want to see how an address would be classified before building anything, paste it into our free email verifier. It flags known disposable domains, checks syntax and MX records, and notes role addresses, free providers, and likely domain typos. It doesn’t connect to the recipient’s mail server, so it won’t tell you whether a particular mailbox exists. Use it to sanity-check your rules, then run the same logic in your backend. For bulk or automated checks, see the API details.
FAQ
What is the best way to block disposable emails?
Check the domain against a maintained disposable-domain list on the server at signup, and show a clear message asking for a permanent address. Refresh the list regularly, keep an allowlist for mistakes, and require email confirmation before activating the account.
Can users get around a disposable email block?
Yes. They can use a domain that isn’t on the list yet, a free webmail account, or a forwarding alias. That’s why a domain check works best alongside confirmation emails, rate limits, and bot detection, not as your only control.
Should I block Apple Hide My Email addresses?
Usually not. These aliases forward to a real, active inbox, and many people get them automatically through “Sign in with Apple.” Blocking them turns away legitimate, privacy-minded customers without much benefit.
How often should I update my disposable domain list?
At least weekly, which matches OWASP’s bot-management guidance. Automate the download, sanity-check the file size before replacing your copy, and log the domains you block so you can add new ones yourself.
Does blocking disposable emails help deliverability?
Indirectly, yes. Temporary inboxes expire and then hard bounce, and high bounce rates hurt your sender reputation and can trigger reviews by your email provider. Keeping them off your list keeps bounces down. See how to reduce email bounce rate for the rest of the checklist.
Free email verifier: syntax, MX, disposable and role-based addresses, typos. Paste up to 100 at once.