Beta privadaMailbeam está en beta privada: la API pública todavía no está abierta.Únete a la lista de espera

Mailbeam
Node.js + ExpressIniciación15 minutosActualizado en enero de 2025

Verificación de email en Node.js

En este tutorial añadirás verificación de email en tiempo real a una aplicación Node.js con Express. Al terminar, los emails desechables, los buzones inexistentes y las direcciones con erratas se rechazarán en el endpoint de registro antes de crear ningún usuario.

Qué vas a construir

Un middleware de Express reutilizable que:

  • Verifica una dirección de email con la API de Mailbeam
  • Devuelve un 422 con un código de error legible por máquina cuando falla
  • Falla en abierto ante errores de la API (para que una caída de Mailbeam no rompa tu registro)
  • Opcionalmente cachea los resultados para no verificar dos veces lo mismo

Requisitos previos

  • Node.js 18 o posterior
  • Un proyecto con npm, pnpm o yarn
  • Una cuenta de Mailbeam y una clave de API (regístrate gratis)

Paso 1 — Añade un cliente pequeño

No hay ningún SDK que instalar. Mailbeam es un único endpoint HTTP, así que con una docena de líneas en tu propio código lo cubres, y no hay nada que mantener actualizado. Los SDK oficiales están en la hoja de ruta; esto es lo que hay que hacer hoy.

// 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();
}

Paso 2 — Configura tu clave de API

Añade tu clave a .env o a .env.local:

MAILBEAM_KEY=mb_live_xxxxxxxxxxxxxxxxxxxx

Paso 3 — Crea el middleware de verificación

Crea middleware/verifyEmail.js:

import { verifyEmail } from "../lib/mailbeam.js";

/**
 * Middleware de Express que verifica el email de req.body.email.
 * Llama a next() si va bien, devuelve 422 si falla.
 * Falla en abierto ante errores de la API de Mailbeam: no bloquees a los
 * usuarios si la API está caída.
 */
export async function verifyEmail(req, res, next) {
  const { email } = req.body;

  if (!email) {
    return res.status(400).json({ error: "El campo email es obligatorio." });
  }

  try {
    const { valid, score, reason } = await verifyEmail(email);

    if (!valid || score < 60) {
      return res.status(422).json({
        error: "Escribe una dirección de email válida.",
        code: reason ?? "invalid_email",
      });
    }

    // Adjunta el resultado a la petición para que lo usen los handlers de después
    req.emailVerification = { valid, score, reason };
    next();
  } catch (err) {
    // Registra el error pero no bloquees: una caída de Mailbeam no debería
    // romper tu registro
    console.error("[Mailbeam] error de verificación:", err.message);
    next();
  }
}

Paso 4 — Añádelo a tu ruta de registro

// 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: "No se ha podido crear la cuenta." });
  }
});

export default router;

Y la configuración de tu app de 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("Servidor en marcha en http://localhost:3000");
});

Probar la integración

Arranca tu servidor y prueba con cURL:

# Email válido — debería devolver 201
curl -X POST http://localhost:3000/api/auth/signup \
  -H "Content-Type: application/json" \
  -d '{"email": "valid@example.com", "password": "secretpass"}'

# Email desechable — debería devolver 422
curl -X POST http://localhost:3000/api/auth/signup \
  -H "Content-Type: application/json" \
  -d '{"email": "throwaway@mailinator.com", "password": "secretpass"}'

Usa los dominios de prueba de Mailbeam en tu pipeline de CI para no consumir cuota:

# Siempre devuelve válido (score 99)
curl ... -d '{"email": "user@valid.mailbeam-test.dev", ...}'

# Siempre devuelve inválido
curl ... -d '{"email": "user@invalid.mailbeam-test.dev", ...}'

Añadir una capa de caché (opcional)

En registros con mucho tráfico, cachea los resultados de verificación para evitar llamadas redundantes:

import { LRUCache } from "lru-cache";

const cache = new LRUCache({
  max: 500,
  ttl: 1000 * 60 * 60, // 1 hora
});

export async function verifyEmail(req, res, next) {
  const { email } = req.body;
  if (!email) return res.status(400).json({ error: "El campo email es obligatorio." });

  const normalised = email.toLowerCase().trim();
  const cached = cache.get(normalised);

  if (cached) {
    if (!cached.valid || cached.score < 60) {
      return res.status(422).json({
        error: "Escribe una dirección de email válida.",
        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: "Escribe una dirección de email válida.",
        code: result.reason ?? "invalid_email",
      });
    }
    next();
  } catch (err) {
    console.error("[Mailbeam] error de verificación:", err.message);
    next();
  }
}

Buenas prácticas

PrácticaPor qué
Fallar en abierto ante errores de la APIUna caída de Mailbeam no debería impedir los registros
Cachear los resultados (TTL de 1 h)Evita verificar dos veces la misma dirección
Pasar a minúsculas y recortar antes de verificarEvita fallos de caché por diferencias triviales
Usar dominios de prueba en CINo consumas cuota de producción en los tests automáticos
Registrar errores, no emailsEvita escribir datos personales en los logs de producción

Checklist de producción

  • MAILBEAM_KEY definida como secreto de la plataforma (no en el código)
  • Registro de errores configurado (sin escribir la dirección de email)
  • Capa de caché añadida en las rutas con mucho tráfico
  • Dominios de prueba usados en el pipeline de CI
  • Umbral de puntuación decidido y documentado (por defecto: 60)
  • El frontend muestra un mensaje de error claro cuando llega un 422

Siguientes pasos