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

Mailbeam
Firebase + Cloud FunctionsIntermedio25 minutosActualizado en enero de 2025

Verificación de email con Firebase

Firebase Authentication permite interceptar los eventos de registro con funciones bloqueantes beforeCreate. Este tutorial añade la verificación de Mailbeam a ese hook para que los emails inválidos y desechables se bloqueen antes de crear el registro de usuario en Firebase.

Requisitos previos

  • Un proyecto de Firebase con plan Blaze (necesario para Cloud Functions)
  • La CLI de Firebase instalada
  • Una clave de API de Mailbeam (regístrate gratis)

Preparación

firebase init functions
cd functions
npm install axios

Define la clave de Mailbeam como variable de entorno de Firebase:

firebase functions:config:set mailbeam.key="mb_live_xxxxxxxxxxxxxxxxxxxx"

Crea la función bloqueante

// functions/index.js
const functions = require("firebase-functions");
const { getAuth } = require("firebase-admin/auth");
const axios = require("axios");

// beforeCreate se ejecuta ANTES de escribir el usuario en Firebase Auth
exports.validateEmailBeforeCreate = functions.auth
  .user()
  .beforeCreate(async (user, context) => {
    const email = user.email;
    if (!email) return; // Sin email: otros proveedores, sáltalo

    const apiKey = functions.config().mailbeam.key;

    try {
      const { data } = await axios.post(
        "https://api.mailbeam.dev/v1/verify",
        { email },
        {
          headers: { Authorization: `Bearer ${apiKey}` },
          timeout: 5000,
        }
      );

      const { valid, score, reason } = data;

      if (!valid || score < 60) {
        const message =
          reason === "disposable_domain"
            ? "Usa una dirección de email permanente, no una temporal."
            : "Escribe una dirección de email válida y alcanzable.";

        throw new functions.auth.HttpsError("invalid-argument", message);
      }
    } catch (err) {
      // Si ya es nuestro HttpsError, relánzalo
      if (err.code === "functions/invalid-argument") throw err;
      // Si no: registra el error y falla en abierto
      functions.logger.error("Ha fallado la verificación de Mailbeam", { error: err.message });
    }
  });

Versión en TypeScript

// functions/src/index.ts
import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
import axios from "axios";

admin.initializeApp();

export const validateEmailBeforeCreate = functions.auth
  .user()
  .beforeCreate(async (user) => {
    if (!user.email) return;

    const apiKey = functions.config().mailbeam.key;

    try {
      const { data } = await axios.post<{
        valid: boolean;
        score: number;
        reason: string | null;
      }>(
        "https://api.mailbeam.dev/v1/verify",
        { email: user.email },
        { headers: { Authorization: `Bearer ${apiKey}` }, timeout: 5000 }
      );

      if (!data.valid || data.score < 60) {
        throw new functions.auth.HttpsError(
          "invalid-argument",
          data.reason === "disposable_domain"
            ? "Usa una dirección de email permanente."
            : "Usa una dirección de email válida y alcanzable."
        );
      }
    } catch (err: unknown) {
      if ((err as { code?: string }).code === "functions/invalid-argument") throw err;
      functions.logger.error("Error de Mailbeam", err);
    }
  });

Despliegue

firebase deploy --only functions

Pruebas

// Usa la Emulator Suite de Firebase para probar en local
firebase emulators:start

// Intenta crear un usuario con un email desechable desde el SDK de Firebase
const { createUserWithEmailAndPassword } = require("firebase/auth");

try {
  await createUserWithEmailAndPassword(auth, "temp@mailinator.com", "password");
} catch (error) {
  console.log(error.code);    // "auth/invalid-argument"
  console.log(error.message); // "Usa una dirección de email permanente."
}

Buenas prácticas

  • Usa beforeCreate, no onCreate: beforeCreate se ejecuta antes de guardar el registro y onCreate después
  • Relanza siempre functions.auth.HttpsError y falla en abierto ante cualquier otro error
  • Usa functions.logger.error, no console.error, para tener logs estructurados en Firebase

Siguientes pasos