1

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

7

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 );
5
  • This is a really nice solution, good stuff. Apr 24, 2015 at 20:15
  • thanks! a million... you saved me big time! Apr 27, 2021 at 20:53
  • You're welcome. :) I'm glad it was useful to you.
    – Dominic P
    Apr 28, 2021 at 0:11
  • You're right, that delays email sending, but this is not a real async email send except if you set up WP cron in server CRON tab running every 5s or less. If not, the mail will be sent when user (or another user) triggers the WP cron that runs within the user script execution: user will endure equally if email fails or is slow. For a real async sending, you have to set up a promise for a client such as GuzzleHttp. Jan 11, 2023 at 14:59
  • Guess I was wrong, I just learned wp is running cron through an http request separated from the current viewer, my bad ! Jan 11, 2023 at 17:37

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.