Wiki / Documentación interna / Plataforma

Envío de email: SMTP y Resend

Dos proveedores intercambiables en caliente, sin redeploy, más un log completo de cada intento de envío.

El Send Email Hook

Supabase Auth deja de mandar sus propios correos genéricos en cuanto este hook está activo. Cada correo transaccional de autenticación (alta, recuperación, invitación, cambio de email) pasa por nuestro propio webhook, que compone el HTML con la plantilla de la sociedad correspondiente antes de enviarlo de verdad.

Supabase dispara el hook

Firma la petición con AUTH_EMAIL_HOOK_SECRET y la envía a /api/webhooks/auth-email con el tipo de correo y los datos del token.

Verificación de firma

La librería standardwebhooks comprueba la firma contra el mismo secreto. Si no coincide, 401 — y ahora además queda un registro en el log (ver abajo).

Composición

resolverPlantillaCorreo() resuelve la sociedad y su plantilla personalizada (módulo emails).

Página intermedia "Un paso más"

El enlace del correo no apunta directo a Supabase: pasa por /auth/confirmar, para que un escáner de seguridad del proveedor de correo (que visita enlaces automáticamente) no gaste el token de un solo uso antes de que la persona pulse de verdad.

Envío y registro

enviarCorreo() manda por el proveedor activo; registrarEnvioCorreo() deja constancia en email_log, éxito o fallo.

Selector de proveedor: SMTP / Resend

  • Tabla de fila única platform_email_config (id boolean primary key check (id) — patrón que fuerza que solo pueda existir esa fila). Guarda provider, y desde hoy también resend_api_key_cifrado y resend_from_email.
  • Lectura abierta a cualquier authenticated (el valor en sí no es sensible, la barrera es la escritura); escritura solo superadmin.
  • La API key de Resend se cifra igual que un IBAN (src/lib/crypto/campos.ts) — nunca se descifra para mostrarla de vuelta al cliente, solo para usarla al enviar.
  • Pantalla: Estado de servicio → Información del sistema → "Envío de email". Cambio inmediato, sin redeploy.
  • resolverConfigEmailActiva(supabase) es el punto único que resuelve proveedor + credenciales de Resend en una sola consulta, usado por los 6 puntos de envío de correo de la plataforma.

Log de emails enviados

Estado de servicio → Logs → Emails: los últimos 30 envíos, con origen, remitente, destinatario, asunto, cuerpo completo y si tuvo error. Exportable a CSV. Un fallo de verificación de firma del webhook también deja rastro aquí (origen "Auth (firma del webhook inválida)"), sin exponer el token ni la firma.

Entregabilidad: SPF, DKIM, DMARC

Aceptar un envío (código 200 de Resend, o que el SMTP no dé error) no significa que llegue a la bandeja de entrada. Para un dominio nuevo en Resend hacen falta los tres registros DNS:

Registro Quién lo exige Qué aporta
SPF Resend, para verificar el dominio Autoriza qué servidores pueden enviar en nombre del dominio
DKIM (resend._domainkey) Resend, para verificar el dominio Firma criptográfica del mensaje
DMARC (_dmarc) Opcional para Resend, pero Gmail lo valora mucho Indica qué hacer si SPF/DKIM fallan; sin él, un dominio nuevo parte con desventaja de confianza
Solo puede existir un registro _dmarc.<dominio>. Si hay dos, los proveedores de correo lo tratan como si no hubiera ninguno — pasó de verdad el 19/09/2026 al añadir uno nuevo sin borrar el anterior.

Un dominio nuevo, aunque esté bien configurado, puede caer en spam los primeros envíos: Gmail no tiene todavía historial de confianza con él. Marcar como "no es spam" en un envío de prueba ayuda a construir esa reputación para ese remitente concreto.

Incidente completo del 19/09/2026 (secreto del webhook desincronizado, DMARC duplicado, y un bug de doble canje de PKCE que reabría sesión sin pedir contraseña nueva) documentado en Incidencias resueltas.