Un sistema de emails de prueba parece una pieza pequeña de un SaaS, hasta que una prueba falla y nadie sabe si el problema está en el formulario, la cola o el buzón. La solución no es solamente generar más direcciones: es definir un contrato sencillo que todos los componentes puedan entender.
Por qué un email de prueba necesita un contrato
En un proyecto nuevo solemos escribir una prueba así: crear usuario, esperar un correo y hacer clic en el enlace. Funciona durante unos días. Luego llegan las pruebas en paralelo, los reintentos y los mensajes tardíos. El resultado son tests inestables y un equipo que repite el mismo diagnóstico cada mañana.
Un contrato de email describe qué se envía, a quién, cuándo puede leerse y cómo se identifica. No es una especificación enorme. Es un acuerdo pequeño entre la aplicación, el proveedor de correo de pruebas y la suite de CI.
También ayuda a separar el correo de producción de los datos temporales. Para una prueba local puede ser suficiente una dirección de correo desechable, pero la regla importante es que la dirección tenga un dueño y una vida útil clara.
Los cuatro estados mínimos
Para empezar, modela el flujo con cuatro estados:
- Creado: la prueba reservó un buzón y guardó su identificador.
- Esperando: la aplicación pidió el correo, pero todavía no ha llegado.
- Recibido: existe un mensaje que coincide con el asunto, el destinatario y el intento.
- Consumido o expirado: la prueba terminó, o el buzón ya no debe aceptar lecturas.
El estado recibido no debería significar simplemente “hay un email”. Debe incluir un correlation_id, el tipo de mensaje y la hora de recepción. Con esos datos, un fallo deja una pista útil en vez de un “timeout” genérico.
Diseña el contrato paso a paso
Un contrato práctico puede ser un objeto JSON parecido a este:
{
"test_id": "signup-4821",
"recipient": "signup-4821@example.test",
"message_type": "email_verification",
"correlation_id": "run-2026-09-23-4821",
"expires_at": "2026-09-23T15:00:00Z",
"status": "waiting"
}
Primero genera test_id y correlation_id antes de abrir el formulario. Segundo, pasa esos valores a la aplicación o inclúyelos en el contexto que el sistema de email pueda devolver. Tercero, busca por varios campos: destinatario exacto, tipo de mensaje y correlación. Buscar solo por el asunto es una invitación a leer el mensaje equivocado.
Finalmente, define un timeout y un error útil. “No llegó el email” es poco accionable. “No llegó email_verification para signup-4821 después de 45 segundos; último evento: queued” permite revisar la cola, el worker o el proveedor correcto.
Aislamiento y trazabilidad en el backend
Cada ejecución paralela necesita un buzón, alias o namespace que no pueda confundirse con otro. Un contador global no basta: dos workers pueden solicitarlo al mismo tiempo. Usa un identificador aleatorio corto y conserva el vínculo entre ejecución, usuario de prueba y mensaje.
Guarda en los artefactos de CI solo lo necesario: estado, identificadores, timestamps y un resumen del mensaje. No copies tokens de recuperación ni el contenido completo si no es imprescindible. Esta decisión de privacidad es parte del diseño de Backend, no una tarea para después.
Cuando una prueba falle, registra una secuencia de eventos: created, queued, delivered, read y expired. Puedes complementar el flujo con alertas de cambios con contexto real y con correos útiles para alertas nocturnas, sobre todo si tu CI comparte infraestructura con servicios de operación.
Una nota curiosa: al buscar documentación o reportar un incidente alguien puede escribir “fake e mail com” o “temp mailid”. No son nombres de campos válidos, pero conviene reconocerlos en la búsqueda interna para encontrar el contexto sin meterlos en el código.
Errores comunes que parecen pequeños
- Reutilizar buzones: un mensaje viejo puede hacer que la prueba pase por accidente.
- Esperar sin límite: un bucle infinito bloquea workers y oculta la causa real.
- No fijar el tipo de mensaje: un correo de bienvenida puede confundirse con el de verificación.
- Borrar los artefactos demasiado pronto: después nadie puede reconstruir el fallo.
- Mezclar producción y pruebas: es un riesgo de privacidad y también una fuente de datos contaminados.
- Confiar solo en el asunto: cambios de idioma o plantillas pueden romper el selector.
En SaaS, la tentación es añadir reintentos hasta que el test pase. Los reintentos ayudan con fallos transitorios, pero no corrigen un contrato incompleto. Mantén pocos intentos, registra cada uno y deja que el error final explique que ocurrió.
Checklist de cierre
Antes de dar por terminado el flujo, comprueba:
- Cada prueba crea un identificador único.
- El contrato define destinatario, tipo, correlación, expiración y estado.
- La lectura filtra por más de un campo.
- Los tests paralelos no comparten datos.
- El timeout devuelve el último evento conocido.
- Los artefactos no contienen secretos ni tokens reutilizables.
- La limpieza ocurre después de guardar el resumen del resultado.
La idea central es simple: un email de prueba no es un detalle de la UI, sino una dependencia del backend con estados y límites. Cuando lo tratas como un contrato, las pruebas de tu SaaS se vuelven más repetibles, los fallos son más fáciles de investigar y el equipo pierde menos tiempo adivinando.
Top comments (0)