Every signup form eventually has the same problem: someone types john@gnail.com, hits submit, and three weeks later your welcome email bounces. Multiply that by a few hundred signups a month and your sender reputation starts taking real damage.
The fix is simple — validate the email before it ever hits your database, not after. Here's how to do it in Node.js with a real-time email validation API.
Why validate at signup instead of before sending
Most teams validate their list right before a campaign. That's better than nothing, but it means bad data sits in your database for weeks, syncs into your CRM, and gets used for segmentation and reporting before anyone notices it's garbage.
Catching it at the point of signup is cheaper in every sense:
- One API call instead of a bulk cleanup job later
- The user is still on the page, so they can fix a typo immediately
- Your database never gets polluted in the first place
The basic flow
- User submits the signup form
- Your backend calls the validation API before writing to the database
- If the response flags the address as invalid, disposable, or high-risk, you reject it (or ask the user to double check)
- Otherwise, proceed with signup as normal
Code example
Here's a minimal Node.js example using Gamalogic's email validation API, which returns syntax, MX/DNS, and SMTP checks along with a risk score:
'use strict';
var https = require('https');
function validateEmail(email, apiKey, callback) {
https.get({
host: 'gamalogic.com',
path: `/emailvrf/?emailid=${encodeURIComponent(email)}&apikey=${apiKey}`,
}, function (res) {
var json = '';
res.on('data', function (chunk) {
json += chunk;
});
res.on('end', function () {
callback(null, JSON.parse(json));
});
}).on('error', function (err) {
callback(err);
});
}
// Usage inside your signup route
app.post('/signup', (req, res) => {
const { email } = req.body;
validateEmail(email, process.env.GAMALOGIC_API_KEY, (err, result) => {
if (err) {
// Fail open or closed depending on your risk tolerance
return res.status(500).json({ error: 'Validation service unavailable' });
}
if (!result.valid || result.disposable) {
return res.status(400).json({
error: 'This email address looks invalid or disposable. Please double-check it.'
});
}
// Proceed with normal signup logic
createUser(email).then(() => res.status(200).json({ success: true }));
});
});
What the response actually tells you
A validation response typically includes:
- valid — passes syntax, MX, and DNS checks
- smtp — mailbox actually exists (confirmed via SMTP handshake)
- disposable — flagged as a temp-mail/throwaway domain
- catchall — domain accepts all addresses, so a "valid" result here is less certain
- score — an overall risk score you can use to set your own accept/reject threshold
That last point matters — you don't have to hard-reject every risky signup. Many teams let catch-all or unknown addresses through but flag them internally for a secondary check before a big campaign send.
A few practical tips
- Cache the response for a short window (a few minutes) if your form does client-side validation-as-you-type, so you're not burning credits on every keystroke pause.
- Fail open, not closed, if the validation service times out — don't block signups because a third-party API had a slow moment. Just log it for later re-validation.
-
Don't rely on regex alone. A syntactically perfect email (
name@example.com) can still be a dead mailbox, a disposable domain, or a spam trap. Regex catches typos; it doesn't catch deliverability risk.
Wrapping up
Real-time validation at the signup step is one of the highest-leverage, lowest-effort changes you can make to protect deliverability. It's a single API call, and it stops bad data before it ever becomes your problem.
If you want to try this yourself, Gamalogic Email validation api gives 500 free validation credits with no card required — enough to wire this up and test it against your own form today.
Have you handled this differently — client-side checks, a different provider, your own SMTP verification? Curious how others are solving this. Drop a comment below.
Top comments (0)