A valid-looking email address is not always a trustworthy signup.
Basic email validation usually answers only one question:
Does this string look like an email address?
That is useful, but it does not tell us whether the address uses a disposable domain, whether the domain can receive mail, or whether the result is reliable enough to accept automatically.
I wanted a small server-side check that returns an explainable decision instead of a simple true or false.
Why a Boolean Result Is Not Enough
Consider these cases:
- The email syntax is invalid.
- The domain is a known disposable email provider.
- The domain has no MX records.
- The address appears to be a role account such as
admin@orsupport@. - The domain looks like a typo of a common provider.
- A DNS request temporarily fails.
These situations should not all produce the same result.
A temporary DNS failure, for example, should not automatically cause a legitimate customer to be rejected.
For that reason, I use four decisions:
| Decision | Recommended action |
|---|---|
ACCEPT |
Allow the signup to continue |
REVIEW |
Require additional verification |
REJECT |
Block because strong risk evidence was found |
UNKNOWN |
Retry later or use a fallback flow |
The important part is that UNKNOWN remains separate from REJECT.
Signals Used for the Decision
The checker evaluates several signals together:
- Email syntax
- Disposable email domain evidence
- MX mail-routing records
- Free email provider detection
- Role-based local parts
- Common domain typo suggestions
- Confidence and risk level
No single weak signal should decide the entire result.
For example, a role address such as support@example.com may be undesirable for a consumer signup but completely normal for a B2B contact form.
The final policy depends on the application.
Calling the API with Node.js
The following example requires Node.js 18 or later because it uses the built-in fetch function.
Create a file named check-email.mjs:
const email = process.argv[2];
const apiKey = process.env.RAPIDAPI_KEY;
const host =
"riskbeacon-signup-email-domain-intelligence-api.p.rapidapi.com";
if (!email || !apiKey) {
console.error(
"Usage: RAPIDAPI_KEY=your_key node check-email.mjs user@example.com"
);
process.exit(1);
}
const response = await fetch(`https://${host}/email/v1/verify`, {
method: "POST",
headers: {
"content-type": "application/json",
"x-rapidapi-key": apiKey,
"x-rapidapi-host": host
},
body: JSON.stringify({
email,
profile: "SIGNUP_BALANCED"
})
});
const result = await response.json();
if (!response.ok) {
console.error(`Request failed: ${response.status}`, result);
process.exit(1);
}
console.log(JSON.stringify({
decision: result.decision,
confidence: result.confidence,
riskLevel: result.riskLevel,
disposable: result.disposable,
roleAccount: result.roleAccount,
reason: result.reason
}, null, 2));
Set your RapidAPI key and run the script.
macOS or Linux
RAPIDAPI_KEY="YOUR_RAPIDAPI_KEY" \
node check-email.mjs "new.user@gmail.com"
Windows PowerShell
$env:RAPIDAPI_KEY = "YOUR_RAPIDAPI_KEY"
node .\check-email.mjs "new.user@gmail.com"
A simplified result looks like this:
{
"decision": "ACCEPT",
"confidence": 90,
"riskLevel": "LOW",
"disposable": false,
"roleAccount": false,
"reason": "Email passed the selected validation policy"
}
Using the Decision in a Signup Flow
A simple application policy might look like this:
switch (result.decision) {
case "ACCEPT":
// Continue the normal signup flow.
break;
case "REVIEW":
// Require an email OTP, magic link, or CAPTCHA.
break;
case "REJECT":
// Stop the signup and show a neutral error message.
break;
case "UNKNOWN":
// Retry later or use the normal email verification flow.
break;
}
This lets the application add friction only when the available evidence justifies it.
What This Check Does Not Prove
An MX record proves that a domain is configured to receive mail. It does not prove that a specific mailbox exists.
This checker intentionally does not perform SMTP mailbox probing. SMTP probing can be unreliable, may expose user information, and is often blocked or intentionally obscured by mail providers.
The result should therefore be used as a risk signal before signup, not as a replacement for:
- Email ownership verification
- OTP or magic-link confirmation
- Rate limiting
- CAPTCHA
- Device and IP abuse detection
Privacy Considerations
The verification service does not persist submitted email addresses.
Applications should still avoid logging full email addresses unnecessarily. If logging is required, consider masking the local part or storing a one-way hash.
Try the Example
I published the complete Node.js example under the MIT license:
GitHub: Signup Email Risk Checker
The underlying email and domain intelligence API is available here:
Disclosure: I built both the example project and the RiskBeacon API. I would appreciate feedback about the response structure, decision model, and signals that would be most useful in a real signup flow.
Top comments (0)