Check signup emails in Express
This guide adds a Signitize check to an Express signup route as a small middleware. It needs Node.js 18 or later (built-in fetch).
1. Add your key
.env
SIGNITIZE_API_KEY=sk_live_...
Get a free key if you don't have one.
2. The middleware
middleware/check-email.js
async function callSignitize(email) {
try {
const response = await fetch('https://api.signitize.io/v1/check', {
method: 'POST',
headers: {
Authorization: `Bearer ${process.env.SIGNITIZE_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({ email }),
signal: AbortSignal.timeout(5000),
})
if (response.ok) return { status: 'checked', ...(await response.json()) }
if (response.status === 400) return { status: 'invalid' }
if ([401, 422, 429].includes(response.status)) console.warn('Signitize answered', response.status)
} catch {
// timeout or network error
}
return { status: 'unavailable' }
}
export async function checkEmail(req, res, next) {
const check = await callSignitize(String(req.body.email ?? '').trim())
if (check.status === 'invalid') return res.status(422).json({ error: 'Enter a valid email address.' })
if (check.status === 'checked' && check.disposable) {
return res.status(422).json({ error: 'Please use a permanent email address.' })
}
if (check.status === 'checked' && !check.deliverable) {
return res.status(422).json({ error: 'This email address cannot receive mail. Please check it for typos.' })
}
req.emailCheck = check
next()
}
3. The route
routes/signup.js
import express from 'express'
import { checkEmail } from '../middleware/check-email.js'
import { users } from '../db.js'
const router = express.Router()
router.post('/signup', express.json(), checkEmail, async (req, res) => {
const typed = req.body.email.trim()
const check = req.emailCheck
if (check.status === 'checked') {
if (await users.findByCanonicalEmail(check.email)) {
return res.status(409).json({ error: 'You already have an account.' })
}
await users.create({ email: typed, emailCanonical: check.email, emailCheck: 'passed' })
} else {
await users.create({ email: typed, emailCanonical: null, emailCheck: 'pending' })
}
await sendVerificationEmail(typed)
res.status(201).json({ ok: true })
})
export default router
Store emailCanonical in a unique, nullable column, and send mail to the typed address.
With the npm client
The signitize package replaces callSignitize above. Its safeCheck() never throws and returns checked, invalid or unavailable:
npm install signitize
middleware/check-email.js
import { Signitize } from 'signitize'
const signitize = new Signitize() // reads SIGNITIZE_API_KEY
export async function checkEmail(req, res, next) {
const outcome = await signitize.safeCheck(String(req.body.email ?? '').trim())
if (outcome.status === 'invalid') return res.status(422).json({ error: 'Enter a valid email address.' })
if (outcome.status === 'checked' && outcome.result.disposable) {
return res.status(422).json({ error: 'Please use a permanent email address.' })
}
if (outcome.status === 'checked' && !outcome.result.deliverable) {
return res.status(422).json({ error: 'This email address cannot receive mail. Please check it for typos.' })
}
req.emailCheck = outcome.status === 'checked' ? { status: 'checked', ...outcome.result } : { status: 'unavailable' }
next()
}
The route in step 3 stays the same. A runnable version is in the Express example.
4. Recheck pending users
Users created while Signitize was unavailable are pending. Run the recheck job from Never block a signup every few minutes and grant free credits only to passed users.