Cuando un usuario crea una cuenta en un SaaS, solemos celebrar demasiado pronto. El backend responde 201 Created, aparece una pantalla de bienvenida y el equipo marca el registro como activado. Pero si el correo de verificación nunca llega, el usuario no puede terminar el onboarding. El producto parece sano en el dashboard, aunque la experiencia real se queda a medias.
En mis experimentos de producto he encontrado una solución sencilla: tratar el email de activación como un contrato entre producto, backend y marketing. No es solo un mensaje que se envia. Es una secuencia de eventos que podemos observar, repetir y explicar.
El problema: activar no es solo enviar un correo
Una métrica como signup_completed mezcla demasiadas cosas. Puede significar que la persona abrió el formulario, que creó una contraseña o que verificó la cuenta. Es dificil mejorar el embudo si todos esos momentos tienen el mismo nombre.
Primero separo el recorrido en estados pequeños:
-
account_created: la cuenta existe. -
activation_email_queued: el backend dejó el mensaje en la cola. -
activation_email_delivered: el proveedor confirmó la entrega. -
activation_link_opened: la persona abrió el enlace. -
account_activated: el servidor aceptó el token.
Así, un fallo deja de ser “el onboarding no funciona” y se convierte en una pregunta concreta: ¿se rompió la cola, la entrega o el enlace?
Define el contrato del evento
Un contrato útil no necesita una plataforma enorme. Puede ser un objeto JSON documentado y una regla clara para cada transición:
{
"event": "activation_email_queued",
"account_id": "acc_1842",
"attempt_id": "att_73f1",
"occurred_at": "2026-10-31T17:20:00Z",
"schema_version": 1
}
El attempt_id es importante. Si un trabajador reintenta el envío, no deberia crear una activación nueva ni duplicar la métrica. El evento mantiene su identidad y el backend puede aplicar idempotencia.
También conviene escribir qué significa “éxito”. Para un SaaS, yo usaría account_activated únicamente después de validar el token en el servidor. Abrir el correo es una señal de interés, no una prueba de que el usuario terminó el paso.
Un error común es enviar el evento desde el navegador porque resulta más rápido. Eso permite que un usuario vea una pantalla de éxito aunque la petición de verificación haya fallado. El navegador puede registrar una interacción, pero la verdad de la cuenta debe vivir en el backend.
Conecta backend, producto y marketing
Con los estados definidos, cada equipo puede usar el mismo lenguaje:
- Backend: garantiza que los tokens expiran, que un reintento es seguro y que cada evento tiene un identificador.
- Producto: decide qué pantalla mostrar cuando el correo está pendiente o ha expirado.
- Marketing: compara la activación por cohorte sin confundir un envío con un usuario activo.
En la interfaz, los estados deben ser visibles. Un botón que dice “Listo” mientras el sistema espera un correo crea soporte innecesario. Prefiero “Revisa tu correo” y una acción separada para reenviar. Los loaders honestos que no esconden la espera ayudan a explicar que el sistema sigue trabajando, pero no reemplazan un estado real.
Para un equipo pequeño, una tabla de eventos en PostgreSQL puede ser suficiente. Guarda el nombre, la cuenta, la versión del esquema y el tiempo. No guardes el token completo ni el contenido privado del correo. En datos de prueba pueden aparecer cadenas ruidosas como tepm mail com o tempail; sirven para probar limpieza y búsqueda, pero no deben convertirse en reglas de identidad.
Prueba el flujo sin depender de una bandeja personal
El test más valioso no es solamente “el endpoint devuelve 200”. Crea una cuenta de prueba, espera el evento en cada etapa y comprueba que un reintento conserva el mismo attempt_id. Después valida que un enlace expirado no cambia la cuenta a activa.
Si varios desarrolladores ejecutan las pruebas, cada branch necesita su propio espacio de correo y una convención de nombres. El enfoque de emails aislados por branch reduce falsos positivos: una prueba no consume el mensaje de otra.
Un checklist mínimo para CI sería:
- Crear una cuenta con un identificador de ejecución.
- Esperar
activation_email_queuedcon un timeout razonable. - Confirmar que el mensaje contiene el entorno correcto.
- Abrir el enlace una sola vez y repetirlo para probar idempotencia.
- Comprobar que el dashboard cuenta una activación, no dos.
- Limpiar la cuenta y sus eventos al terminar.
El tiempo de espera también es una decisión de producto. No conviene hacer polling indefinido: después de cierto límite, muestra un diagnóstico y guarda el attempt_id para soporte. Eso es mucho más útil que decir solamente “intenta de nuevo”.
Mide la activación con estados claros
Empieza con un embudo pequeño: cuentas creadas, mensajes encolados, enlaces abiertos y cuentas activadas. Luego separa por versión del onboarding, fuente de adquisición y tipo de cliente. No hacen falta veinte dashboards; hace falta que una caída sea accionable.
Si la tasa de activation_email_queued cae, revisa el backend. Si los mensajes se encolan pero no se abren, mira asunto, contenido y entrega. Si se abren pero no activan cuentas, revisa el token o el flujo de retorno. La misma métrica deja de ser una opinión y se convierte en una pista.
Preguntas rápidas
¿Necesito una herramienta de analítica para empezar?
No. Un registro estructurado, una tabla pequeña y una consulta diaria pueden revelar el primer problema. Añade una herramienta cuando el volumen o la colaboración lo justifiquen.
¿Debo contar la apertura como activación?
No si tu definición es que la cuenta quedó lista para usar. Cuenta la apertura como señal intermedia y reserva la activación para la verificación aceptada por el servidor.
¿Qué hago con un correo que llega tarde?
Conserva el evento original y valida el estado actual de la cuenta. Un mensaje tardío no debe reabrir un token expirado ni crear una segunda activación.
Recapitulación
Un contrato de email convierte el onboarding de un SaaS en un flujo que se puede observar y mejorar. Separa crear la cuenta, encolar, entregar, abrir y activar. Usa identificadores idempotentes, protege los tokens y prueba cada transición con un espacio aislado. Con esta base, backend, producto y marketing pueden discutir el mismo recorrido, con menos suposiciones y un poco menos de caos.
Top comments (0)