Email Risk Scoring: How to Automatically Block Bad Signups
Not every bad email is obviously bad — some are valid addresses attached to high-risk patterns. Risk scoring is how you catch the ones that slip past every other filter.
MailSentry·Email Validation API

TL;DR
- •Risk scoring replaces binary valid/invalid with a nuanced 0–100 signal
- •Use tiered decisions: accept, review, challenge, or reject based on thresholds
- •Combine email risk with IP reputation and device fingerprinting for best results
0 – 30
30 – 60
60 – 80
80 – 100
Binary email validation — valid or invalid — leaves a lot of nuance on the table. An address can be technically valid yet still represent a high risk to your platform. It might belong to a serial free-trial abuser, sit on a domain associated with fraud, or exhibit a pattern that strongly correlates with fake signups. Quality scoring fills this gap by assigning a numerical confidence score that reflects how trustworthy an address is.
What Is a Quality Score?
A quality score is a composite value between 0 and 100, where 100 means "fully verified, no issues" and 0 means "almost certainly invalid." MailSentry starts every address at 100 and applies weighted deductions for each issue it finds — bad MX records, disposable domain, gibberish local part, failed SMTP, and so on. The final score is what remains after all deductions.
Think of it as a credit score for email addresses. No single factor is dispositive, but the weighted combination of many factors produces a reliable signal.
Signals That Feed Into Quality Scoring
A robust quality-scoring model draws on a variety of inputs:
- Domain age — Newly registered domains (less than 30 days) are disproportionately associated with spam and fraud.
- Domain type — Free providers (Gmail, Yahoo) carry moderate risk. Corporate domains carry lower risk. Disposable providers carry very high risk.
- Disposable email detection — If the domain is a known disposable provider, the quality score drops sharply.
- Role-based prefix — Addresses like
info@andadmin@are flagged because they rarely represent individual users. - MX record health — Missing, misconfigured, or suspicious MX records lower the score.
- SMTP verification result — Mailbox does not exist, or the server is a catch-all? That is a signal.
- Pattern analysis — Randomly generated local parts (
xkq93mdf@) or local parts that match known bot patterns contribute to the score. - Historical abuse data — Has this domain or address appeared in spam traps, blacklists, or previous fraud incidents?
- DNS configuration — Does the domain have SPF, DKIM, and DMARC records? Legitimate sending domains almost always do.
How to Use Quality Scores in Your Application
The most effective pattern is a tiered decision framework with configurable thresholds:
type SignupDecision = "accept" | "review" | "challenge" | "reject";
function evaluateSignup(score: number): SignupDecision {
if (score >= 80) return "accept"; // high quality — proceed
if (score >= 60) return "review"; // moderate — flag for manual review
if (score >= 30) return "challenge"; // low quality — require CAPTCHA or phone verification
return "reject"; // very low — block signup
}
This gives you granularity that a binary valid/invalid check cannot provide. A score of 65 might represent a free email provider with a role-based prefix — not definitively bad, but worth a second look. A score of 10 almost certainly indicates a disposable address on a freshly registered domain with no legitimate DNS infrastructure.
Implementing Score-Based Signup Flow
Here is a more complete example showing how to integrate risk scoring into a registration endpoint:
// app/api/signup/route.ts
import { NextResponse } from "next/server";
export async function POST(request: Request) {
const { email, password, name } = await request.json();
// Validate email via MailSentry
const validation = await fetch(
"https://api.mailsentry.dev/v1/verify",
{
method: "POST",
headers: {
Authorization: `Bearer ${process.env.MAILSENTRY_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ email }),
}
).then((r) => r.json());
// Hard reject: invalid email
if (validation.verdict === "invalid") {
return NextResponse.json(
{ error: "Please provide a valid email address." },
{ status: 422 }
);
}
const { score } = validation;
// Tier 1: High quality — create account immediately
if (score >= 80) {
const user = await createUser({ email, password, name, tier: "trusted" });
await sendWelcomeEmail(user);
return NextResponse.json({ success: true, user_id: user.id });
}
// Tier 2: Moderate quality — create account but require email verification
if (score >= 60) {
const user = await createUser({ email, password, name, tier: "unverified" });
await sendVerificationEmail(user);
return NextResponse.json({
success: true,
user_id: user.id,
requires_verification: true,
});
}
// Tier 3: Low quality — require additional verification
if (score >= 30) {
return NextResponse.json({
success: false,
challenge_required: true,
challenge_type: "captcha", // or "phone_verification"
});
}
// Tier 4: Very low quality — reject
return NextResponse.json(
{ error: "Unable to create an account with this email address." },
{ status: 422 }
);
}
Tuning Your Thresholds
The right thresholds depend on your product's risk tolerance:
- Consumer apps with free tiers tend to be more aggressive (lower reject thresholds) because free-trial abuse is expensive.
- B2B SaaS can afford to be more permissive because the signup volume is lower and manual review is feasible.
- E-commerce should be strict for account creation but permissive for guest checkout, where the downside of a bad email is limited to a lost order confirmation.
Start with conservative thresholds and adjust based on data. Log every signup decision — the email, the quality score, and the outcome — so you can review false positives and false negatives and refine your cutoffs over time.
Combining Quality Scores with Other Signals
Email quality scoring is most powerful when combined with other fraud signals:
function computeCompositeScore(signals: {
emailScore: number; // MailSentry score (0-100, 100 = safe)
ipReputationScore: number; // 0-100, 100 = clean
deviceFingerprintScore: number;
velocityPenalty: number; // 0-100, 0 = normal, 100 = suspicious
}): number {
return (
signals.emailScore * 0.4 +
signals.ipReputationScore * 0.25 +
signals.deviceFingerprintScore * 0.2 +
(100 - signals.velocityPenalty) * 0.15
);
}
Weighting the email quality score at 40 percent reflects its high signal value, but blending it with IP reputation, device fingerprinting, and velocity checks produces a more robust fraud detection system than any single signal alone.
Key Takeaways
Quality scoring replaces binary validation with a nuanced, actionable signal that lets you automate signup decisions at scale. Feed it into a tiered decision framework — accept, review, challenge, reject — and tune your thresholds based on your product's risk profile. Combine it with other fraud signals for defense in depth, and log everything so you can iterate. The result is a signup flow that blocks the vast majority of bad actors while minimizing friction for legitimate users.