WooCommerce: Send a Custom Email on Order Status Change

If you use custom WooCommerce order statuses, or wish to target an order status transition that is not default (e.g. when order goes from “Processing” to “Completed”, the Completed email triggers – but what if you want to target a transition from “Processing” to “Custom Status”?), sending custom emails is quite complex.

First of all, they won’t show under WooCommerce > Settings > Emails (unless you code it, true) – second, no email will trigger. So, how do they do it?

Send a custom email when an order is marked with custom status – WooCommerce

PHP Snippet: Send WooCommerce Email @ Custom Order Status

/**
 * @snippet       Send Formatted Email @ WooCommerce Custom Order Status
 * @how-to        Get CustomizeWoo.com FREE
 * @author        Rodolfo Melogli
 * @compatible    WooCommerce 8
 * @community     https://businessbloomer.com/club/
 */
 
// Targets custom order status "refused"
// Uses 'woocommerce_order_status_' hook
 
add_action( 'woocommerce_order_status_refused', 'bbloomer_status_custom_notification', 20, 2 );
 
function bbloomer_status_custom_notification( $order_id, $order ) {
     
    $heading = $subject = 'Order Refused';
 
    // Get WooCommerce email objects
    $mailer = WC()->mailer()->get_emails();
 
    // Use one of the active emails e.g. "Customer_Completed_Order"
    // Wont work if you choose an object that is not active
    // Assign heading & subject to chosen object
    $mailer['WC_Email_Customer_Completed_Order']->heading = $heading;
    $mailer['WC_Email_Customer_Completed_Order']->subject = $subject;
 
    // Send the email with custom heading & subject
    $mailer['WC_Email_Customer_Completed_Order']->trigger( $order_id );
 
    // To add email content use https://businessbloomer.com/woocommerce-add-extra-content-order-email/
    // You have to use the email ID chosen above and also that $order->get_status() == "refused"
     
}

Where to add custom code?

You should place custom PHP in functions.php and custom CSS in style.css of your child theme: where to place WooCommerce customization?

This code still works, unless you report otherwise. To exclude conflicts, temporarily switch to the Storefront theme, disable all plugins except WooCommerce, and test the snippet again: WooCommerce troubleshooting 101

Related content

  • WooCommerce: Add Content to a Specific Order Email
    Customizing WooCommerce emails via the WordPress dashboard is not easy and – sometimes – not possible. For example, you can’t edit or add content to them unless you’re familiar with code. Well, here’s a quick example to learn how to add content to any WooCommerce default order email. In this case study, our goal is […]
  • WooCommerce: How to Add a Custom Checkout Field
    Let’s imagine you want to add a custom checkout field (and not an additional billing or shipping field) on the WooCommerce Checkout page. For example, it might be a customer licence number – this has got nothing to do with billing and nothing to do with shipping. Ideally, this custom field could show above the […]
  • WooCommerce Visual Hook Guide: Emails
    WooCommerce customizers: the Visual Hook Guide is back! Here’s a visual HTML hook guide for the WooCommerce Emails. This visual guide belongs to my “Visual Hook Guide Series“, that I’ve put together so that you can find WooCommerce hooks quickly and easily by seeing their actual locations. Let me know in the comments if this […]
  • WooCommerce: Create a Custom Order Status
    All WooCommerce orders go to either “processing”, “completed”, “on-hold” and other default order statuses based on the payment method and product type. Sometimes these statuses are not enough. For example, you might need to mark certain orders in a different way for tracking, filtering, exporting purposes. Or you might want to disable default emails by […]
  • WooCommerce: Add To: Cc: Bcc: Email Recipients
    The WooCommerce Email Settings allow you to add custom recipients only for New Order, Cancelled Order, Failed Order and all admin-only emails. But what if you want to add an email recipient to a customer email e.g. the Completed Order one? For example, you need to send it to your dropshipper. Also, you might want […]

Rodolfo Melogli

Business Bloomer Founder

Author, WooCommerce expert and WordCamp speaker, Rodolfo has worked as an independent WooCommerce freelancer since 2011. His goal is to help entrepreneurs and developers overcome their WooCommerce nightmares. Rodolfo loves travelling, chasing tennis & soccer balls and, of course, wood fired oven pizza. Follow @rmelogli

32 thoughts on “WooCommerce: Send a Custom Email on Order Status Change

  1. Hi Rodolfo,

    Just wanted to ask what is the best way to apply this PHP code if my theme is deactivated because I am using Oxygen Builder.?

    Many Thanks,
    oli

    1. Use the Code Snippets plugin

  2. Hi there,
    I have a status using this plugin named “reminder”. Now I have also created email template for that reminder as well.
    Now I want to add this email as trigger in processing order email. I mean to say that whenever I change status from reminder to processing. The processing email should be sent to customer. It is not sending right now.
    How can I achieve this?
    Thanks

    1. Hi Mujahid thanks so much for your comment! Yes, this is definitely possible, but I’m afraid it’s custom work. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding!

  3. Hi, how can I change the snippet to send emails for 2 different custom order statuses? Thanks

    1. Hi Radek, thanks so much for your comment! Yes, this is definitely possible, but Iโ€™m afraid itโ€™s custom work. If youโ€™d like to get a quote, feel free to contact me here. Thanks a lot for your understanding!

  4. Hi, We used a plugin to add custom “shipped” status to order and used your snippet to send customer email with customized heading and subject. It works perfectly for a while, and we only noticed a problem since this morning:

    the email can still be send out after changing order status to “shipped”(that means it still triggers the action),
    but the custom subject and headings are gone, our customers are getting “Order completed email” including heading and subject.

    Any updated from WordPress or Woocommerce that caused the issue? what other way to change subject or heading of the email?

    Thanks a lot

    1. Hi Damon, that’s weird. To troubleshoot, disable all plugins but WooCommerce and also switch temporarily to “Twentytwenty” theme (load the snippet there in functions.php) as explained here: https://www.businessbloomer.com/lesson/trwm4l01/

      Once you do that, does it work? If yes, you have a problem with your current theme or one of the plugins.

      Hope this helps!

  5. Hi Rodolfo ,

    I have put a comment here before but it doesn’t seem to have been approved…

    Everything works wonderfully well but it will only send the email if it specifies the WC_Email_Customer_Completed_Order email. If you try and specify one that is unused such as ‘On Hold’ and use the correct hooks, it fails and won’t finish the cycle. Change it back to the completed order email and works again without issue.

    Any thoughts why this may be? The email is turned on, not used for anything else and I have re-created this on two different sites? Thank you

    1. Sorry I have no idea. Sure the On Hold is enabled?

  6. Hi Rodolfo, it’s not working on my website…

    1. function wpblog_wc_register_post_statuses() {
      register_post_status( 'wc-shipped', array(
      'label' => _x( 'Shipped', 'WooCommerce Order status', 'text_domain' ),
      'public' => true,
      'exclude_from_search' => false,
      'show_in_admin_all_list' => true,
      'show_in_admin_status_list' => true,
      'label_count' => _n_noop( 'Approved (%s)', 'Approved (%s)', 'text_domain' )
      ) );
      }
      add_filter( 'init', 'wpblog_wc_register_post_statuses' );
      
      function wpblog_wc_add_order_statuses( $order_statuses ) {
      $order_statuses['wc-shipped'] = _x( 'Shipped', 'WooCommerce Order status', 'text_domain' );
      return $order_statuses;
      }
      add_filter( 'wc_order_statuses', 'wpblog_wc_add_order_statuses' );
      
      /**
       * @snippet       Send Formatted Email @ WooCommerce Custom Order Status
       * @how-to        Get CustomizeWoo.com FREE
       * @sourcecode    https://businessbloomer.com/?p=91907
       * @author        Rodolfo Melogli
       * @compatible    WooCommerce 3.5.7
       * @community     https://businessbloomer.com/club/
       */
        
      // Targets custom order status "shipped"
      // Uses 'woocommerce_order_status_' hook
        
      add_action( 'woocommerce_order_status_shipped', 'bbloomer_status_custom_notification', 20, 2 );
        
      function bbloomer_status_custom_notification( $order_id, $order ) {
            
          $heading = 'Order Shipped';
          $subject = 'Order Shipped';
        
          // Get WooCommerce email objects
          $mailer = WC()->mailer()->get_emails();
        
          // Use one of the active emails e.g. "Customer_Completed_Order"
          // Wont work if you choose an object that is not active
          // Assign heading & subject to chosen object
          $mailer['WC_Email_Customer_Completed_Order']->heading = $heading;
          $mailer['WC_Email_Customer_Completed_Order']->settings['heading'] = $heading;
          $mailer['WC_Email_Customer_Completed_Order']->subject = $subject;
          $mailer['WC_Email_Customer_Completed_Order']->settings['subject'] = $subject;
        
          // Send the email with custom heading & subject
          $mailer['WC_Email_Customer_Completed_Order']->trigger( $order_id );
        
          // To add email content use https://businessbloomer.com/woocommerce-add-extra-content-order-email/
          // You have to use the email ID chosen above and also that $order->get_status() == "shipped"
            
      }
      
      1. Sure “shipped” is the correct email ID?

        1. I’m sorry but what do you mean by email ID? Completely new to PHP ๐Ÿ™

          1. Hi it’s now working! There’s conflict with my other plugin.

            1. The only problem is it doesn’t send email to gmail or yahoo. I can only receive notification from the custom status if sending to my own email domain.

              1. Not sure Jackie, but well done for figuring that out

  7. Hi it’s not working for me ๐Ÿ™ I’ve changed “refused” to “shipped”.

  8. Hey! How can I get a webhook for a custom order status and By replacing the webhook of refuse from the above code, will It work as same

    1. Hi Mudit, thanks so much for your comment! Yes, this is definitely possible, but I’m afraid it’s custom work. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding!

  9. Hi,

    I’m looking to create 2 Order Statuses for Preorders.

    Preorder On-hold (Before Payment) –> Copy Email template from On-Hold
    Preorder Processing (Confirmed after Payment) –> Copy Email template from Processing

    There will be a Preorder Stock status as well, how can I create that using functions.php too?

    Preorder On-hold will be triggered when Customer buys a Preorder product(Preorder stock status), and pends for BACS payment like the rest of the normal instock items.

    Preorder Processing will be manually triggered by myself when Customer made payment.

    I actually see that its possible to create using your above coding but got confused…… I supposed the Order status should be separately created? (Your Order Status here is Refused)

    Thanks.

    1. Yes

  10. How to get custom mails as admin for order payment finished via PayPal? When you don’t use the PayPal notifications because it’s the secondary PayPal mail.

    1. Hi Andre, thanks so much for your comment! Yes, this is definitely possible, but I’m afraid it’s custom work. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding!

  11. Hey, where am I supposed to include the custom status slug/name? I see you commented that I should include “$order->get_status() == “refused” ” but where? Cheers!

    1. Hey Joao! Just change “refused” with your custom order slug here:

      add_action( 'woocommerce_order_status_refused'
  12. Hi, thank you for this information. I’m interested in the following. After a payment is made in Woocommerce we place the order into ‘Processing’ than 5 business days later we change the status to ‘Awaiting Shipping’, using the following plugin to add a custom email then after the item ships we mark the order status as ‘Completed’.

    We would like to automate the part that changes the status to ‘Awaiting Shipping’. Is that possible? So after 5 business days, the order status updates automatically to Awaiting Shipping.

    1. Hi there, thanks so much for your comment! Yes, this is definitely possible, but I’m afraid it’s custom work. If you’d like to get a quote, feel free to contact me here. Thanks a lot for your understanding!

  13. Hey, will this allow my website to send “delivery on route” emails? Also are these emails automatic after installing your code ?

    1. Hello Jacqui, yes & yes ๐Ÿ™‚

  14. Where do I add content from https://businessbloomer.com/woocommerce-add-extra-content-order-email/
    Within same function ?
    Pl advice with example. thanks.

    1. Hey Kumar, it’s explained in the snippet comments. Unfortunately this is custom work and I cannot provide a complementary solution here via the blog comments. Thanks a lot for your understanding! ~R

Questions? Feedback? Customization? Leave your comment now!
_____

If you are writing code, please wrap it like so: [php]code_here[/php]. Failure to complying with this, as well as going off topic or not using the English language will result in comment disapproval. You should expect a reply in about 2 weeks - this is a popular blog but I need to get paid work done first. Please consider joining the Business Bloomer Club to get quick WooCommerce support. Thank you!

Your email address will not be published. Required fields are marked *