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). Guardaprovider, y desde hoy tambiénresend_api_key_cifradoyresend_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 |
_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.