How to make WordPress emails async

I recently had an issue on my site where emails were failing to send. That was a problem, but the bigger problem was that the failure caused the script to timeout which really put a damper on the user experience.

I’m posting my solution for making wp_mail asynchronous in the hope of getting some feedback on the idea. Is this a good solution? What pitfalls will I encounter?

1 Answer
1

Since wp_mail is pluggable, we can selectively override it. I run the following code in my general functionality plugin:

/**
 * Email Async.
 * 
 * We override the wp_mail function for all non-cron requests with a function that simply
 * captures the arguments and schedules a cron event to send the email.
 */
if ( ! defined( 'DOING_CRON' ) || ( defined( 'DOING_CRON' ) && ! DOING_CRON ) ) {

    function wp_mail() {

        // Get the args passed to the wp_mail function
        $args = func_get_args();

        // Add a random value to work around that fact that identical events scheduled within 10 minutes of each other
        // will not work. See: http://codex.wordpress.org/Function_Reference/wp_schedule_single_event
        $args[] = mt_rand();

        // Schedule the email to be sent
        wp_schedule_single_event( time() + 5, 'cron_send_mail', $args );
    }
}

Then, I have the following function defined to actually send the email.

/**
 * This function runs during cron requests to send emails previously scheduled by our
 * overrided wp_mail function. We remove the last argument because it is just a random
 * value added to make sure the cron job schedules correctly.
 * 
 * @hook    cron_send_mail  10
 */
function example_cron_send_mail() {

    $args = func_get_args();

    // Remove the random number that was added to the arguments
    array_pop( $args );

    call_user_func_array( 'wp_mail', $args );
}

/**
 * Hook the mail sender. We accept more arguments than wp_mail currently takes just in case
 * they add more in the future.
 */
add_action( 'cron_send_mail', 'example_cron_send_mail', 10, 10 );

Leave a Comment