Correo: Resend y DNS
Webhooks de Resend, SPF, DKIM, DMARC, MTA-STS y TLS-RPT.
En esta página
BloomX usa Resend para enviar y recibir. No habla IMAP/SMTP: el correo entrante llega por webhook y el saliente sale por la API de Resend. La guía completa y ampliada también está en DNS_SETUP.md del repositorio.
Configurar Resend#
- En Resend añade el dominio con el que enviarás (por ejemplo
mail.tu-dominio.com) y publica exactamente los registros que te indique (SPF/verificación, DKIM, y MX si recibirás correo). No cambies nombres, prioridades ni valores. - Espera a que Resend marque el dominio como verificado antes de enviar tráfico real.
- Crea una clave de API y guárdala en
RESEND_API_KEYdel frontend. - Define
TOP_DOMAINcon ese dominio: BloomX genera correos del sistema comonoreply@<TOP_DOMAIN>. - Crea los dos webhooks descritos abajo.
Un buzón por dominio
Publicar los MX de Resend en el dominio raíz reemplaza cualquier otro proveedor de correo entrante (Google Workspace, Microsoft 365). Si ya recibes correo en ese dominio, usa un subdominio dedicado (por ejemplo mail.tu-dominio.com) y ajusta TOP_DOMAIN. Mantén un solo conjunto de MX por dominio o subdominio.
Webhooks de Resend#
| Webhook | Eventos | Variable de firma (opcional) |
|---|---|---|
https://<tu-host>/api/webhooks/resend | email.received (correo entrante) y estados de entrega (email.sent, email.delivered, email.bounced, email.complained, email.delivery_delayed) | WEBHOOK_SECRET (whsec_…) |
https://<tu-host>/api/webhooks/resend-events | Rebotes y quejas: email.bounced, email.complained, email.delivery_delayed | RESEND_WEBHOOK_SECRET (whsec_…) |
- Los secretos son opcionales y los decide cada organizador. Con
WEBHOOK_SECRETse exige una firma Svix válida en/api/webhooks/resend(400 si no); sin él, la petición se acepta sin firma y solo se escribe un aviso en el log. Lo mismo paraRESEND_WEBHOOK_SECRETenresend-events. Cada webhook de Resend tiene su propio secreto: copia el de cada uno en su variable. Recomendado en producción: sin firma, cualquiera que conozca la URL podría inyectar correos o bajas. - Sin el segundo webhook, los rebotes permanentes y las quejas no alimentan la lista de supresión de Elixir.
- La URL debe ser pública y https. Si el webhook responde 500, Resend reintenta (por diseño en
resend-events). - Al recibir un correo BloomX: lo guarda (idempotente), resuelve To/Cc/Bcc, etiqueta por alias/regex y reglas, puntúa spam con
Authentication-Results, procesa adjuntos en segundo plano y dispara el hookEMAIL_RECEIVEDsi tu dominio está en modo firmado.
DNS: SPF, DKIM y DMARC#
# Ejemplos de forma (usa SIEMPRE los valores exactos que te muestre Resend)
TXT @ v=spf1 include:<lo-que-indique-resend> ~all # un solo SPF por dominio
CNAME <selector> <valor-DKIM-de-resend> # DKIM: tal cual, sin editar
TXT _dmarc v=DMARC1; p=none; rua=mailto:dmarc@tu-dominio.com; adkim=r; aspf=r; pct=100
MX <host> <prioridad> <destino-MX-de-resend> # solo si recibes correo con Resend- SPF: un único registro por dominio. Si usas otros proveedores, combínalos dentro del mismo SPF. Máximo 10 consultas DNS (
include,a,mx,redirect); si pasas, haypermerrory DMARC falla. Usa-all(o~allmientras pruebas), nunca+all. - DKIM: obligatorio. Publica todos los registros que entregue Resend, sin editar el selector ni convertir
CNAMEenTXT. Claves de 2048 bits y rotación del selector cada 6–12 meses. - DMARC: empieza con
p=noney alineación relajada (adkim=r; aspf=r). No uses alineación estricta al inicio: Resend enruta con un subdominio (return-path) y conaspf=sel SPF no alinea. Tras 2–4 semanas de reportesruasube ap=quarantine; pct=25, luegopct=100y por últimop=reject(consp=rejectpara subdominios que no envían). - Los reportes DMARC (
rua) llegan a un buzón real. Si tu dominio apunta a BloomX, llegan como.zip/.gzal usuariodmarc, que debe existir. - Envía con un
From:del mismo dominio autenticado. Evita mandar desdegmail.comu otros dominios ajenos.
MTA-STS y TLS-RPT#
Para exigir TLS a quienes te envían correo (BloomX recibe a través de Resend, que negocia TLS de forma oportunista):
TXT _mta-sts v=STSv1; id=20260101000000
TXT _smtp._tls v=TLSRPTv1; rua=mailto:tlsrpt@tu-dominio.com
# https://mta-sts.tu-dominio.com/.well-known/mta-sts.txt (certificado válido, sin redirecciones)
version: STSv1
mode: testing
mx: <host MX exacto que te da Resend>
max_age: 86400- BloomX no sirve el archivo de política ni ninguna ruta MTA-STS/TLS-RPT: debes alojar
mta-sts.tu-dominio.comtú (un host estático). La única ruta/.well-knownde BloomX esbloomx-backend-key.json(clave de firma del backend) y no tiene relación. - Empieza con
mode: testing; cuando los reportes no muestren fallos pasa aenforcey subemax_age(604800 o más). Cada vez que cambies la política, cambia el `id`. - Si no puedes alojar la política, omite MTA-STS (un
idpublicado sin política accesible causa fallos de entrega). TLS-RPT sí puede publicarse siempre.
Otros registros recomendados#
- DNSSEC en el dominio, para proteger SPF/DKIM/DMARC/MTA-STS de respuestas DNS falsas.
- CAA para limitar las autoridades que pueden emitir certificados (
CAA 0 issue "letsencrypt.org"). - BIMI (opcional): requiere DMARC con
p=quarantineop=reject. ARC solo si reenvías o alojas listas: BloomX no firma ARC. - Esto son recomendaciones de DNS genéricas; el código de BloomX no las comprueba.
Verificar antes de escalar#
- Envía a Gmail, Outlook y una cuenta corporativa y confirma
SPF=PASS,DKIM=PASSyDMARC=PASS(BloomX muestra una insignia con el veredicto de la cabeceraAuthentication-Results, si Resend la incluye). - Usa Mail-Tester, MXToolbox o Google Postmaster Tools.
- Calienta el dominio: sube el volumen de forma gradual durante 2–4 semanas.
- Para envíos masivos: Gmail y Yahoo exigen SPF/DKIM/DMARC alineados, quejas < 0,3 % y baja de un clic. Los envíos de Elixir incluyen
List-UnsubscribeyList-Unsubscribe-Post(RFC 8058) siNEXT_PUBLIC_APP_URLes https público y hay secreto (UNSUBSCRIBE_SECREToNEXTAUTH_SECRET).