Interceptar las llamadas a wp_mail en WordPress es una técnica imprescindible para registrar correos, depurar el flujo de envío, evitar envíos en entornos de desarrollo y auditar contenido y cabeceras. A continuación tienes un tutorial detallado con ejemplos claros, buenas prácticas y advertencias sobre seguridad y rendimiento. Todos los fragmentos de código están listos para usarse en un plugin o en el archivo functions.php de un tema (preferible plugin para persistencia).
Contents
Por qué interceptar wp_mail
- Depuración: Ver exactamente qué se está mandando (destinatarios, asunto, headers, cuerpo) y detectar problemas de codificación o contenido inesperado.
- Registro/Auditoría: Mantener un historial de comunicaciones generadas por el sitio (útil en entornos multisitio o transaccionales).
- Entornos de desarrollo: Evitar envíos reales y redirigir correos a buzones de pruebas.
- Modificación avanzada: Manipular PHPMailer antes de que se envíe (por ejemplo, forzar SMTP, añadir cabeceras, cambiar Reply-To).
Resumen de hooks útiles
| Hook | Tipo | Qué permite |
|---|---|---|
| wp_mail | Filter | Modificar/leer los argumentos (to, subject, message, headers, attachments) justo antes del envío. Devuelve el array de argumentos. |
| pre_wp_mail | Filter (opcional) | Permite anular el envío por completo y devolver una respuesta (ideal para entornos de testing). (Disponibilidad según versión en versiones modernas existe.) |
| phpmailer_init | Action | Acceder al objeto PHPMailer para inspeccionar/alterar transporte, cabeceras y contenido final. |
| wp_mail_failed | Action | Recibir errores cuando falla el envío (recibe un WP_Error con detalles). |
Buenas prácticas antes de tocar el envío
- Implementa el código como un plugin para que no se pierda al actualizar el tema.
- Respeta la privacidad: no registres información sensible (contraseñas, tokens) y anonymiza direcciones si el log es público.
- Usa logs con rotación y límites de tamaño para evitar llenar disco.
- En entornos de producción, registra a un servicio seguro o tabla en la base de datos con acceso restringido.
Ejemplos prácticos
1) Registro simple con add_filter(wp_mail)
Este ejemplo registra todos los correos en el log de PHP (error_log). Útil para debugging rápido.
stringarray,
// subject => string,
// message => string,
// headers => stringarray,
// attachments => array
// )
log = sprintf(
[WP_MAIL] To: %s Subject: %s Headers: %s Attachments: %s Time: %snMessage:n%sn---n,
is_array( args[to] ) ? implode( ,, args[to] ) : args[to],
args[subject],
is_array( args[headers] ) ? json_encode( args[headers] ) : args[headers],
!empty( args[attachments] ) ? implode( ,, args[attachments] ) : none,
date( Y-m-d H:i:s ),
args[message]
)
error_log( log ) // envía a PHP error log (puedes cambiar por file_put_contents)
return args // Muy importante devolver los argumentos para continuar el envío
}, 10 )
?>
2) Evitar envíos en entornos de desarrollo y guardar en archivo
En development suele ser necesario bloquear los envíos y volcarlos a un archivo local. Aquí mostramos cómo hacerlo con pre_wp_mail si está disponible si no, se puede usar wp_mail y devolver un array con modificaciones.
3) Inspeccionar el PHPMailer final con phpmailer_init
Si quieres ver la versión final que PHPMailer está a punto de enviar (cabeceras ya procesadas, content-type, encodings, etc.), usa phpmailer_init. Útil para debugging con SMTP y para verificar cabeceras multipart.
phpmailer->From,
FromName => phpmailer->FromName,
Subject => phpmailer->Subject,
Body => phpmailer->Body,
AltBody => phpmailer->AltBody,
To => array_map( function(t){ return (string) t }, (array) phpmailer->getToAddresses() ),
Cc => array_map( function(t){ return (string) t }, (array) phpmailer->getCcAddresses() ),
Bcc => array_map( function(t){ return (string) t }, (array) phpmailer->getBccAddresses() ),
Headers => phpmailer->getCustomHeaders(),
Mailer => phpmailer->Mailer,
SMTPDebug => phpmailer->SMTPDebug,
]
// Guardar en fichero de debug (no público)
uploads = wp_upload_dir()
file = trailingslashit( uploads[basedir] ) . phpmailer-debug.log
file_put_contents( file, date( Y-m-d H:i:s ) . . print_r( info, true ) . n----n, FILE_APPEND LOCK_EX )
})
?>
4) Capturar errores con wp_mail_failed
Cuando el envío falla, WordPress dispara wp_mail_failed pasando un WP_Error. Aprovecha esto para registrar fallos y notificar al administrador.
get_error_code(),
wp_error->get_error_message(),
date( Y-m-d H:i:s )
)
// Guardar en log de errores
error_log( message )
// Opcional: enviar alerta administrador (cuidado con loops)
// wp_mail( get_option( admin_email ), Alerta: fallo envío de correo, message )
})
?>
5) Enviar logs a un endpoint remoto (webhook) de forma segura
Enviar los logs a un sistema centralizado es preferible en infraestructuras distribuidas. Ejemplo simple con cURL y autenticación por token. Asegúrate de no incluir contenido sensible o de cifrarlo.
args[to],
subject => args[subject],
message => args[message],
headers => args[headers],
time => date( c ),
site => get_bloginfo( url ),
]
ch = curl_init( https://logs.example.com/receive )
curl_setopt( ch, CURLOPT_RETURNTRANSFER, true )
curl_setopt( ch, CURLOPT_POST, true )
curl_setopt( ch, CURLOPT_HTTPHEADER, [
Content-Type: application/json,
Authorization: Bearer YOUR_SECRET_TOKEN
] )
curl_setopt( ch, CURLOPT_POSTFIELDS, json_encode( payload ) )
curl_setopt( ch, CURLOPT_TIMEOUT, 2 ) // no bloquear
resp = curl_exec( ch )
curl_close( ch )
return args
}, 10 )
?>
Qué registrar (recomendado)
- Destinatarios (To, Cc, Bcc) — enmascara si es necesario.
- Asunto y cuerpo — si contienen datos sensibles, guarda solo un hash o un extracto.
- Cabeceras relevantes (From, Reply-To, Content-Type).
- Adjuntos — nombre y tamaño, no el contenido.
- Resultado del envío (éxito/fallo y detalles del error).
- Marca temporal y site/entorno.
Rendimiento y escalabilidad
- Evita operaciones de red síncronas en cada llamado a wp_mail usa colas o wp_cron para procesar logs de forma asíncrona.
- Si registras en base de datos, crea tabla específica con índices en fecha y destinatario para consultas rápidas.
- Archiva o rota logs periódicamente (logrotate o tareas WordPress).
- Limita la cantidad de datos guardados por correo (no guardar HTML enorme completo si no es necesario).
Consideraciones de seguridad y privacidad
- No registres datos personales sin justificación. Cumple la legislación aplicable (ej. RGPD): mínimo necesario, retención limitada y acceso controlado.
- Protege ficheros y endpoints (ACLs, autenticación, cifrado en tránsito y en reposo si procede).
- Si los logs contienen emails de usuarios, protégelos y ofrécete a anonimizar cuando corresponda.
Diagnóstico avanzado
- Activa SMTPDebug en PHPMailer para obtener trazas del diálogo SMTP (solo en entornos seguros).
- Comprueba encodings (UTF-8) y longitudes de asunto que pueden truncarse.
- Verifica cabeceras duplicadas (Content-Type vs. headers plugin) y conflictos de plugins que manipulan el correo.
Conclusión
Interceptar wp_mail te da control total para logging y debugging. Empieza con un registro simple (wp_mail o phpmailer_init) y evoluciona a soluciones más robustas (colado asíncrono, envío a un servicio centralizado) según lo necesite tu proyecto. Ten siempre en cuenta la privacidad y el rendimiento al diseñar qué y cómo registras.
Recursos útiles
|
|
Acepto donaciones de BAT's mediante el navegador Brave 🙂 |
