SaaS companies measure growth by signups, trials, and conversions. When disposable email addresses enter the registration funnel, these metrics become distorted. Users who sign up with temporary inboxes—Mailinator, Guerrilla Mail, 10 Minute Mail, and hundreds of similar services—rarely convert to paying customers. They consume free trials, inflate user counts, and create support burden without contributing revenue. This guide explains how to integrate Emailyze at signup to block or flag disposable emails in real time, preserving conversion quality while reducing abuse.
#### The Problem: Fake Signups, Trial Abuse, and Spam Accounts
Inflated Metrics
Signup counts that include disposable users are misleading. A product team celebrating 10,000 new signups may discover that a significant portion never opens a second email or logs in after the first session. These "zombie" accounts skew retention curves, A/B test results, and growth projections. Investors and stakeholders expect metrics that reflect genuine user interest; disposable signups undermine that trust.
Trial Abuse
Free trials are a conversion lever, but they are also an abuse vector. Bad actors create multiple accounts with disposable emails to harvest trial credits, bypass usage limits, or test products without commitment. Each abused trial represents lost revenue and increased infrastructure cost. In fraud prevention terminology, trial abuse is a form of "promotion abuse"—exploiting generous offers without intent to convert.
Spam and Bot Accounts
Automated signup flows can flood a system with disposable-backed accounts. These may be bots testing credential stuffing, scrapers harvesting data, or malicious actors building a base for future abuse. Blocking disposable emails at registration reduces the surface area for these attacks, complementing CAPTCHA, rate limiting, and other anti-abuse measures.
#### The Solution: Real-Time Check at Registration
Integrate Emailyze's REST API into the signup flow. When a user submits an email address, the backend calls GET /v1/check/?email=user@example.com before creating the account. The response includes is_disposable (boolean), risk_score (0–100), and provider_type (disposable, personal, freemail, masked, unknown). Based on these signals, the application can block, flag, or allow the signup.
Block when is_disposable=true — Reject the signup and display a message asking the user to provide a permanent email.
Flag when risk_score >= threshold — Allow the signup but queue for manual review, apply additional verification, or limit account capabilities until the user is verified.
Allow when is_disposable=false and risk_score is low — Proceed with normal account creation.
#### How It Works: Three-Step Flow
1. User submits email — The signup form captures the email address (and other fields). The frontend sends the data to the backend.
2. Backend calls Emailyze — Before creating the account, the backend makes a synchronous request to GET /v1/check/?email={email}. The API responds in under 50ms with is_disposable, risk_score, and provider_type.
3. Backend decides: block or allow — If the email is disposable or exceeds the risk threshold, return an error to the user. Otherwise, create the account and proceed with the normal onboarding flow.
#### Code Example: Signup Validation
cURL (Single Check)
curl -X GET "https://api.emailyze.xyz/v1/check/?email=user@guerrillamail.com" \
-H "Authorization: Bearer YOUR_API_KEY"
Example Response
{
"email": "user@guerrillamail.com",
"is_disposable": true,
"risk_score": 95,
"provider_type": "disposable",
"domain": "guerrillamail.com"
}
Python (Django/Flask-style)
import requests
def validate_email_for_signup(email: str, api_key: str) -> dict:
response = requests.get(
"https://api.emailyze.xyz/v1/check/",
params={"email": email},
headers={"Authorization": f"Bearer {api_key}"},
timeout=2
)
response.raise_for_status()
data = response.json()
return {
"is_disposable": data.get("is_disposable", False),
"risk_score": data.get("risk_score", 0),
"provider_type": data.get("provider_type", "unknown")
}
def signup_view(request):
email = request.POST.get("email")
validation = validate_email_for_signup(email, settings.EMAILYZE_API_KEY)
if validation["is_disposable"]:
return JsonResponse(
{"error": "Please use a permanent email address to sign up."},
status=400
)
if validation["risk_score"] >= 80:
# Optional: flag for review instead of blocking
return JsonResponse(
{"error": "We couldn't verify this email. Please use a different address."},
status=400
)
# Proceed with account creation
user = create_user(email=email, ...)
return JsonResponse({"success": True, "user_id": user.id})
Node.js (Express-style)
const axios = require('axios');
async function validateEmailForSignup(email, apiKey) {
const { data } = await axios.get('https://api.emailyze.xyz/v1/check/', {
params: { email },
headers: { Authorization: `Bearer ${apiKey}` },
timeout: 2000
});
return {
is_disposable: data.is_disposable ?? false,
risk_score: data.risk_score ?? 0,
provider_type: data.provider_type ?? 'unknown'
};
}
app.post('/signup', async (req, res) => {
const { email } = req.body;
const validation = await validateEmailForSignup(email, process.env.EMAILYZE_API_KEY);
if (validation.is_disposable) {
return res.status(400).json({ error: 'Please use a permanent email address to sign up.' });
}
if (validation.risk_score >= 80) {
return res.status(400).json({ error: "We couldn't verify this email. Please use a different address." });
}
const user = await createUser({ email, ...req.body });
return res.json({ success: true, user_id: user.id });
});
#### Signals to Use: is_disposable, risk_score, provider_type
is_disposable (boolean)
The primary signal. When true, the email domain is known to be a disposable/temporary inbox service. Use this for a simple block/allow decision. Most integrations will block when is_disposable=true.
risk_score (0–100)
A composite risk indicator. Higher scores indicate higher likelihood of disposable, abusive, or low-quality addresses. Use for threshold-based policies: e.g., block when risk_score >= 80, flag when risk_score >= 60, allow when risk_score < 60. The score captures edge cases where is_disposable may be false but the address still carries risk (e.g., newly observed domains, freemail with abuse patterns).
provider_type (string)
Categorizes the email provider: disposable, personal, freemail, masked, unknown. Useful for nuanced policies:
risk_score to decide.#### Best Practices: Threshold Tuning and Masked Email Handling
Threshold Tuning
Start conservative: block when is_disposable=true and optionally when risk_score >= 90. Monitor false positives (legitimate users blocked) and false negatives (disposable users allowed). Adjust the threshold based on your tolerance for each. SaaS with high signup volume may prefer a lower threshold (e.g., 70) to catch more disposables; B2B with lower volume may use a higher threshold (e.g., 95) to avoid blocking edge-case corporate domains.
Masked Email Handling
Apple Hide My Email and similar services return provider_type: "masked". These are not disposable—they are privacy-preserving relays. Recommended: allow masked addresses. Blocking them would frustrate privacy-conscious users and reduce conversion. If needed, treat masked as a distinct segment for analytics (e.g., track conversion rates for masked vs. non-masked).
Error Handling
If the Emailyze API is unavailable or times out, decide: fail open (allow signup) or fail closed (block signup). Fail-open preserves conversion when the service is down but allows disposables through. Fail-closed is stricter but may block legitimate users during outages. Many teams use fail-open with logging, then run periodic list hygiene to catch any disposables that slipped through.
#### CTA: Next Steps
GET /v1/check/, POST /v1/check/batch/, and GET /v1/download/.