Disposable email addresses (mailinator.com, 10minutemail.com, guerrillamail.com) are created solely to bypass signup requirements and are abandoned immediately after use. Contacts from these domains never open, never click, and frequently expire — sending to them raises complaint rates and depresses engagement signals that ISPs use to classify your reputation. CWE-20 applies: accepting input you know to be functionally invalid is an input validation failure. High-volume disposable-address lists also skew A/B test results, distort open-rate reporting, and inflate subscription counts that feed into billing tiers or investor metrics.
High because disposable addresses predictably deliver zero engagement and elevated complaints, degrading sender reputation and corrupting list-level analytics used for business decisions.
Add a disposable domain check at the ingest point using the disposable-email-domains npm package as a baseline, supplemented by an API service for real-time coverage:
import disposableDomains from 'disposable-email-domains'
function isDisposable(email: string): boolean {
const domain = email.split('@')[1]?.toLowerCase()
return domain ? disposableDomains.includes(domain) : false
}
// In your ingest handler:
if (isDisposable(email)) {
return res.status(422).json({ error: 'Disposable email addresses are not accepted' })
}
The disposable-email-domains package covers ~10,000 domains but is updated only at npm release cadence. For production lists above 10k contacts/month, complement it with ZeroBounce or Kickbox API calls that maintain real-time lists. Reject at signup rather than quarantining — quarantine segments require ongoing maintenance and often go unsuppressed.
ID: data-quality-list-hygiene.email-validation.disposable-domain-detection
Severity: high
What to look for: Check whether the ingest path compares the email domain against a list of known disposable/temporary email providers (mailinator.com, guerrillamail.com, 10minutemail.com, etc.). Look for the disposable-email-domains npm package, a custom block-list file, or an external API call that returns a disposability score. Count the number of domains in the block-list if a custom list is used — fewer than 200 domains is insufficient coverage.
Pass criteria: New contacts are checked against a maintained disposable domain list containing at least 200 known disposable domains. Disposable addresses are either rejected or placed in a quarantine segment that is excluded from sends.
Fail criteria: No disposable domain check is performed, or the block-list has not been updated in over 6 months, or the block-list contains fewer than 200 domains.
Skip (N/A) when: The system only accepts contacts from verified OAuth sign-ins (Google, GitHub) where disposable addresses are already blocked upstream.
Detail on fail: Example: "No disposable email check — users can subscribe with mailinator.com addresses" or "Block-list last updated 2023-08-01, over 6 months stale"
Remediation: Use a maintained package or API:
import disposableDomains from 'disposable-email-domains'
function isDisposable(email: string): boolean {
const domain = email.split('@')[1]?.toLowerCase()
return domain ? disposableDomains.includes(domain) : false
}
For higher accuracy, complement the package with an API service (ZeroBounce, NeverBounce, Kickbox) that maintains real-time lists. Decide whether to reject disposable addresses outright or route them to a separate segment — rejection at signup is generally preferable.