Verifica delle email in Node.js
In questo tutorial aggiungerai la verifica delle email in tempo reale a un'applicazione Node.js con Express. Alla fine, le email usa e getta, le caselle inesistenti e gli indirizzi con refusi verranno rifiutati nell'endpoint di registrazione prima che venga creato qualsiasi utente.
Che cosa costruirai
Un middleware di Express riutilizzabile che:
- Verifica un indirizzo email con l'API di Mailbeam
- Restituisce un 422 con un codice di errore leggibile dalla macchina quando fallisce
- Lascia passare in caso di errore dell'API (così un guasto di Mailbeam non rompe la tua registrazione)
- Se vuoi, mette in cache i risultati per non verificare due volte la stessa cosa
Prerequisiti
- Node.js 18 o successivo
- Un progetto con npm, pnpm o yarn
- Un account Mailbeam e una chiave API (iscriviti gratis)
Passo 1 — Aggiungi un piccolo client
Non c'è nessun SDK da installare. Mailbeam è un unico endpoint HTTP, quindi una dozzina di righe nel tuo codice lo copre, e non c'è niente da tenere aggiornato. Gli SDK ufficiali sono nella roadmap; questo è quello che si fa oggi.
// lib/mailbeam.js
const ENDPOINT = "https://api.mailbeam.dev/v1/verify";
export async function verifyEmail(email, { timeoutMs = 3000 } = {}) {
const response = await fetch(ENDPOINT, {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.MAILBEAM_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({ email }),
signal: AbortSignal.timeout(timeoutMs),
});
if (!response.ok) {
const { error, message } = await response.json();
throw Object.assign(new Error(message), { code: error });
}
return response.json();
}Passo 2 — Configura la tua chiave API
Aggiungi la tua chiave a .env o a .env.local:
MAILBEAM_KEY=mb_live_xxxxxxxxxxxxxxxxxxxxPasso 3 — Crea il middleware di verifica
Crea middleware/verifyEmail.js:
import { verifyEmail } from "../lib/mailbeam.js";
/**
* Middleware di Express che verifica l'email in req.body.email.
* Chiama next() se va bene, restituisce 422 se fallisce.
* In caso di errore dell'API di Mailbeam lascia passare: non bloccare gli
* utenti se l'API non risponde.
*/
export async function verifyEmail(req, res, next) {
const { email } = req.body;
if (!email) {
return res.status(400).json({ error: "Il campo email è obbligatorio." });
}
try {
const { valid, score, reason } = await verifyEmail(email);
if (!valid || score < 60) {
return res.status(422).json({
error: "Inserisci un indirizzo email valido.",
code: reason ?? "invalid_email",
});
}
// Allega il risultato alla richiesta perché lo usino i gestori successivi
req.emailVerification = { valid, score, reason };
next();
} catch (err) {
// Registra l'errore ma non bloccare: un guasto di Mailbeam non deve
// rompere la tua registrazione
console.error("[Mailbeam] errore di verifica:", err.message);
next();
}
}Passo 4 — Aggiungilo alla tua rotta di registrazione
// routes/auth.js
import express from "express";
import { verifyEmail } from "../middleware/verifyEmail.js";
const router = express.Router();
router.post("/signup", verifyEmail, async (req, res) => {
const { email, password } = req.body;
try {
const user = await db.createUser({ email, password });
res.status(201).json({ user });
} catch (err) {
res.status(500).json({ error: "Non è stato possibile creare l'account." });
}
});
export default router;E la configurazione della tua app Express:
// app.js
import express from "express";
import authRoutes from "./routes/auth.js";
const app = express();
app.use(express.json());
app.use("/api/auth", authRoutes);
app.listen(3000, () => {
console.log("Server attivo su http://localhost:3000");
});Provare l'integrazione
Avvia il tuo server e prova con cURL:
# Email valida — dovrebbe restituire 201
curl -X POST http://localhost:3000/api/auth/signup \
-H "Content-Type: application/json" \
-d '{"email": "valid@example.com", "password": "secretpass"}'
# Email usa e getta — dovrebbe restituire 422
curl -X POST http://localhost:3000/api/auth/signup \
-H "Content-Type: application/json" \
-d '{"email": "throwaway@mailinator.com", "password": "secretpass"}'Usa i domini di prova di Mailbeam nella tua catena di CI per non consumare quota:
# Restituisce sempre valido (punteggio 99)
curl ... -d '{"email": "user@valid.mailbeam-test.dev", ...}'
# Restituisce sempre non valido
curl ... -d '{"email": "user@invalid.mailbeam-test.dev", ...}'Aggiungere uno strato di cache (facoltativo)
Nelle registrazioni con molto traffico, metti in cache i risultati di verifica per evitare chiamate ridondanti:
import { LRUCache } from "lru-cache";
const cache = new LRUCache({
max: 500,
ttl: 1000 * 60 * 60, // 1 ora
});
export async function verifyEmail(req, res, next) {
const { email } = req.body;
if (!email) return res.status(400).json({ error: "Il campo email è obbligatorio." });
const normalised = email.toLowerCase().trim();
const cached = cache.get(normalised);
if (cached) {
if (!cached.valid || cached.score < 60) {
return res.status(422).json({
error: "Inserisci un indirizzo email valido.",
code: cached.reason ?? "invalid_email",
});
}
return next();
}
try {
const result = await verifyEmail(normalised);
cache.set(normalised, result);
if (!result.valid || result.score < 60) {
return res.status(422).json({
error: "Inserisci un indirizzo email valido.",
code: result.reason ?? "invalid_email",
});
}
next();
} catch (err) {
console.error("[Mailbeam] errore di verifica:", err.message);
next();
}
}Buone pratiche
| Pratica | Perché |
|---|---|
| Lasciar passare davanti agli errori dell'API | Un guasto di Mailbeam non deve impedire le registrazioni |
| Mettere in cache i risultati (TTL di 1 h) | Evita di verificare due volte lo stesso indirizzo |
| Portare in minuscolo e ripulire prima di verificare | Evita mancati riscontri in cache per differenze banali |
| Usare i domini di prova in CI | Non consumare quota di produzione nei test automatici |
| Registrare gli errori, non le email | Evita di scrivere dati personali nei registri di produzione |
Lista di controllo per la produzione
-
MAILBEAM_KEYdefinita come segreto della piattaforma (non nel codice) - Registrazione degli errori configurata (senza scrivere l'indirizzo email)
- Strato di cache aggiunto sulle rotte con molto traffico
- Domini di prova usati nella catena di CI
- Soglia di punteggio decisa e documentata (predefinita: 60)
- Il frontend mostra un messaggio di errore chiaro quando arriva un 422