Log Every Email to Daily Files With Rotation
Writes one line per outgoing email (time, recipient, subject, result) to a daily log file in a protected uploads folder, and deletes files older than the number of days you choose.
Opens WPIDE on
Code
$wpide_mail_log_days = 14; // Days of log files to keep.
$wpide_mail_log_write = function ( $line ) {
$uploads = wp_upload_dir( null, false );
$dir = trailingslashit( $uploads['basedir'] ) . 'wpide-mail-logs';
if ( ! is_dir( $dir ) ) {
wp_mkdir_p( $dir );
file_put_contents( $dir . '/index.php', "<?php\n// Silence is golden.\n" );
file_put_contents( $dir . '/.htaccess', "Require all denied\nDeny from all\n" );
}
$file = sprintf( '%s/mail-%s-%s.log', $dir, gmdate( 'Y-m-d' ), substr( wp_hash( 'mail-log' ), 0, 12 ) );
file_put_contents( $file, '[' . gmdate( 'c' ) . '] ' . str_replace( array( "\r", "\n" ), ' ', $line ) . "\n", FILE_APPEND | LOCK_EX );
};
add_filter( 'wp_mail', function ( $atts ) use ( $wpide_mail_log_write ) {
$wpide_mail_log_write( sprintf( 'QUEUED to=%s subject="%s"', implode( ',', (array) $atts['to'] ), wp_strip_all_tags( (string) $atts['subject'] ) ) );
return $atts;
}, PHP_INT_MAX );
add_action( 'wp_mail_succeeded', function ( $data ) use ( $wpide_mail_log_write ) {
$wpide_mail_log_write( sprintf( 'SENT to=%s', implode( ',', (array) $data['to'] ) ) );
} );
add_action( 'wp_mail_failed', function ( $error ) use ( $wpide_mail_log_write ) {
$data = (array) $error->get_error_data();
$wpide_mail_log_write( sprintf( 'FAILED to=%s error="%s"', isset( $data['to'] ) ? implode( ',', (array) $data['to'] ) : '?', $error->get_error_message() ) );
} );
add_action( 'init', function () {
if ( ! wp_next_scheduled( 'wpide_mail_log_rotate' ) ) {
wp_schedule_event( time() + HOUR_IN_SECONDS, 'daily', 'wpide_mail_log_rotate' );
}
} );
add_action( 'wpide_mail_log_rotate', function () use ( $wpide_mail_log_days ) {
$uploads = wp_upload_dir( null, false );
$files = glob( trailingslashit( $uploads['basedir'] ) . 'wpide-mail-logs/mail-*.log' );
foreach ( (array) $files as $file ) {
if ( filemtime( $file ) < time() - $wpide_mail_log_days * DAY_IN_SECONDS ) {
wp_delete_file( $file );
}
}
} );
Notes
Files live in uploads/wpide-mail-logs with an unguessable name, an index.php and an Apache deny rule (on Nginx keep that folder private), and message bodies are not logged.
How to add this snippet
- Install WPIDE on your WordPress site (it is free) and open Code Snippets.
- Use snippet above adds it from the library in one click. Or copy the code into a new snippet with the same code type.
- It is added inactive: review the code and settings, then switch it on.