Correo no se envía desde WordPress/App: configuración de relé SMTP que realmente entrega

¿Te fue útil?

Tu sitio WordPress dice “Mensaje enviado.” Tu app registra “Correo en cola.” Los clientes aseguran que no recibieron nada.
Marketing te escribe cada 30 minutos. Revisas carpetas de spam. Nada. Reenvías. Sigue sin llegar.

Este es el peor tipo de fallo: silencioso, dañino para la reputación y lo bastante verosímil como para que todos supongan que “probablemente está bien.”
Hagamos que no esté bien. Hagamos que sea aburrido. Lo aburrido es bueno en la entrega de correo.

Qué falla realmente cuando los correos de WordPress/app “no se envían”

Cuando alguien dice “el correo no se envía”, normalmente se refiere a una de cuatro fallas distintas:

1) La app nunca entrega el correo a algo real

Problema clásico de WordPress/PHP: mail() devuelve éxito porque entregó el contenido a una interfaz MTA local,
no porque el mensaje saliera del edificio. Si no hay un MTA local, o está mal configurado, obtienes la ilusión de éxito.
Por eso “funciona en mi portátil” no es una estrategia de correo.

2) El mensaje sale del host pero muere en el siguiente salto

Causas comunes: el proveedor de hosting bloquea el puerto 25; el SMTP saliente está denegado por un firewall; o tu MTA intenta entregar directamente
y sufre limitación de tasa, greylisting o es rechazado con un código de política. El correo puede quedarse en cola durante horas y luego rebotar,
o puede ser aceptado y filtrado después. Lo que conduce a…

3) El destinatario lo acepta y luego los filtros de spam lo ocultan

Este es el fallo “entregado pero no visto”. También es el más políticamente incómodo: tu sistema dice “enviado”,
el servidor receptor dice “aceptado” y el usuario dice “nope”. Las tres pueden ser verdad.
Falta de alineación SPF/DKIM/DMARC, mala reputación, rDNS roto y dominios “From” que no controlas son los principales culpables.

4) Estás enviando tráfico legítimo que parece ilegítimo

El correo transaccional (restablecimientos de contraseña, recibos, formularios de contacto) tiene un patrón: picos durante eventos, plantillas idénticas,
asuntos similares y enlaces. Eso puede parecer spam si no te autenticas o si la IP de tu relé es “nueva” en el mundo.
La entregabilidad no es moralidad. Es coincidencia de patrones más reputación.

La solución no es “probar otro plugin”. La solución es establecer una ruta de relé SMTP adecuada con autenticación,
identidad consistente, alineación DNS y registros que puedas solicitar desde tus propios sistemas.

Hechos interesantes y breve historia (para entender los fallos actuales)

  • SMTP es anterior a la web. Se estandarizó a principios de los 80 y aún asume una red mayormente confiada.
  • El puerto 25 solía ser “la tubería de correo de Internet.” Ahora con frecuencia se bloquea para servidores de clientes porque equipos comprometidos envían spam.
  • SPF nació para “detener remitentes de sobres falsificados.” Verifica quién puede enviar correo por un dominio vía DNS, pero cubre solo una capa de identidad.
  • DKIM se diseñó para sobrevivir reenvíos. Firma el contenido del mensaje para que los receptores puedan verificar que no fue alterado en tránsito (o por un gateway “servicial”).
  • DMARC es política y alineación, no magia. Indica a los receptores qué hacer cuando SPF/DKIM fallan y requiere que los identificadores coincidan con el “From” visible.
  • El greylisting está hecho para molestar intencionalmente. Algunos servidores rechazan temporalmente los primeros intentos para ver si reintentas como un MTA real. Las apps que “disparan y olvidan” pierden.
  • “Aceptado” no es lo mismo que “en la bandeja de entrada.” La aceptación SMTP significa “nos hicimos responsables”, no “lo mostramos prominentemente a un humano”.
  • El Reverse DNS sigue siendo una comprobación de credibilidad. Muchos receptores desconfían mucho de IPs sin rDNS o con rDNS no coincidente porque eso es común en botnets.
  • Los grandes proveedores ejecutan aprendizaje automático sobre los flujos de correo. Tu mensaje se juzga por reputación de dominio, reputación de IP, engagement y características del contenido.

Guía de diagnóstico rápido (primeras/segundas/terceras comprobaciones)

Cuando el correo “no se envía”, la rapidez importa. Quieres identificar el cuello de botella en minutos, no después de una reunión.
Aquí está el orden de triaje que uso en producción.

Primero: determina si el correo sale del host de la app

  1. Envía un único correo de prueba con un asunto único.
  2. Revisa los registros locales o la cola (Postfix/Exim) en el host. Si no hay cola ni registros, la app nunca lo entregó.
  3. Confirma que no dependes de PHP mail() sin un MTA detrás.

Segundo: determina si el siguiente salto SMTP es alcanzable y acepta

  1. Prueba la conectividad saliente a tu relé en el puerto 587 (y 465 si es necesario). No asumas que el puerto 25 funciona.
  2. Intenta una sesión SMTP autenticada. Si la autenticación falla, no tienes “problemas de entregabilidad”, tienes “problemas de inicio de sesión”.
  3. Busca rechazos inmediatos con códigos SMTP claros (5xx) frente a aplazamientos (4xx).

Tercero: determina si el mensaje es rechazado más tarde (política, reputación, autenticación)

  1. Inspecciona las cabeceras de un mensaje que llegue a algún sitio (incluso a un buzón de prueba) para ver resultados SPF/DKIM/DMARC.
  2. Confirma la alineación del dominio From y que no estés enviando como un dominio que no controlas.
  3. Revisa si los rebotes van a algún lugar que nunca monitoreas (clásico: dirección de rebote VERP apunta a la nada).

El objetivo de esta guía es clasificar la falla en: entrega desde la app, red/autenticación, o política de entregabilidad.
Cada categoría tiene una solución diferente. Mezclarlas hace perder días.

La arquitectura que realmente entrega (y por qué)

El patrón fiable es simple: tu app hace submission SMTP a un relé; el relé maneja la entrega.
El relé está autenticado, registra, limita tasa y está alineado con la identidad de tu dominio.

Lo que deberías hacer (opinión)

  • Usar submission SMTP (587) con autenticación desde WordPress/app hacia un relé.
  • Enviar desde un dominio que controles y configurar correctamente los registros DNS (SPF/DKIM/DMARC).
  • Centralizar el envío de correo para poder aplicar políticas y ver registros en un solo lugar.
  • Separar flujos transaccionales y de marketing si los volúmenes difieren; reputaciones distintas, modos de fallo distintos.
  • Preferir un relé SMTP gestionado salvo que tengas una razón para operar la reputación saliente tú mismo.

Lo que deberías evitar

  • Entrega directa a MX desde servidores web aleatorios. Funciona hasta que no, y entonces tú te haces cargo de la reputación, límites y listas de bloqueo.
  • Usar “From: tuMarca.com” pero en realidad enviar vía “otraCosa.com”. Eso rompe la alineación y la confianza.
  • Esparcir plugins/configuraciones SMTP distintas entre servidores. Terminarás con 12 variantes sutilmente rotas.

Una broma, como recompensa: La entregabilidad de correo es como las citas—si apareces con un nombre falso y sin referencias, nadie llamará.

Elegir un relé SMTP: qué importa y qué es ruido

Puedes ejecutar tu propio relé (Postfix), usar el relé de tu proveedor cloud, o comprar un servicio transaccional especializado.
La “mejor” respuesta depende de cumplimiento, volumen y si disfrutas depurar puntuaciones de reputación como hobby.

Qué importa

  • Opciones de autenticación: SMTP AUTH sobre TLS, idealmente credenciales por aplicación.
  • Soporte DKIM: que el relé firme o que tú firmes; pero debe ser consistente.
  • Manejo de rebotes: necesitas visibilidad. Al menos, un buzón para rebotes; mejor, registros de eventos.
  • Controles de tasa: tanto para proteger tu reputación como para prevenir inundaciones accidentales por un bucle roto.
  • Gestión de reputación IP/dominio: quién la posee y cuán rápido se recupera tras un incidente.
  • Acceso a registros: necesitas resultados de entrega con IDs de mensaje. “Lo enviamos” no es evidencia.

Qué es en su mayoría ruido

  • Promesas de envío “ilimitado” sin un plan de reputación.
  • Paneles bonitos si no puedes exportar o correlacionar IDs de mensaje.
  • “Integración WordPress con un clic” que oculta la identidad SMTP real y rompe la alineación.

Tareas prácticas (comandos, salida esperada y decisiones)

Estas tareas asumen un servidor Linux ejecutando Postfix como MTA local o relé, además de un host WordPress/app que envía correo.
Incluso si usas un relé gestionado, muchas de estas comprobaciones aplican (red, TLS, DNS y rastreo de mensajes).

Task 1 — Confirmar que Postfix está instalado y en ejecución

cr0x@server:~$ systemctl status postfix
● postfix.service - Postfix Mail Transport Agent
     Loaded: loaded (/lib/systemd/system/postfix.service; enabled)
     Active: active (running) since Mon 2026-01-04 08:11:02 UTC; 2h 13min ago
       Docs: man:postfix(1)
   Main PID: 1327 (master)
      Tasks: 3 (limit: 4567)
     Memory: 12.3M
     CGroup: /system.slice/postfix.service
             ├─1327 /usr/lib/postfix/sbin/master -w
             ├─1331 qmgr -l -t unix -u
             └─1332 tlsmgr -l -t unix -u

Qué significa: Si no está active (running), tu “relé SMTP” es imaginario.
Decisión: Si está inactivo, arráncalo y revisa la configuración antes de tocar WordPress.

Task 2 — Comprobar si hay algo atascado en la cola de correo

cr0x@server:~$ postqueue -p
-Queue ID-  --Size-- ----Arrival Time---- -Sender/Recipient-------
A1B2C3D4E5     3120 Mon Jan  4 09:22:14  no-reply@example.com
                                         user@gmail.com
                                         (connect to gmail-smtp-in.l.google.com[142.250.102.27]:25: Connection timed out)

Qué significa: Postfix aceptó el correo pero no puede alcanzar el MX remoto (timeout). Es red o egreso por puerto 25.
Decisión: Si ves timeouts, deja de intentar direct-to-MX y usa relay via submission (587) a un proveedor.

Task 3 — Inspeccionar los registros recientes para rechazos/aplazamientos

cr0x@server:~$ sudo tail -n 50 /var/log/mail.log
Jan  4 10:05:12 server postfix/smtp[24518]: A1B2C3D4E5: to=<user@gmail.com>, relay=gmail-smtp-in.l.google.com[142.250.102.27]:25, delay=67, delays=0.1/0.02/67/0, dsn=4.4.1, status=deferred (connect to gmail-smtp-in.l.google.com[142.250.102.27]:25: Connection timed out)
Jan  4 10:05:45 server postfix/smtpd[24544]: warning: unknown[203.0.113.50]: SASL LOGIN authentication failed: authentication failure
Jan  4 10:05:45 server postfix/smtpd[24544]: disconnect from unknown[203.0.113.50] ehlo=1 auth=0/1 rset=1 quit=1 commands=3/4

Qué significa: Tienes dos problemas distintos: timeouts de entrega saliente (direct-to-MX) y fallos de autenticación entrantes (clientes mal configurados o maliciosos).
Decisión: Restringe la submission y arregla tu ruta de relé para no entregar en puerto 25 desde nodos web aleatorios.

Task 4 — Verificar conectividad saliente hacia tu relé (puerto 587)

cr0x@server:~$ nc -vz smtp.relay.local 587
Connection to smtp.relay.local 587 port [tcp/submission] succeeded!

Qué significa: La ruta de red existe. Si falla, el firewall/grupo de seguridad/DNS es el culpable.
Decisión: Arregla el enrutamiento/firewall antes de cambiar la configuración de la app.

Task 5 — Probar handshake TLS y detalles del certificado

cr0x@server:~$ openssl s_client -starttls smtp -connect smtp.relay.local:587 -servername smtp.relay.local -brief
CONNECTION ESTABLISHED
Protocol version: TLSv1.3
Ciphersuite: TLS_AES_256_GCM_SHA384
Peer certificate: CN = smtp.relay.local
Verification: OK

Qué significa: TLS funciona y el certificado valida. Si la verificación falla, muchos clientes rechazaran enviar.
Decisión: Arregla los certificados (o el trust store) en lugar de “desactivar la verificación” en la app.

Task 6 — Intentar una sesión SMTP autenticada (manual, señal rápida)

cr0x@server:~$ swaks --to user@example.net --from no-reply@example.com --server smtp.relay.local --port 587 --auth LOGIN --auth-user app-smtp --auth-password 'REDACTED' --tls
=== Trying smtp.relay.local:587...
=== Connected to smtp.relay.local.
=== TLS started with cipher TLS_AES_256_GCM_SHA384
<=  220 smtp.relay.local ESMTP Postfix
=>  EHLO server
<=  250-smtp.relay.local
<=  250-AUTH PLAIN LOGIN
<=  250 STARTTLS
=>  AUTH LOGIN
<=  235 2.7.0 Authentication successful
=>  MAIL FROM:<no-reply@example.com>
<=  250 2.1.0 Ok
=>  RCPT TO:<user@example.net>
<=  250 2.1.5 Ok
=>  DATA
<=  354 End data with <CR><LF>.<CR><LF>
=>  .
<=  250 2.0.0 Ok: queued as 9F8E7D6C5B
=== Message sent.

Qué significa: Puedes enviar mediante submission con éxito. El ID de cola es rastreable en los registros del relé.
Decisión: Si esto funciona pero WordPress no, el plugin/config de tu app está mal, no la red.

Task 7 — Rastrear un ID de mensaje en los registros (deja de adivinar)

cr0x@server:~$ sudo grep '9F8E7D6C5B' /var/log/mail.log
Jan  4 11:14:22 server postfix/cleanup[27102]: 9F8E7D6C5B: message-id=<20260104111422.9F8E7D6C5B@smtp.relay.local>
Jan  4 11:14:22 server postfix/qmgr[1331]: 9F8E7D6C5B: from=<no-reply@example.com>, size=1023, nrcpt=1 (queue active)
Jan  4 11:14:23 server postfix/smtp[27105]: 9F8E7D6C5B: to=<user@example.net>, relay=mx.example.net[198.51.100.20]:25, delay=1.1, delays=0.1/0.02/0.4/0.6, dsn=2.0.0, status=sent (250 2.0.0 OK)

Qué significa: Entrega de extremo a extremo al MX del destinatario exitosa.
Decisión: Si los usuarios aún no lo ven, estás en territorio de “filtrado por spam o reglas de buzón”—pasa al análisis de cabeceras y comprobaciones de autenticación.

Task 8 — Confirmar que el hostname y FQDN del servidor son razonables

cr0x@server:~$ hostnamectl
 Static hostname: smtp.relay.local
       Icon name: computer-vm
         Chassis: vm
      Machine ID: 2b3f4c5d6e7f8a9b
         Boot ID: 0a1b2c3d4e5f6a7b
  Operating System: Ubuntu 22.04.4 LTS
            Kernel: Linux 5.15.0-91-generic
      Architecture: x86-64

Qué significa: Un hostname consistente ayuda a evitar desajustes extraños en HELO/EHLO.
Decisión: Si tu hostname es localhost o cambia, arréglalo y actualiza myhostname en Postfix.

Task 9 — Comprobar DNS para SPF (e interpretar el resultado)

cr0x@server:~$ dig +short TXT example.com
"v=spf1 include:_spf.relayvendor.net -all"

Qué significa: SPF está presente y es estricto (-all). Bien—si es correcto.
Decisión: Si en realidad no envías a través de _spf.relayvendor.net, corrige SPF o tu correo fallará las comprobaciones SPF.

Task 10 — Buscar publicación de clave DKIM (selector)

cr0x@server:~$ dig +short TXT s1._domainkey.example.com
"v=DKIM1; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A..."

Qué significa: La clave pública DKIM existe para el selector s1.
Decisión: Si falta, la firma DKIM puede estar ocurriendo pero no validará; publica la clave correcta o configura el relé para firmar.

Task 11 — Comprobar política DMARC y direcciones de reporte

cr0x@server:~$ dig +short TXT _dmarc.example.com
"v=DMARC1; p=quarantine; rua=mailto:dmarc-reports@example.com; ruf=mailto:dmarc-forensics@example.com; adkim=s; aspf=s"

Qué significa: DMARC está aplicando quarantena y alineación estricta.
Decisión: Si aún estás integrando un relé, considera p=none temporalmente mientras validas la alineación—luego aplica.

Task 12 — Verificar reverse DNS para tu IP saliente

cr0x@server:~$ dig +short -x 198.51.100.10
smtp.example.com.

Qué significa: rDNS existe. Si apunta a algo genérico o falta, algunos receptores desconfiarán.
Decisión: Si operas tus propias IPs, configura rDNS a un hostname estable que coincida razonablemente con DNS directo.

Task 13 — Comprobar si el egreso por puerto 25 está bloqueado (verificación direct-to-MX)

cr0x@server:~$ nc -vz gmail-smtp-in.l.google.com 25
nc: connect to gmail-smtp-in.l.google.com (142.250.102.27) port 25 (tcp) failed: Connection timed out

Qué significa: No puedes entregar directamente a Gmail por puerto 25 desde este host (bloqueado o filtrado).
Decisión: Usa un relé de submission en 587. No luches contra la política de egreso de tu proveedor con “trucos” ingeniosos.

Task 14 — Confirmar que el host de WordPress no intenta ejecutar “sendmail” sin un MTA

cr0x@server:~$ command -v sendmail || echo "sendmail not found"
sendmail not found

Qué significa: PHP mail() probablemente fallará o hará no-op silencioso según la configuración.
Decisión: Configura WordPress para usar submission SMTP explícitamente; no confíes en un binario local ausente.

Task 15 — Observar registros en vivo mientras envías una prueba (verdad en tiempo real)

cr0x@server:~$ sudo tail -f /var/log/mail.log
Jan  4 11:29:17 server postfix/smtpd[28110]: connect from web01[203.0.113.11]
Jan  4 11:29:18 server postfix/smtpd[28110]: 1A2B3C4D5E: client=web01[203.0.113.11], sasl_method=LOGIN, sasl_username=app-smtp
Jan  4 11:29:18 server postfix/cleanup[28113]: 1A2B3C4D5E: message-id=<6f9d2a3c9e1b@web01>
Jan  4 11:29:18 server postfix/qmgr[1331]: 1A2B3C4D5E: from=<no-reply@example.com>, size=1845, nrcpt=1 (queue active)
Jan  4 11:29:19 server postfix/smtp[28115]: 1A2B3C4D5E: to=<user@example.net>, relay=mx.example.net[198.51.100.20]:25, delay=1.2, dsn=2.0.0, status=sent (250 2.0.0 OK)

Qué significa: Ves al cliente conectar, autenticarse, encolar y entregar. Esa es la historia completa.
Decisión: Si la conexión nunca aparece, WordPress no está usando tu relé. Arregla la configuración del plugin y las credenciales.

Task 16 — Validar la configuración de Postfix por errores obvios

cr0x@server:~$ sudo postconf -n
myhostname = smtp.relay.local
mydestination = $myhostname, localhost.localdomain, localhost
inet_interfaces = all
smtpd_tls_security_level = may
smtp_tls_security_level = may
smtpd_sasl_auth_enable = yes
smtpd_recipient_restrictions = permit_sasl_authenticated,reject_unauth_destination

Qué significa: Líneas clave: SASL auth habilitado, y reject_unauth_destination evita relay abierto.
Decisión: Si no ves reject_unauth_destination, detente y arréglalo antes de exponer este servidor a la red.

Segunda broma (y última): Un relay abierto es como dejar el coche abierto con las llaves dentro—excepto que las multas llegan a la casa de tu jefe.

Una configuración Postfix de grado producción (con salvaguardas)

Hay dos roles comunes de “relé” que la gente confunde:
(1) un servidor de submission que acepta correo autenticado desde tus apps,
y (2) un smart host que reenvía el correo saliente a través de un proveedor ascendente.
Puedes ejecutar ambos roles en una instancia Postfix, pero sé explícito.

Patrón A: servidor Postfix de submission que reenvía a un proveedor gestionado

Esto es lo que recomiendo para la mayoría de equipos: las apps envían a tu Postfix en 587 con SMTP AUTH, Postfix reenvía al proveedor en 587.
Obtienes registros centralizados y políticas, y no posees la reputación de IP.

Instalar paquetes (ejemplo Debian/Ubuntu)

cr0x@server:~$ sudo apt-get update
Hit:1 http://archive.ubuntu.com/ubuntu jammy InRelease
Reading package lists... Done
cr0x@server:~$ sudo apt-get install -y postfix libsasl2-modules mailutils
Reading package lists... Done
Building dependency tree... Done
Setting up postfix (3.6.4-1ubuntu1.3) ...

Decisión: Si ya hay Exim u otro MTA en el entorno, no apiles MTAs. Elige uno.

Configurar Postfix para submission autenticada y reenvío seguro

Edita /etc/postfix/main.cf (mostrando lo esencial, no todos los valores por defecto). Los valores son ejemplos; ajusta hostnames/dominios.

cr0x@server:~$ sudo postconf -e "myhostname = smtp.example.com"
cr0x@server:~$ sudo postconf -e "myorigin = example.com"
cr0x@server:~$ sudo postconf -e "mydestination = \$myhostname, localhost.localdomain, localhost"
cr0x@server:~$ sudo postconf -e "inet_interfaces = all"
cr0x@server:~$ sudo postconf -e "mynetworks = 127.0.0.0/8 [::1]/128"
cr0x@server:~$ sudo postconf -e "smtpd_recipient_restrictions = permit_sasl_authenticated, reject_unauth_destination"
cr0x@server:~$ sudo postconf -e "smtpd_sasl_auth_enable = yes"
cr0x@server:~$ sudo postconf -e "smtpd_tls_security_level = may"
cr0x@server:~$ sudo postconf -e "smtpd_tls_auth_only = yes"
cr0x@server:~$ sudo postconf -e "smtp_tls_security_level = may"

Qué hace esto:
El servidor no es un relay abierto; solo usuarios autenticados pueden relayer.
TLS se usa para la autenticación (así no envías contraseñas en texto plano).

Habilitar el servicio submission en el puerto 587

En /etc/postfix/master.cf, asegúrate de que submission esté habilitado y requiera cifrado.
Puedes hacerlo con un append seguro + revisión manual. Tras editar, verifica con postfix check.

cr0x@server:~$ sudo grep -n '^submission' -A6 /etc/postfix/master.cf
submission inet n       -       y       -       -       smtpd
  -o syslog_name=postfix/submission
  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
  -o milter_macro_daemon_name=ORIGINATING

Decisión: Si no puedes imponer TLS en submission, no ejecutes submission en un segmento de red no confiable.

Configurar Postfix para relé saliente vía un smart host ascendente

Si tu proveedor te da smtp.provider.tld:587 con credenciales, configura relayhost y el mapa de contraseñas SASL.

cr0x@server:~$ sudo postconf -e "relayhost = [smtp.provider.tld]:587"
cr0x@server:~$ sudo postconf -e "smtp_sasl_auth_enable = yes"
cr0x@server:~$ sudo postconf -e "smtp_sasl_security_options = noanonymous"
cr0x@server:~$ sudo postconf -e "smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd"
cr0x@server:~$ sudo postconf -e "smtp_tls_security_level = encrypt"
cr0x@server:~$ sudo bash -c 'cat > /etc/postfix/sasl_passwd <<EOF
[smtp.provider.tld]:587 relay-user:relay-password
EOF'
cr0x@server:~$ sudo postmap /etc/postfix/sasl_passwd
cr0x@server:~$ sudo chmod 600 /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db

Decisión: Si estás chequeando /etc/postfix/sasl_passwd en Git, para. Pon las credenciales en un almacén de secretos y empléalas en el despliegue.

Reiniciar y validar la configuración

cr0x@server:~$ sudo postfix check
cr0x@server:~$ sudo systemctl restart postfix
cr0x@server:~$ sudo systemctl is-active postfix
active

Qué significa: Postfix aceptó la configuración y está en ejecución.
Decisión: Si postfix check se queja, arregla eso primero; no “reinicies hasta que funcione.”

Básicos de hardening que no debes omitir

  • Firewall: expone 587 solo a las redes de app/VPN, y 25 solo si realmente lo necesitas (muchos no lo necesitan).
  • Limitación de tasa: limita por cliente para evitar que un WordPress comprometido envíe 200k “facturas”.
  • Separación de autenticación: credenciales SMTP distintas por entorno (prod/stage/dev) y por app si es posible.
  • Retención de registros: guarda lo suficiente para investigar disputas; pero no registres cuerpos de mensajes si la política lo impide.

Una cita ingenieril para mantenerte honesto: “La esperanza no es una estrategia.” — idea parafraseada atribuida a la cultura de operaciones (a menudo repetida en equipos SRE).

Autenticación DNS que afecta la entregabilidad (SPF, DKIM, DMARC, rDNS)

La entrega de correo es mitad SMTP y mitad identidad. Necesitas ambas.
La autenticación no garantiza la colocación en bandeja, pero la falta de ella garantiza problemas.

SPF: quién está autorizado a enviar

SPF comprueba el remitente del sobre (Return-Path / MAIL FROM). Los receptores consultan DNS por un TXT en el dominio.
Si envías a través de un proveedor relé, tu SPF debe incluirlos.

Qué hacer: publica un único registro SPF, manténlo dentro de los límites de consultas DNS (realidad práctica),
y usa -all cuando estés seguro.

Qué evitar: múltiples registros SPF (los receptores lo tratan como permerror), y “pon simplemente +all” (lo que anula el propósito).

DKIM: firma del contenido

DKIM firma cabeceras y cuerpo; los receptores verifican con la clave pública en DNS.
Es sensible a la modificación del mensaje—algunos gateways “de seguridad” y pies de página pueden romper DKIM.

Qué hacer: que exactamente un componente firme (tu relé o tu proveedor), rota claves, y mantiene selectores estables por flujo de envío.

DMARC: política + alineación

DMARC añade dos ideas cruciales:
(1) decir a los receptores qué hacer ante fallos de autenticación, y
(2) exigir alineación entre el dominio en la cabecera From visible y los dominios autenticados por SPF/DKIM.

Despliegue recomendado: comienza con p=none para observar, luego pasa a quarantine, luego a reject.
Si tu organización tiene múltiples emisores (helpdesk, CRM, marketing), haz un inventario primero o romperás correos legítimos.

Reverse DNS (rDNS): identidad de la IP

Si operas la IP saliente, configura rDNS. Si usas un proveedor, ellos generalmente lo gestionan.
Los receptores usan rDNS como indicio de credibilidad. No es estrictamente obligatorio en todos lados, pero faltar rDNS es como presentarse a una entrevista sin identificación.

Chequeo de realidad de la alineación: “From” debe ser tuyo

La herida autoinfligida más común: WordPress envía “From: wordpress@server-hostname” o “From: info@gmail.com”
mientras el remitente del sobre es otra cosa. DMARC ve la desalineación y los receptores te tratan como sospechoso.
Arregla el dominio From. Contrólalo.

Patrones de configuración de WordPress/app que no te sabotean

WordPress en sí no es el villano; la configuración inconsistente lo es.
Tu trabajo es hacer que WordPress se comporte como un cliente bien educado: submission SMTP autenticado, identidad estable, cabeceras sensatas.

Elige una ruta de envío y hazla cumplir

Si ejecutas submission Postfix internamente, todo debe enviar a él. Si usas un relé gestionado directamente desde WordPress,
hazlo de forma consistente. Lo que no quieres es:

  • algunos correos yendo por PHP mail(),
  • otros por el plugin SMTP A,
  • y restablecimientos de contraseña por el plugin B porque “arregló” algo el año pasado.

Usa una dirección remitente dedicada para correo transaccional

Usa algo como no-reply@tudominio o notifications@tudominio.
Manténla consistente. Los receptores aprenden patrones. Los humanos también.

Configura Reply-To intencionadamente

Si los usuarios deben responder, pon Reply-To a una dirección monitoreada. Si no deben, considera igualmente un buzón monitoreado para manejo de rebotes.
Los fallos silenciosos a menudo se ocultan en rebotes que nunca lees.

No envíes como un dominio que no controlas

Enviar “From: tuMarca@gmail.com” desde tu servidor es autolesionarse en entregabilidad. También complica auditoría.
Usa tu dominio, autentícalo y dirige las respuestas donde quieras recibirlas.

Apps: prefiere librerías SMTP con manejo explícito de errores

Ya sea PHP, Node, Python o Java: configura tu cliente SMTP para fallar en voz alta y registrar respuestas SMTP.
Si tu app se traga excepciones, aprenderás de fallos de correo por clientes enojados. Ese es un sistema de monitorización duro.

Monitorización, alertas y evidencias: deja de adivinar

El correo fiable no es “configúralo y olvídalo.” Es configurar, observar y aplicar.
Necesitas al menos tres capas: salud del servicio, salud de la cola y señales de entregabilidad.

Salud del servicio

  • Alerta si Postfix está caído.
  • Alerta si el disco está casi lleno (colas y registros necesitan espacio; disco lleno produce fallos creativos).
  • Alerta sobre expiración de certificados TLS si terminas TLS tú mismo.

Salud de la cola

Una cola de correo creciente no es “ruido normal”. Es un síntoma visible de rechazo ascendente, problema de red,
fallo de credenciales o throttling.

cr0x@server:~$ postqueue -p | tail -n 5
-- 2 Kbytes in 1 Request.

Decisión: Si está consistentemente distinto de cero y aumentando, alerta e investiga los códigos de respuesta SMTP en los registros.

Señales de entregabilidad

Al menos: guarda muestras de cabeceras entregadas y verifica que SPF/DKIM/DMARC pasen consistentemente.
Mejor: recopila códigos de rebote y clasifícalos (autenticación, política, buzón lleno, rechazo por spam).

Correlaciona por IDs de mensaje

Tu relé debe registrar IDs de cola e IDs ascendentes. Tu app debe registrar un ID de correlación para la “intención de correo.”
Si no puedes trazar “usuario solicitó restablecer contraseña” → “mensaje aceptado por el relé” → “entregado o rebotado”,
no tienes un sistema de correo. Tienes vibras.

Tres mini-historias corporativas desde las trincheras

Mini-historia 1: El incidente causado por una suposición errónea

Una empresa SaaS mediana ejecutaba WordPress para páginas de marketing y una app personalizada para el producto.
Los restablecimientos de contraseña se “enviaban” (según registros de la app). Los formularios de contacto se “enviaban” (según WordPress).
Los tickets de soporte se dispararon: los usuarios no podían iniciar sesión.

La suposición errónea fue sutil: todos creían que una llamada API exitosa al mailer de la aplicación significaba entrega exitosa.
En realidad, la app estaba configurada para usar la interfaz local sendmail, que solo entregaba mensajes a una cola local. Esa cola existía—apenas.
La imagen de la VM tenía un MTA instalado meses antes, pero nadie lo gestionaba. Nadie lo monitoreaba. Nadie leía los registros de correo.

Durante un ciclo rutinario de parches del SO, el host se reinició y volvió con un hostname cambiado y una configuración de resolver faltante (cloud-init “ayudó”).
Postfix arrancó, pero no podía resolver registros MX remotos. Los mensajes se encolaron y encolaron. La app seguía devolviendo éxito.
Mientras tanto, algunos mensajes salieron a cuentagotas después de que DNS se recuperara, llegando horas tarde y confundiendo aún más.

La solución no fue heroica. Pasaron a submission SMTP a un único relé, registraron IDs de cola en la app,
y pusieron una alerta para tamaño de cola > umbral pequeño por más de unos minutos.
La próxima vez que DNS falló, lo vieron de inmediato. Nada de conjeturas. Nada de arqueología para clientes.

Mini-historia 2: La optimización que salió mal

Otra compañía decidió que su proveedor de correo transaccional gestionado era “demasiado caro.”
Tenían un brillante clúster Kubernetes, un equipo SRE inteligente y la confianza justa para ser peligrosos.
El plan: enviar correo directamente desde los pods de la app usando una librería SMTP ligera hacia los MX de los destinatarios.

En papel, parecía eficiente: menos dependencias, sin vendor lock-in y “SMTP es solo un protocolo.”
En realidad, redescubrieron por qué el correo saliente es un servicio especializado.
Su proveedor cloud bloqueaba el puerto 25 desde los nodos. Solicitaron una excepción y la obtuvieron—más o menos.
Algunos caminos de egreso funcionaban; otros eran throttleados silenciosamente. La entrega se volvió no determinista entre pods.

Luego entró la reputación. Sus IPs salientes cambiaban a medida que los nodos rotaban.
La firma DKIM era inconsistente porque diferentes despliegues tenían secretos ligeramente distintos.
Algunos mensajes pasaban, otros fallaban. La alineación DMARC era inestable. Los receptores empezaron a limitar tasas y a mandar a spam.
La “optimización” no solo costó tiempo; enseñó a los proveedores a desconfiar de su dominio.

Revirtieron el cambio. La solución aburrida: un relé centralizado con identidad estable, DKIM consistente y un proveedor que realmente gestiona reputación.
El equipo SRE no perdió prestigio; ganó una lección operativa: el correo más barato es el que no tienes que explicar.

Mini-historia 3: La práctica aburrida pero correcta que salvó el día

Una gran empresa tenía una práctica que genuinamente respeto: cada correo transaccional llevaba un ID de trazado en una cabecera,
y cada salto SMTP lo registraba. No “a veces.” Siempre.
Se imponía en CI: si tu mailer no añadía la cabecera, la build fallaba.

Una mañana, finanzas informó facturas faltantes. Ventas escaló. Comenzó la tormenta habitual:
“¿La app está caída?” “¿Es la red?” “¿Alguien cambió DNS?” La gente empezó a componer teorías como si fuera un proyecto grupal.

En cambio, el on-call sacó un ID de trazado de los registros de la app, lo buscó en los registros del relé y encontró una aceptación SMTP 250 limpia del relé,
seguida por repetidos aplazamientos 4xx del proveedor ascendente: throttling temporal por política.
La cola crecía, pero dentro de límites configurados. Los reintentos ocurrían. Nada estaba “roto”, estaba lento.

Como tenían evidencia, hicieron lo sensato: informaron a stakeholders de la demora, redujeron temporalmente la tasa de picos,
y dejaron que la cola se vaciara. Sin pánicos. Sin cambios de configuración improvisados.
Práctica aburrida, día aburrido. Ese es el sueño.

Errores comunes: síntoma → causa raíz → solución

“WordPress dice enviado, pero nada llega” → PHP mail() entrega localmente → usar submission SMTP

Síntoma: El plugin de WordPress informa éxito; no hay rebotes; no hay registros de correo.

Causa raíz: PHP mail() no garantiza entrega; MTA local ausente o roto.

Solución: Configura WordPress para usar SMTP (587) hacia tu relé; verifica con registros en vivo del relé y una prueba como swaks.

“El correo está en cola horas” → direct-to-MX bloqueado o aplazado → relé vía proveedor en 587

Síntoma: postqueue -p muestra muchos mensajes aplazados; registros muestran timeouts a puerto 25.

Causa raíz: puerto 25 saliente bloqueado; greylisting sin reintentos; filtrado de red.

Solución: enruta saliente via un smart host ascendente en 587 con auth; deja la lógica de reintentos en Postfix, no en tu app.

“Gmail acepta pero los mensajes van a spam” → autenticación/alineación débil → arreglar SPF/DKIM/DMARC

Síntoma: mensajes llegan a spam; cabeceras muestran SPF softfail/neutral o DKIM fail; DMARC fail.

Causa raíz: dominio remitente no alineado; DKIM faltante; SPF apunta a emisores equivocados.

Solución: alinea el dominio From con dominios autenticados; publica includes SPF, habilita firma DKIM, establece DMARC tras validar.

“Algunos correos se envían, otros no” → múltiples rutas de envío → imponer una ruta

Síntoma: restablecimiento funciona; formulario de contacto no; o viceversa.

Causa raíz: plugins/funciones distintos usando MTAs diferentes o credenciales distintas.

Solución: estandariza: todo correo por un endpoint de submission SMTP; desactiva plugins legacy y rutas de correo locales.

“Auth failed” → credenciales incorrectas o mismatch TLS → arreglar SMTP AUTH y validación de certs

Síntoma: registros muestran fallos SASL; la app informa “No se pudo autenticar.”

Causa raíz: usuario/contraseña erróneos; uso de puerto 25 sin submission; TLS requerido pero no usado.

Solución: confirmar con swaks; imponer TLS en 587; rotar credenciales y usar secretos por app.

“Los rebotes nunca aparecen” → Return-Path apunta a la nada → configurar manejo de rebotes

Síntoma: usuarios reportan no entrega; no tienes buzón de rebotes.

Causa raíz: remitente de sobre no monitorizado; el relé reescribe Return-Path; o nunca configuraste un dominio de rebotes.

Solución: asegura que los rebotes vayan a un buzón/sistema monitorizado; registra y categoriza los DSN.

“Tras habilitar DMARC reject, correos legítimos fallan” → emisores olvidados → inventario primero

Síntoma: helpdesk/CRM/sistemas legacy dejan de enviar.

Causa raíz: DMARC en modo enforce sin mapear todas las fuentes; falta firma DKIM en algunos sistemas.

Solución: empieza DMARC con p=none, revisa reportes, luego aplica; migra emisores sueltos al relé o fírmales correctamente.

Listas de verificación / plan paso a paso

Plan A (recomendado): WordPress/app → submission Postfix → proveedor de relé gestionado

  1. Elige tu dominio remitente para correo transaccional (ejemplo: example.com).
  2. Levanta un endpoint de submission (Postfix en 587) accesible solo desde tus servidores de app.
  3. Configura relayhost ascendente en Postfix hacia tu proveedor en 587 con SMTP AUTH.
  4. Configura WordPress/app para usar SMTP hacia tu host de submission con TLS y credenciales por app.
  5. Publica SPF para el dominio incluyendo al proveedor (y solo lo que realmente usas).
  6. Habilita firma DKIM (proveedor o relé) y publica claves de selector.
  7. Despliega DMARC como p=none inicialmente; confirma alineación; luego pasa a quarantine/reject.
  8. Configura manejo de rebotes (Return-Path) y monitoriza DSN.
  9. Añade monitorización: servicio postfix, tamaño de cola, alertas basadas en logs por 4xx/5xx repetidos.
  10. Ejecuta una matriz de pruebas: envía a varios proveedores principales; inspecciona cabeceras; confirma resultados de paso.

Checklist de emergencia “haz que envíe ahora” (sin crear deuda futura)

  1. Deja de usar direct-to-MX desde servidores web si el puerto 25 es inestable.
  2. Consigue submission SMTP funcionando con swaks primero; luego apunta WordPress/app a él.
  3. Usa una dirección From en tu dominio (no un dominio de correo gratuito).
  4. Publica SPF y DKIM antes de empezar a enviar en masa.
  5. Activa el registro y guarda los IDs de mensaje.

“Queremos manejar nuestra propia entrega saliente” checklist (el impuesto de la realidad)

  1. Confirma que el egreso por puerto 25 esté permitido y estable en todos los caminos de egreso.
  2. Configura rDNS y DNS directo; mantiene IPs estables.
  3. Implementa firma DKIM y rotación de claves.
  4. Implementa procesamiento de feedback loops donde esté disponible (quejas y rebotes).
  5. Precalienta IPs y dominios (aumento gradual del tráfico).
  6. Construye monitorización para eventos de listas de bloqueo y patrones de rechazo.

Si esa lista suena como un segundo trabajo, es porque lo es.

Preguntas frecuentes (lo que se pregunta a las 2 a.m.)

1) ¿Por qué WordPress dice “enviado” cuando nada llega?

Porque muchos caminos solo confirman la entrega local (a la interfaz mail de PHP o a un MTA local),
no la entrega final. “Enviado” muchas veces significa “lo dejé en una tubería.”

2) ¿Debo usar SMTP puerto 25, 465 o 587?

Usa 587 para submission de clientes con autenticación y TLS. El puerto 25 es para servidor-a-servidor y comúnmente bloqueado para clientes.
El puerto 465 es legado “TLS implícito” y todavía se usa, pero 587 es la elección estándar moderna.

3) ¿Puedo usar SMTP de Gmail para mi sitio?

Puedes para bajo volumen, pero suele ser una mala solución a largo plazo: límites de tasa, gestión de credenciales y problemas de alineación.
Además, depender de un buzón personal como dependencia de producción es cómo terminas depurando correo desde una sala de espera del aeropuerto.

4) ¿Cuál es la configuración DNS mínima para la entregabilidad?

SPF y DKIM como mínimo, con DMARC añadido pronto. Si operas tus propias IPs salientes, añade rDNS.
Sin estos, apuestas contra el escepticismo predeterminado de los receptores.

5) ¿Qué significa realmente la alineación DMARC?

Significa que el dominio que ven los humanos en la cabecera From: debe coincidir (o ser un padre, según estrictez)
con los dominios autenticados por SPF y/o DKIM. La desalineación es una razón común por la que correo legítimo va a la basura.

6) ¿Por qué veo mensajes “deferred” en la cola?

Los aplazamientos son fallos temporales (4xx). Causas incluyen greylisting, límites de tasa, bloqueos temporales de política o problemas de red.
Los aplazamientos no son “normales” si se acumulan; solo están bien si reintentan y se vacían de forma predecible.

7) ¿Cómo demuestro que un correo fue entregado?

Puedes demostrar que tu servidor SMTP obtuvo un 250 “sent/accepted” del MX del destinatario.
No puedes demostrar que un humano lo leyó. Si necesitas prueba a nivel humano, eso es problema de producto (notificaciones in-app, recibos, etc.).

8) ¿Mi servidor WordPress debería ejecutar Postfix directamente?

A veces. Pero suele ser mejor mantener WordPress como cliente y centralizar correo a través de un host de relé/submission.
Los servidores web se comprometen; no quieres que servidores web comprometidos tengan poder de envío de correo saliente directo.

9) ¿Por qué fallan más los correos de restablecimiento de contraseña que los boletines?

No siempre fallan más—la gente los nota más. Además, los restablecimientos suelen activarse durante incidentes (picos de tráfico),
y su tiempo es urgente. Cualquier demora en cola se siente como un fallo.

10) ¿Está bien desactivar la verificación TLS en el plugin SMTP?

No, no en producción. “Arregla” el síntoma eliminando seguridad y complicando la depuración futura.
Arregla certificados y confianza correctamente. Quieres comportamiento seguro y repetible.

Conclusión: próximos pasos que permanecen

El correo fiable no trata sobre el plugin perfecto. Trata de tener una ruta de relé real, identidad consistente y registros que digan la verdad.
Construye un endpoint de submission, enruta a través de un proveedor salvo que realmente necesites auto-hospedar reputación, y alinea SPF/DKIM/DMARC.

Haz esto esta semana

  • Ejecuta la guía de diagnóstico rápido y clasifica la falla (entrega desde app vs red/auth vs entregabilidad).
  • Estandariza en submission SMTP (587) desde WordPress/app hacia un único relé.
  • Publica/verifica SPF, DKIM y DMARC alineados para el dominio From que usas realmente.
  • Añade monitorización de cola y registros para que lo descubras antes que tus clientes.

Haz esto después

  • Separa flujos transaccionales y de marketing si envías ambos.
  • Rota credenciales, separa prod/stage y trata las credenciales SMTP como cualquier otro secreto de producción.
  • Documenta la ruta de trazado (intención de app → ID de cola del relé → resultado ascendente) y hazla parte de la respuesta a incidentes.

Haz que el correo sea aburrido. Tu yo futuro te lo agradecerá, probablemente en silencio, porque finalmente tendrá tiempo para otra cosa.

← Anterior
WireGuard sitio a sitio: conectar dos oficinas por Internet paso a paso
Siguiente →
API remota de Docker: no expongas root accidentalmente en Internet

Deja un comentario