Saltar al contenido principal

MailHog vs Mailpit: Prueba de correos de verificación y restablecimiento de contraseña con Casdoor

· 10 min de lectura
Yang Luo
Casdoor Maintainer

MailHog y Mailpit son ambos servidores SMTP falsos para desarrollo: aceptan cada mensaje, lo almacenan y lo muestran en una interfaz web en lugar de entregarlo. Ambos usan los mismos puertos predeterminados, SMTP en 1025 y la interfaz web y API en 8025, por lo que la dirección SMTP es smtp://127.0.0.1:1025 y la bandeja de entrada está en http://127.0.0.1:8025 para cualquiera de ellos. La diferencia es el mantenimiento: el último lanzamiento de MailHog, v1.0.1, salió en agosto de 2020, mientras que Mailpit lanzó v1.33.0 el 31 de octubre de 2026. Para un nuevo proyecto, use Mailpit. Casdoor envía a ambos a través de un proveedor SMTP estándar, por lo que puede probar códigos de registro, correos de restablecimiento de contraseña y enlaces mágicos sin una cuenta de correo real.

MailHog vs Mailpit de un vistazo​

MailHogMailpit
Último lanzamientov1.0.1, 2020-08-11v1.33.0, 2026-10-31
Último commit en la rama predeterminada2022-08-022026-10-31
LicenciaMITMIT
Puerto SMTP predeterminado10251025
Puerto predeterminado de la interfaz web y API80258025
Imagen Dockermailhog/mailhog, solo amd64axllent/mailpit, amd64, arm64 y 386
API HTTPv1 y v2: listar, obtener, eliminar, buscar por from, to o containingv1: listar, obtener, eliminar, buscar con filtros como to: y subject:, atajo para mensaje latest
Almacenamiento predeterminadoEn memoriaBase de datos SQLite temporal, eliminada al salir
Almacenamiento persistenteMongoDB o MaildirArchivo SQLite (MP_DATABASE) o rqlite
Límite de mensajesNo documentadoMantiene los 500 más recientes por defecto (MP_MAX_MESSAGES)
Comprobación HTML, comprobación de enlaces, comprobación de spamNoSí
Webhook en nuevo correoNoSí (MP_WEBHOOK_URL)
SMTP TLSNo ofrecidoSTARTTLS u SSL/TLS opcionales
Inyección de fallosJimChaos
Liberar un mensaje a un servidor SMTP realSíSí
Servidor POP3NoSí, opcional
Autenticación básica para la interfaz webSíSí

Las estadísticas de Docker Hub muestran que muchas personas siguen descargando MailHog. Esto refleja tutoriales antiguos y archivos de CI, no actividad actual: una issue abierta en el repositorio de MailHog titulada "THIS PROJECT IS DEAD!" tiene una respuesta de 2023 del autor diciendo que ya no tiene tiempo para mantenerlo. El README de Mailpit se describe a sí mismo como inspirado en MailHog y apunta a ese mismo comentario.

La arquitectura de la imagen importa más de lo que parece. En un portátil Apple Silicon o un ejecutor de CI ARM, mailhog/mailhog se ejecuta solo bajo emulación, mientras que axllent/mailpit tiene una imagen nativa arm64.

Ejecutar cualquiera de ellos con Docker​

MailHog:

docker run -d --name mailhog -p 1025:1025 -p 8025:8025 mailhog/mailhog

Mailpit:

docker run -d --name mailpit -p 1025:1025 -p 8025:8025 axllent/mailpit

Mailpit mantiene los correos en una base de datos temporal que desaparece cuando se detiene el contenedor. Para conservarla entre reinicios, monte un volumen y configure MP_DATABASE:

docker run -d --name mailpit \
-v "$PWD/mailpit-data:/data" \
-e MP_DATABASE=/data/mailpit.db \
-p 1025:1025 -p 8025:8025 \
axllent/mailpit

Sin Docker, tanto brew install mailhog como brew install mailpit funcionan en macOS, y Mailpit ofrece binarios estáticos para Windows, Linux y macOS en su página de lanzamientos.

En GitHub Actions, ejecútelo como un contenedor de servicio junto a su trabajo de prueba:

services:
mailpit:
image: axllent/mailpit
ports:
- 1025:1025
- 8025:8025

Apuntar Casdoor a MailHog o Mailpit​

Casdoor no tiene un tipo de proveedor separado para MailHog o Mailpit, y no lo necesita. El tipo de correo electrónico Default envía a través de SMTP, y ambas herramientas son servidores SMTP.

  1. Como administrador global, agregue un proveedor en la organización admin o built-in.
  2. Establece Category en Email y Type en Default.
  3. Establezca Host en la ubicación donde se ejecuta la herramienta y Port en 1025.
  4. Deje Username y Password vacíos.
  5. Haga clic en Test SMTP Connection, luego en Send Testing Email, y revise la interfaz web en el puerto 8025.

Las páginas paso a paso con capturas de pantalla son Test email with MailHog y Test email with Mailpit.

Algunos detalles deciden si esto funciona a la primera:

Deje el modo SSL en Auto o configúrelo en Disable. En Auto, Casdoor usa TLS implícito solo en el puerto 465 y actualiza con STARTTLS solo si el servidor lo ofrece. Ni MailHog ni un Mailpit predeterminado ofrecen STARTTLS en el puerto 1025, por lo que la conexión permanece sin cifrar. No elija Enable: eso fuerza TLS implícito, y el handshake falla contra un servidor de texto plano. La tabla de modos SSL tiene el comportamiento completo.

Deje las credenciales vacías. Casdoor inicia sesión en el servidor SMTP solo cuando se establece Username. Si lo rellena, la autenticación PLAIN de Go se niega a enviar la contraseña sobre una conexión no cifrada a menos que el host sea localhost, por lo que un MailHog en 192.168.x.x fallará con un error de autenticación aunque MailHog aceptaría cualquier inicio de sesión. Mailpit, por defecto, no solicita autenticación en absoluto.

Use el host correcto. 127.0.0.1 funciona solo cuando Casdoor y el receptor de correo se ejecutan en la misma máquina. Si ambos se ejecutan en Docker Compose, use el nombre del servicio, como mailpit, como host.

Use un proveedor global. Un proveedor propiedad de una organización ordinaria solo puede acceder a direcciones de Internet, por lo que no puede conectarse a 127.0.0.1 o una IP privada. Los proveedores en admin o built-in no están restringidos. Consulte Qué direcciones puede alcanzar un proveedor.

Configure origin para los enlaces. Los códigos de verificación funcionan inmediatamente. Los enlaces de restablecimiento de contraseña y los enlaces mágicos necesitan que Casdoor conozca su URL pública, mediante origin en conf/app.conf o una solicitud en un host de bucle invertido (loopback). De lo contrario, el enlace de restablecimiento se elimina del correo y los enlaces mágicos fallan. Consulte Plantillas.

Finalmente, agregue el proveedor a su aplicación en Add providers to an application para que el registro y el restablecimiento de contraseña lo usen realmente.

Leer el código de verificación en una prueba automatizada​

Los códigos de verificación de Casdoor tienen seis dígitos, y la plantilla predeterminada dice "Here is your code: " seguido del código. Una prueba de extremo a extremo registra un usuario, pide a Casdoor que envíe el código y luego lo lee desde la API del receptor de correo.

Con Mailpit, busque por destinatario y abra la coincidencia más reciente. GET /api/v1/search devuelve las coincidencias ordenadas de la más nueva a la más antigua, y GET /api/v1/message/{ID} devuelve los cuerpos Text y HTML analizados:

import { request } from "@playwright/test";

const MAILPIT = process.env.MAILPIT_URL ?? "http://127.0.0.1:8025";

export async function latestCode(to: string): Promise<string> {
const api = await request.newContext({ baseURL: MAILPIT });
for (let i = 0; i < 20; i++) {
const res = await api.get("/api/v1/search", {
params: { query: `to:"${to}"`, limit: "1" },
});
const { messages } = await res.json();
if (messages.length > 0) {
const msg = await (await api.get(`/api/v1/message/${messages[0].ID}`)).json();
const match = (msg.Text || msg.HTML).match(/code: (\d{6})/);
if (match) return match[1];
}
await new Promise((r) => setTimeout(r, 500));
}
throw new Error(`no verification email for ${to}`);
}

Si solo una prueba envía un correo a la vez, GET /api/v1/message/latest omite el paso de búsqueda. Antes de cada prueba, DELETE /api/v1/messages sin cuerpo limpia la bandeja de entrada.

Con MailHog, la llamada más cercana es GET /api/v2/search?kind=to&query=<address>. Los mensajes se devuelven en orden cronológico inverso (del más reciente al más antiguo) en items, y el cuerpo está en items[0].Content.Body:

const res = await api.get("/api/v2/search", {
params: { kind: "to", query: to, limit: "1" },
});
const { items } = await res.json();
const body: string = items[0]?.Content.Body ?? "";

Content.Body es el cuerpo MIME sin procesar. Casdoor envía en formato quoted-printable, por lo que = se convierte en =3D y las líneas largas tienen saltos suaves que terminan en =. Descodifíquelo primero o mantenga el código cerca del inicio de una plantilla corta. Limpie MailHog con DELETE /api/v1/messages.

Migración de MailHog a Mailpit​

Debido a que los puertos coinciden, la mayoría de las migraciones requieren un cambio de una sola línea en docker-compose.yml: reemplace mailhog/mailhog por axllent/mailpit. El proveedor de Casdoor mantiene el mismo host y puerto. Lo que cambia es:

  • Configuración. MailHog lee variables MH_*; Mailpit lee MP_*. Si usaba MH_STORAGE=maildir o MongoDB, pase a MP_DATABASE.
  • Helpers de prueba. Mailpit no tiene endpoints /api/v2. Reescriba las llamadas a /api/v2/messages y /api/v2/search para usar /api/v1/messages y /api/v1/search, y lea messages[].ID junto con Text o HTML en lugar de items[].Content.Body. La decodificación quoted-printable desaparece.
  • Sintaxis de búsqueda. kind=to&query=a@example.com se convierte en query=to:"a@example.com".
  • Inyección de fallos. Jim no tiene banderas en Mailpit; use Chaos.
  • Autenticación. Si una aplicación insiste en iniciar sesión sobre SMTP sin cifrar, inicie Mailpit con MP_SMTP_AUTH_ACCEPT_ANY=1 y MP_SMTP_AUTH_ALLOW_INSECURE=1. Para Casdoor, es más simple dejar las credenciales vacías.
  • Retención. Mailpit elimina por defecto los mensajes más antiguos hasta conservar los 500 más recientes. Aumente MP_MAX_MESSAGES si una ejecución de pruebas larga necesita más.

Pasando a producción​

MailHog y Mailpit nunca entregan correos a bandejas de entrada reales a menos que libere los mensajes manualmente, por lo que la producción necesita un proveedor real. En Casdoor cambia el proveedor, no las plantillas. Las plantillas de correo electrónico, el marcador de posición de código %s y el bloque <reset-link> permanecen iguales:

Una configuración común mantiene Mailpit en desarrollo y CI, y el proveedor real en producción. Cada entorno apunta su aplicación a un proveedor diferente, por lo que el flujo de registro que prueba es el que se publica.

Referencias​