How to Detect Disposable Emails in Your Signup Flow
Matt King
February 28, 2026
Disposable email detection works by checking an email's domain against a database of known throwaway providers. The database must be updated continuously — new disposable services launch daily, and some rotate through thousands of domains. A static blocklist degrades within weeks. An API that maintains a real-time database is the only reliable approach for production.
This guide covers the complete implementation: where to check, how to handle the response, what to tell the user, and the edge cases most teams miss.
The Implementation in Three Steps
Step 1: Call the Validation API on Form Submit
The check should happen server-side when the signup form is submitted, before creating the user account:
// Express.js example
app.post('/signup', async (req, res) => {
const { email, password, name } = req.body;
// Validate email before anything else
const validation = await fetch('https://api.fidro.io/v1/validate/email', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.FIDRO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ email }),
}).then(r => r.json());
if (validation.disposable) {
return res.status(422).json({
error: 'Please use a permanent email address. Temporary emails are not accepted.',
});
}
if (!validation.dns_valid) {
return res.status(422).json({
error: 'This email domain does not appear to be valid. Please check for typos.',
});
}
// Email is clean — proceed with account creation
const user = await createUser({ email, password, name });
res.json({ user });
});
Step 2: Handle Edge Cases
API timeout: Fail open. If the API doesn't respond within 3 seconds, allow the signup and validate asynchronously:
let validation;
try {
const controller = new AbortController();
setTimeout(() => controller.abort(), 3000);
validation = await fetch('https://api.fidro.io/v1/validate/email', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.FIDRO_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ email }),
signal: controller.signal,
}).then(r => r.json());
} catch (err) {
// API timeout or error — allow signup, validate later
console.warn('Email validation timeout, proceeding with signup');
validation = null;
}
Caching: Cache validation results to avoid duplicate API calls on form resubmissions:
const cacheKey = `email:${email}`;
let validation = await redis.get(cacheKey);
if (!validation) {
validation = await callFidroApi(email);
await redis.setex(cacheKey, 86400, JSON.stringify(validation)); // 24h TTL
} else {
validation = JSON.parse(validation);
}
Step 3: Show Clear Error Messages
When a disposable email is detected, tell the user exactly what's wrong and what to do:
Good: "Please use a permanent email address. Temporary and disposable email addresses are not accepted."
Bad: "Invalid email address." (Confusing — the format might be valid)
Bad: "Email not accepted." (Vague — doesn't help the user fix it)
Bad: "Fraudulent email detected." (Accusatory — alienates legitimate users who made an honest mistake)
Optional: Client-Side Pre-Check
For a faster user experience, add a lightweight check when the user tabs out of the email field. This provides instant feedback without waiting for form submission:
const emailInput = document.getElementById('email');
emailInput.addEventListener('blur', async () => {
const email = emailInput.value;
if (!email || !email.includes('@')) return;
const res = await fetch(`/api/check-email?email=${encodeURIComponent(email)}`);
const data = await res.json();
if (data.disposable) {
showError('Please use a permanent email address.');
}
});
Important: Always validate server-side too. Client-side checks can be bypassed by disabling JavaScript or calling your API directly.
What Not to Block
Not every unusual email is disposable. Avoid blocking these legitimate categories:
- Gmail/Yahoo/Outlook — Free but permanent. See our guide on the difference.
- Plus-addressed emails (user+tag@gmail.com) — Real inboxes using Gmail's alias feature.
- Apple Hide My Email — Private relay addresses tied to real Apple IDs.
- ProtonMail/Tutanota — Privacy-focused but permanent.
- Custom domains — Even unusual-looking ones might be legitimate businesses.
A good validation API like Fidro distinguishes between these categories automatically, returning disposable: true only for actual throwaway providers.
Measuring the Impact
After implementing detection, track these metrics:
| Metric | Before | Expected After |
|---|---|---|
| Disposable email signups | ~20-25% of total | <3% of total |
| Email bounce rate | 5-10% | <1% |
| Reported conversion rate | Lower (diluted) | Higher (accurate) |
| Free tier abuse incidents | Frequent | Rare |
Most teams see results within the first week. The impact is immediate because you're removing a category of signups that had zero value.
Getting Started
- Sign up for a free API key — 200 validations per month
- Test with the free email checker tool to see the response format
- Add the server-side check to your signup form
- Optional: add client-side pre-check for faster UX
- Monitor your metrics for 30 days