MailHog vs Mailpit: Prueba de correos de verificación y restablecimiento de contraseña con Casdoor
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
| MailHog | Mailpit | |
|---|---|---|
| Último lanzamiento | v1.0.1, 2020-08-11 | v1.33.0, 2026-10-31 |
| Último commit en la rama predeterminada | 2022-08-02 | 2026-10-31 |
| Licencia | MIT | MIT |
| Puerto SMTP predeterminado | 1025 | 1025 |
| Puerto predeterminado de la interfaz web y API | 8025 | 8025 |
| Imagen Docker | mailhog/mailhog, solo amd64 | axllent/mailpit, amd64, arm64 y 386 |
| API HTTP | v1 y v2: listar, obtener, eliminar, buscar por from, to o containing | v1: listar, obtener, eliminar, buscar con filtros como to: y subject:, atajo para mensaje latest |
| Almacenamiento predeterminado | En memoria | Base de datos SQLite temporal, eliminada al salir |
| Almacenamiento persistente | MongoDB o Maildir | Archivo SQLite (MP_DATABASE) o rqlite |
| Límite de mensajes | No documentado | Mantiene los 500 más recientes por defecto (MP_MAX_MESSAGES) |
| Comprobación HTML, comprobación de enlaces, comprobación de spam | No | Sí |
| Webhook en nuevo correo | No | Sí (MP_WEBHOOK_URL) |
| SMTP TLS | No ofrecido | STARTTLS u SSL/TLS opcionales |
| Inyección de fallos | Jim | Chaos |
| Liberar un mensaje a un servidor SMTP real | Sí | Sí |
| Servidor POP3 | No | Sí, opcional |
| Autenticación básica para la interfaz web | Sí | 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.
- Como administrador global, agregue un proveedor en la organización
adminobuilt-in. - Establece Category en
Emaily Type enDefault. - Establezca Host en la ubicación donde se ejecuta la herramienta y Port en
1025. - Deje Username y Password vacíos.
- 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 leeMP_*. Si usabaMH_STORAGE=maildiro MongoDB, pase aMP_DATABASE. - Helpers de prueba. Mailpit no tiene endpoints
/api/v2. Reescriba las llamadas a/api/v2/messagesy/api/v2/searchpara usar/api/v1/messagesy/api/v1/search, y leamessages[].IDjunto conTextoHTMLen lugar deitems[].Content.Body. La decodificación quoted-printable desaparece. - Sintaxis de búsqueda.
kind=to&query=a@example.comse convierte enquery=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=1yMP_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_MESSAGESsi 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:
- Cualquier servidor SMTP con el tipo
Default, descrito en Proveedores de email - SendGrid y Resend a través de sus APIs
- Brevo a través de su relay SMTP
- Azure Communication Services
- Su propio endpoint HTTP con Custom HTTP Email
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
- Repositorio y README de MailHog: https://github.com/mailhog/MailHog
- Documentación de configuración y API v1/v2 de MailHog: https://github.com/mailhog/MailHog/tree/master/docs
- Comentario de mantenimiento de MailHog: https://github.com/mailhog/MailHog/issues/442#issuecomment-1493415258
- Repositorio y README de Mailpit: https://github.com/axllent/mailpit
- Documentación de Mailpit (Docker, almacenamiento, SMTP, webhook, filtros de búsqueda): https://mailpit.axllent.org/docs/
- Referencia de la API v1 de Mailpit: https://mailpit.axllent.org/docs/api-v1/
- Código del proveedor de email de Casdoor: https://github.com/casdoor/casdoor/tree/master/email