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 🙂 |