Skip to content

How to fix WooCommerce not sending order emails

Either WooCommerce never sent the email, or it sent it and the message did not arrive. Its own log of order emails says which. From there the cause is an unpaid order, an email switched off, a wrong recipient, a site that cannot send mail, a spam filter, or code that stops the email.

By
WP Ministry
Published
Tested on
WordPress 7.1.3, WooCommerce 11.2.0, PHP 8.3.35

In short

  • Read the transactional-emails log under WooCommerce, then Status, then Logs, before changing anything. It records each order email as sent, failed, disabled or skipped.
  • "Sent" means WooCommerce handed the message to the site's mail system. From there it is a delivery problem, not a WooCommerce one.
  • An order in "Pending payment" sends no email. "New order" and "Processing order" go out when the order leaves that status.
  • "Failed to send" means the site itself cannot send mail. No WooCommerce setting fixes that.
  • No log entry for a paid order points to a stuck queue, a broken email template in the theme, or code that removes the email.
  • An email that was not sent is not sent later. Send it again from the order once the cause is fixed.

When order emails go missing, one of two things has happened. Either WooCommerce never sent the email, or it sent it and the message did not arrive. The two look the same from an inbox and are fixed in different places. WooCommerce keeps a log of every order email it tries to send, and that log tells you which one you have.

No order is lost either way: orders stay under WooCommerce, then Orders, whether or not an email went out. An email that was not sent is not sent later, though, so once the cause is fixed you send the missed ones again yourself.

Find out whether the email was sent

  1. Step 1: Check that the order exists, and note its status

    Go to WooCommerce, then Orders. If the order is not there, no email was due and the fault is in the checkout: see WooCommerce checkout not working, or the checkout-down runbook if nobody can buy.

  2. Step 2: Open the email log

    Go to WooCommerce, then Status, then Logs. Under "Browse log files", open the "All sources" dropdown, choose transactional-emails and select Filter. Open the file for the day of the order. Each line names the email, the order and what happened. new_order is "New order", the store's notice. customer_processing_order is "Processing order", the customer's confirmation.

  3. Step 3: Or read the order's notes

    For an email that was sent or that failed, WooCommerce also adds a private note in the order's "Order notes" panel: Email "New order" sent., or a note that begins Email "Processing order" failed to send:. An email that was switched off or skipped is recorded in the log only.

With WP-CLI, run this from the site's folder with the order's number in place of 123. The space after the number keeps order 123 from matching order 1234.

bash
grep -h "order #123 " wp-content/uploads/wc-logs/transactional-emails-*.log

A line looks like this:

text
2026-10-08T02:51:09+00:00 INFO Email "customer_processing_order" for order #123 sent CONTEXT: {"email_type":"customer_processing_order","status":"sent","recipient":"guest","order":123}

The log never shows an email address. recipient is the WordPress username the address belongs to, or guest when no account has it.

What the log says for the orderWhat happenedWhich fix
sentWooCommerce handed the message to the site's mail system, which accepted it."Send from an address at your own domain", then "Add the DNS records that vouch for your mail". For a store notice, try "Correct who receives the email" first.
failed to send, then a reason such as Could not instantiate mail function.The site's mail system returned an error."Repair the site's mail"
not sent: email type is disabledThe email is switched off."Switch the email on"
not sent: no_recipientThere was no valid address to send to."Correct who receives the email"
Nothing, and the order is "Pending payment" or "Draft"No email belongs to that status."Check the order's status"
Nothing, and the order is "Processing", "On hold" or "Completed"WooCommerce never got as far as sending."Find the plugin or code that stops the email", "Take a broken email template out of the theme", "Run the queue of deferred emails"

If there is no transactional-emails log at all, the store may be older than WooCommerce 10.9, which added it: update WooCommerce and look again after the next order. Otherwise select Settings beside Browse on the Logs screen. "Enable logging" has to be ticked, and "Level threshold" must not sit above Info: sent emails are logged at Info, disabled and skipped ones at Notice, failed ones at Warning. With "Log storage" set to the database, the screen lists the entries and the WP-CLI command finds no files.

What "sent" proves

WooCommerce sends through WordPress's wp_mail() function, and WordPress's reference says a successful result means the request was processed without an error, not that the message was received. So sent ends WooCommerce's part and says nothing about the inbox.

The fixes below that are shown as tested have the same limit. The test site's mail program is a stand-in that accepts every message and keeps it. A passing test shows that WooCommerce handed the message over, to which address and from which, and not that it reached an inbox.

Where it goes wrong

A page request passes through each of these in turn. This one comes from a plugin.

  1. Browser
  2. DNS
  3. HTTPS
  4. CDN or firewall
  5. Web server
  6. PHP
  7. WordPress (this error comes from here)
  8. Database and files

What causes it

How to fix it

Check the order's status

  • Easy
  • Low risk
  • About 10 minutes
  • Steps tested on WordPress 7.1.3

Order emails are sent by a change of status, not by the order being created. An order in "Pending payment" has been received and not paid, and while it stays there no email is sent. WooCommerce's troubleshooting guide puts this check first.

EmailSent when the order moves
"New order", to the storeFrom "Pending payment", "Failed" or "Cancelled" to "Processing", "On hold" or "Completed"
"Processing order", to the customerTo "Processing" from "Pending payment", "On hold", "Failed" or "Cancelled"
"Order on-hold", to the customerTo "On hold" from "Pending payment", "Failed" or "Cancelled"
"Completed order", to the customerTo "Completed"
  1. Step 1: Look for the payment at your payment provider

    If there is no payment, nothing is wrong with email: the customer left the payment page or the card was declined. If the payment is there, the order was never updated, which usually means the provider's confirmation did not reach the store. That is a payment fault, and WooCommerce payment gateway errors covers it.

  2. Step 2: Move a paid order on by hand

    Do this only for an order whose payment you have seen at the provider, because it emails the customer. Open the order, set "Status" to "Processing" and select Update. WooCommerce sends "New order" and "Processing order", and the log gains a sent line for each.

With WP-CLI, list the orders that are waiting:

bash
wp wc shop_order list --status=pending --user=1 --fields=id,status,date_created,total

--user=1 runs the command as the user with ID 1, usually the first administrator. WooCommerce's commands refuse to run without an account that may manage the shop.

Then move one paid order on. This sends both emails at once.

bash
wp wc shop_order update 123 --status=processing --user=1

It answers Success: Updated shop_order 123.

To undo it: Set the status back on the order's screen. An email that has gone out cannot be recalled.

Repair the site's mail

  • Takes care
  • Low risk
  • About 30 minutes

failed to send means WooCommerce built the email and the site's mail system refused it. The reason after the colon comes from WordPress or the mail service. Could not instantiate mail function. means PHP could not hand the message to a mail program on the server. No setting inside WooCommerce changes that.

  1. Step 1: Confirm that it is not only order emails

    Password resets and form messages leave the site the same way. How to fix WordPress not sending email has a two-minute test that shows whether WordPress can hand any message over.

  2. Step 2: Send through a mail service

    The same page has the fix: a mail service that takes each message from WordPress and delivers it from servers set up for the job. When its test message goes through, use "Send again the emails that were missed" below.

Send from an address at your own domain

  • Easy
  • Low risk
  • About 10 minutes
  • Steps tested on WordPress 7.1.3

When the log says sent and the customer has nothing, ask them to look in their spam folder. Then look at who the email claims to be from. WooCommerce's documentation says a store email with a free webmail address as its sender is likely to land in spam or be blocked, because that provider's servers did not send it.

  1. Step 1: Set the "From" address

    Go to WooCommerce, then Settings, then Emails, and find "Email sender options" under the list of emails. In "From" address, enter an address at the store's own domain, such as orders@example.com. Use a mailbox someone reads, because customers reply to it. Select Save changes.

  2. Step 2: Check the mail plugin too

    An SMTP plugin can have a sender setting of its own that replaces this one. WooCommerce's documentation says to review it as well.

With WP-CLI, read the address in use:

bash
wp option get woocommerce_email_from_address

Then change it, with your own address in place of the example:

bash
wp option update woocommerce_email_from_address 'orders@example.com'

The test for this fix shows the new address on the next message WooCommerce hands over. How a mailbox provider treats that message depends on the next fix.

To undo it: Put the old address back and save.

Add the DNS records that vouch for your mail

  • Takes care
  • Low risk
  • About 30 minutes

A receiving server checks that a message claiming to come from your domain was sent by a server your domain names. SPF, DKIM and DMARC records carry that information. Google's sender guidelines require SPF or DKIM from everyone who sends to Gmail accounts, and say that mail without authentication may be marked as spam or rejected.

  1. Step 1: Get the records from whoever sends the store's mail

    That is the mail service you connected, or your host if mail leaves through its own system.

  2. Step 2: Add them and check a message

    How to fix WordPress not sending email has the steps: where the records go, a DMARC record to start with, and how to read the result in a message's headers.

Switch the email on

  • Easy
  • No risk
  • About 5 minutes
  • Steps tested on WordPress 7.1.3
  1. Step 1: Open the email's settings

    Go to WooCommerce, then Settings, then Emails, and select Manage beside the email that is missing.

  2. Step 2: Tick "Enable this email notification"

    It is the box beside "Enable/Disable". Select Save changes. The next order's line in the log should say sent.

With WP-CLI, this lists every email with its id, its name, whether it is on, and who receives it:

bash
wp eval 'foreach ( WC()->mailer()->get_emails() as $email ) { echo $email->id, " | ", $email->get_title(), " | ", $email->is_manual() ? "manual" : ( $email->is_enabled() ? "on" : "off" ), " | ", $email->is_customer_email() ? "customer" : $email->get_recipient(), "\n"; }'
text
new_order | New order | off | admin@example.com
customer_processing_order | Processing order | on | customer

An email marked manual is only ever sent by hand. To switch one on, put its id into the option's name. For "New order":

bash
wp option patch update woocommerce_new_order_settings enabled yes

Error: No data exists for key "enabled" means that email's settings were never saved, so it is on its default. If the list still says off when the setting says yes, code is switching the email off: go to "Find the plugin or code that stops the email".

To undo it: Untick the box and save.

Correct who receives the email

  • Easy
  • No risk
  • About 5 minutes
  • Steps tested on WordPress 7.1.3

"New order", "Cancelled order" and "Failed order" go to the store. A valid address that is the wrong one, such as the mailbox of whoever built the site, still shows as sent in the log. A mistyped address that is no longer valid shows as not sent: no_recipient.

  1. Step 1: Check the store's recipients

    Go to WooCommerce, then Settings, then Emails, and select Manage beside the email. Enter the addresses that should get it in "Recipient(s)", separated by commas, and select Save changes.

  2. Step 2: If the box is empty

    The email goes to the site's administration email address, under Settings, then General. How to fix WordPress not sending email shows how to change that address.

  3. Step 3: For a customer's email, check the order

    A customer's email goes to the billing email address on the order. no_recipient there means the order has none, which can happen with an order added by hand. Add the address to the order's billing details, select Update, then send the email again as described below.

With WP-CLI, the list in "Switch the email on" shows each store email's recipients. To set them for "New order":

bash
wp option patch update woocommerce_new_order_settings recipient 'orders@example.com'

If it answers Error: No data exists for key "recipient", the settings were never saved: set the address on the email's screen.

To undo it: Put the old address back and save.

Find the plugin or code that stops the email

  • Takes care
  • Back up first
  • About 30 minutes
  • Steps tested on WordPress 7.1.3

A paid order that changed status and left no line in the log points to code. So does a log that says an email is disabled while its box is ticked. WooCommerce publishes a snippet for developers that unhooks its emails, and filters can switch an email off or empty its recipient. Such code sits in a plugin, in the theme's functions.php or in a must-use plugin.

  1. Step 1: Search the site's code

    Each line of the result gives a file and a line number. A match is a line to read, not a verdict: an extension may adjust its own emails this way. Look for the missing email's id, as in woocommerce_email_enabled_new_order, or its class, as in WC_Email_New_Order.

    bash
    grep -rnE "remove_action.*_notification|woocommerce_email_enabled_|woocommerce_email_recipient_|woocommerce_email_actions" wp-content/mu-plugins wp-content/themes wp-content/plugins 2>/dev/null | grep -v "^wp-content/plugins/woocommerce/"
  2. Step 2: Switch the code off

    For a plugin, deactivate it, with the folder from the path in place of plugin-slug:

    For lines in a theme or a must-use plugin, ask whoever wrote them to take them out.

    bash
    wp plugin deactivate plugin-slug
  3. Step 3: If the search finds nothing

    It reads files only, so code that a snippets plugin keeps in the database is not seen. Use WooCommerce's own method instead. On a staging copy, switch to a default theme, deactivate every plugin except WooCommerce, place a test order and read the log. Then reactivate one at a time until the email stops. How to find and fix a WordPress plugin conflict has the full method.

To undo it: Reactivate the plugin.

Take a broken email template out of the theme

  • Takes care
  • Back up first
  • About 20 minutes
  • Steps tested on WordPress 7.1.3

A theme can replace an email template with a copy of its own, in its woocommerce/emails/ folder. WooCommerce updates its own templates and not the copies. A copy that is only out of date still sends. A copy that calls something WooCommerce no longer has stops PHP while the email is being built: the order has changed status, the email is not sent, and the email log has no line for it.

  1. Step 1: Read the fatal error

    Go to WooCommerce, then Status, then Logs, and open the newest fatal-errors log. Find the entry made when the order changed status. A path through a theme's woocommerce/emails/ folder names the template at fault.

  2. Step 2: See which templates the theme replaces

    Go to WooCommerce, then Status, and scroll to "Templates". "Overrides:" lists each copy, and a stale one is marked, for example "Version 3.7.0 is out of date. The core version is 10.4.0".

  3. Step 3: Move the copy out of the theme

    Take a backup first. Then move the file out of the site's folder, keeping it so that its changes can be redone later. WooCommerce uses its own template from the next email on.

  4. Step 4: Have the copy brought up to date

    For the theme's own copy, update the theme or ask its author. For a copy of your own, copy WooCommerce's current template into the theme and redo your changes in it. How to update WooCommerce safely covers checking template copies before and after each update.

With WP-CLI, show the start of the newest fatal error:

bash
cat wp-content/uploads/wc-logs/fatal-errors-*.log | tail -n 1 | cut -c 1-300

List the email templates that themes replace:

bash
find wp-content/themes -path "*/woocommerce/emails/*.php"

Move the broken one to a folder in your home directory. Use the theme's folder in place of your-theme, and the file the error names:

bash
mkdir -p ~/email-template-copies && mv wp-content/themes/your-theme/woocommerce/emails/customer-processing-order.php ~/email-template-copies/

On our WooCommerce maintenance service, updates are tested on a staging copy first, and checkout and payment are tested after every update.

To undo it: Move the file back into the theme's woocommerce/emails folder.

Run the queue of deferred emails

  • Takes care
  • Low risk
  • About 15 minutes
  • Steps tested on WordPress 7.1.3

WooCommerce can send its emails in the background. This is off unless "Deferred emails" is ticked under WooCommerce, then Settings, then Advanced, then Features, or code turns it on through the woocommerce_defer_transactional_emails filter. Each change of status then leaves a task for Action Scheduler, the task queue inside WooCommerce, under the name woocommerce_send_queued_transactional_email. Until the task runs, its emails are not sent and nothing is logged.

Action Scheduler's documentation says the queue is started by WP-Cron and by requests in the dashboard. Where WP-Cron does not run, the emails wait until someone opens the dashboard.

  1. Step 1: Look at the queue

    Go to WooCommerce, then Status, then Scheduled Actions. Search for woocommerce_send_queued_transactional_email and look under Pending. Each row whose scheduled date has passed holds emails that are waiting.

  2. Step 2: Run what is waiting

    Choose "Run" on each pending row, then read the email log. The order now has its lines.

  3. Step 3: Make the queue run without you

    Get WP-Cron working: how to fix "Missed schedule" covers why it stops. WooCommerce database update required explains the Scheduled Actions screen. Or untick "Deferred emails" and save, and emails are sent as each order changes status.

With WP-CLI, see whether the feature is on. yes means it is.

bash
wp option get woocommerce_feature_deferred_transactional_emails_enabled

List the tasks that are waiting:

bash
wp action-scheduler action list --hook=woocommerce_send_queued_transactional_email --status=pending

Run them:

bash
wp action-scheduler run --hooks=woocommerce_send_queued_transactional_email

It prints Completed processing action for each task. The closing line can read Success: 0 scheduled tasks completed. even when actions ran, so go by those lines and by the email log.

To undo it: Nothing to undo. Running the queue sends the emails that were already waiting.

Send again the emails that were missed

  • Easy
  • Low risk
  • About 5 minutes
  • Steps tested on WordPress 7.1.3

WooCommerce does not try again by itself. Once the cause is fixed, send each missed email from its order.

  1. Step 1: Open the order and choose an action

    In the "Order actions" panel, open "Choose an action...". "Resend new order notification" sends the store's "New order" email again. "Send order details to customer" sends the customer the "Order details" email, which holds the order and, for an unpaid order, a link to pay. Select Update.

  2. Step 2: Check the result

    The order's notes gain Email "New order" sent. or Email "Order details" sent., and the log gains a sent line. In the log, "Order details" is customer_invoice.

With WP-CLI, these do what the two order actions do, for one order at a time. The store's notice:

bash
wp eval 'WC()->payment_gateways(); WC()->shipping(); add_filter( "woocommerce_new_order_email_allows_resend", "__return_true" ); WC()->mailer()->emails["WC_Email_New_Order"]->trigger( 123 );'

The customer's copy of the order:

bash
wp eval 'WC()->payment_gateways(); WC()->shipping(); WC()->mailer()->customer_invoice( wc_get_order( 123 ) );'

Neither prints anything. Read the order's lines in the log to see what happened.

To undo it: An email that has gone out cannot be recalled.

When to get help

If the log says "sent", the "From" address is at your own domain, SPF, DKIM and DMARC all pass and customers still report nothing, the answer is in the mail service's delivery log, read against your DNS records. If a paid order leaves no entry in the log and the queue, the templates and a search of the code turn up nothing, it takes someone who can trace one order through the code on a staging copy.

Common questions

The log says "sent" and the customer says nothing arrived. Whose problem is it?

It is a delivery problem. WooCommerce handed the message to the site's mail system, which accepted it. Ask the customer to check spam, then check the "From" address and the domain's SPF, DKIM and DMARC records. A mail service's delivery log shows whether the receiving server accepted the message.

The customer got a confirmation and the store got no "New order" email. Why?

They are separate emails with separate settings. Open "New order" with Manage and check that it is enabled and that "Recipient(s)" holds an address someone reads. Then read the log: not sent names the reason, and sent means the place to look is that mailbox's spam folder.

Will the missed emails go out once the cause is fixed?

No, with one exception. WooCommerce does not keep an email it could not send, so send each one again from its order. The exception is a deferred email still waiting in the queue, which goes out when the queue runs.

Can I test the emails without a real order?

In part. Under WooCommerce, then Settings, then Emails, "Send a test email" in the email preview shows that mail leaves the site. It does not show that an order changing status sends the right email. For that, place a test order on a staging copy and read the log: how to set up WooCommerce email notifications has the steps.

More on this subject

Would you rather we fixed it?

Quick Fix is $49. One issue, one site, up to about an hour. No fix, no fee. 30-day warranty. It starts with a free diagnosis.