Fixing the bottleneck Transactional Emails

This is part 6 of my article series 25+ Tutorials on How to boost the performance of your WooCommerce store. In this article we will take an in-depth look at transactional emails, and how to optimise your stores performance by deactivating non-essential emails and by sending email asynchronously to your customers.

Each email sent from your store takes times to compile and to send. Whenever an order transitions to another status, when products are running low on stock, when passwords are changed, new users register, an order is placed in the checkout, etc. emails are sent to the customer, to the admin in the worst case to both.

Since each email can take somewhere between 1-3 seconds to send, you might end up with a degraded user experience, without knowing why this is happening. This is especially annoying when a customer is entering their payment information in your WooCommerce checkout and is expecting to see an order confirmation page. But hey, WooCommerce sends a order confirmation to the customer himself, another order notification to the site admin, a third email to notify that stock is running low, maybe even a fourth email with payment instructions on specific pre payment methods. If you happen to register the new customer in your checkout, there even might be more emails being queued up to being sent. And whoops your customer is already waiting for 15-20 secs, to see a simple order confirmation page.

We need to do 2 things to fix this standard behaviour, first we want to reducing the number of emails sent by deactivating everything that’s not essential or of real benefit to you. Of course performance depends on many factors: How fast is my transactional email provider? Am I sending emails from my server or via 3rd party email service?

Step 1: Deactivate non-essential WordPress emails

Use the excellent and simple Manage Notifications Emails Plugin to disable all non essential emails (and ugly because they are non-HTML Emails) WordPress sends by default.

composer require wpackagist-plugin/manage-notification-emails

As you can see in my screenshot, I deactivated all non-essential notifications. We will only keep those password reset emails activated.

Step 2: Deactivate non-essential WooCommerce emails

WooCommerce Email Settings

Disable as many non-essential emails under WooCommerce -> Settings -> Emails. For example: Why send a order confirmation and a duplicate admin notification if you could simply BCC the admin in the order confirmation.

Send emails asynchronously with Scheduled Actions

Sending out emails is important, but we don’t want the customer to wait for emails being sent out in the background. Which is why we want to alter WordPress’s mailing functionality to send out emails asynchronously – not when the user interacts with our site.

This will improve the site performance and will use WordPress scheduled actions logic to send out the email at a later time. In order to not confuse our customers we will send out emails once a minute. The code below is taken from an article on Stackexchange How to make WordPress Email Async.

if ( ! defined( 'DOING_CRON' ) || ( defined( 'DOING_CRON' ) && ! DOING_CRON ) ) { if (!function_exists('wp_mail')) { function wp_mail() { $args = func_get_args(); // Get the args passed to the wp_mail function $args[] = mt_rand(); // append dummy argument to make sure action is unique wp_schedule_single_event( time() + 5, 'cron_send_mail', $args ); } } } function example_cron_send_mail() { $args = func_get_args(); array_pop( $args ); // remove dummy argument appended earlier call_user_func_array( 'wp_mail', $args ); } add_action( 'cron_send_mail', 'example_cron_send_mail', 10, 10 );

What this does is straight-forward. It overwrites the original WordPress, pluggable wp_mail() function. Instead of sending the email right away, our new wp_mail function adds a new scheduled task with all the relevant information (like mail content and recipient, etc) to the queue. Only when the scheduled actions are processed, WordPress’s native wp_mail() function is used to actually send the email. Since this is done at a later time, emails are sent asynchronously and do no longer block rendering pages.

Keep in mind, that this approach adds a certain delay to all emails. Take a password reset email, for example – this is something that a customer expects instantly. So you shouldn’t add too much delay, here.

Continue to part 7 of this tutorial series: Optimising Frontend Resources with Perfmatters & Grunt.