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
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.
Step 2: Open the email log
Go to WooCommerce, then Status, then Logs. Under "Browse log files", open the "All sources" dropdown, choose
transactional-emailsand select Filter. Open the file for the day of the order. Each line names the email, the order and what happened.new_orderis "New order", the store's notice.customer_processing_orderis "Processing order", the customer's confirmation.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 beginsEmail "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.
grep -h "order #123 " wp-content/uploads/wc-logs/transactional-emails-*.logA line looks like this:
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 order | What happened | Which fix |
|---|---|---|
sent | WooCommerce 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 disabled | The email is switched off. | "Switch the email on" |
not sent: no_recipient | There 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.
- Browser
- DNS
- HTTPS
- CDN or firewall
- Web server
- PHP
- WordPress (this error comes from here)
- Database and files
What causes it
The order never reached a status that sends an email
CommonOrder emails are sent when an order changes status. An order still in "Pending payment" has been placed and not paid, and no email belongs to that status.
The site cannot send mail at all
CommonWooCommerce hands each email to WordPress, which hands it to the server's mail program. Where that program is missing or restricted, every email from the site fails, not only order emails.
Fix: Repair the site's mail, or Send again the emails that were missed
The email was sent and then filtered as spam
CommonA message sent by a web server, from an address at a domain that does not vouch for that server, looks forged. Receiving servers put it in spam or refuse it.
Fix: Send from an address at your own domain, or Add the DNS records that vouch for your mail
The email is switched off in WooCommerce
CommonEach email has its own "Enable this email notification" box. With the box unticked, WooCommerce records the email as disabled and sends nothing.
Fix: Switch the email on, or Send again the emails that were missed
The email goes to the wrong address, or has no valid one
CommonThe store's notices go to the addresses in each email's "Recipient(s)" box, or to the site's administration address when the box is empty. A customer's email goes to the billing address on the order.
Fix: Correct who receives the email, or Send again the emails that were missed
A plugin or custom code stops the email
SometimesCode in a plugin, the theme or a must-use plugin can unhook an email from the status change that sends it, switch it off through a filter, or empty its recipient.
Fix: Find the plugin or code that stops the email, or Send again the emails that were missed
A copy of an email template in the theme is broken
SometimesA theme can replace WooCommerce's email templates with its own copies. A copy that calls something WooCommerce no longer has stops PHP while the email is being built.
Fix: Take a broken email template out of the theme, or Send again the emails that were missed
Emails are deferred and the queue is not running
RareWith "Deferred emails" on, the emails for each change of status wait as a task in Action Scheduler. If nothing runs that queue, they stay there.
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.
| Sent when the order moves | |
|---|---|
| "New order", to the store | From "Pending payment", "Failed" or "Cancelled" to "Processing", "On hold" or "Completed" |
| "Processing order", to the customer | To "Processing" from "Pending payment", "On hold", "Failed" or "Cancelled" |
| "Order on-hold", to the customer | To "On hold" from "Pending payment", "Failed" or "Cancelled" |
| "Completed order", to the customer | To "Completed" |
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.
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
sentline for each.
With WP-CLI, list the orders that are waiting:
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.
wp wc shop_order update 123 --status=processing --user=1It 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.
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.
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.
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.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:
wp option get woocommerce_email_from_addressThen change it, with your own address in place of the example:
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.
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.
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
Step 1: Open the email's settings
Go to WooCommerce, then Settings, then Emails, and select Manage beside the email that is missing.
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:
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"; }'new_order | New order | off | admin@example.com
customer_processing_order | Processing order | on | customerAn email marked manual is only ever sent by hand. To switch one on, put its id into the option's name. For "New order":
wp option patch update woocommerce_new_order_settings enabled yesError: 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.
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.
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.
Step 3: For a customer's email, check the order
A customer's email goes to the billing email address on the order.
no_recipientthere 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":
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.
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 inWC_Email_New_Order.bashgrep -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/"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.
bashwp plugin deactivate plugin-slugStep 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.
Step 1: Read the fatal error
Go to WooCommerce, then Status, then Logs, and open the newest
fatal-errorslog. Find the entry made when the order changed status. A path through a theme'swoocommerce/emails/folder names the template at fault.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".
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.
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:
cat wp-content/uploads/wc-logs/fatal-errors-*.log | tail -n 1 | cut -c 1-300List the email templates that themes replace:
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:
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.
Step 1: Look at the queue
Go to WooCommerce, then Status, then Scheduled Actions. Search for
woocommerce_send_queued_transactional_emailand look under Pending. Each row whose scheduled date has passed holds emails that are waiting.Step 2: Run what is waiting
Choose "Run" on each pending row, then read the email log. The order now has its lines.
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.
wp option get woocommerce_feature_deferred_transactional_emails_enabledList the tasks that are waiting:
wp action-scheduler action list --hook=woocommerce_send_queued_transactional_email --status=pendingRun them:
wp action-scheduler run --hooks=woocommerce_send_queued_transactional_emailIt 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.
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.
Step 2: Check the result
The order's notes gain
Email "New order" sent.orEmail "Order details" sent., and the log gains asentline. In the log, "Order details" iscustomer_invoice.
With WP-CLI, these do what the two order actions do, for one order at a time. The store's notice:
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:
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.
- GuideWooCommerce variations and SEO: variation URLs, canonical links and the price in structured data
- Glossary termAction Scheduler
- GuideHow to maintain a WooCommerce store: before every update, every week, every month and before a sale
- GuideHow to migrate from Shopify to WooCommerce
- GuideHow to set up WooCommerce email notifications
- GuideHow to speed up a WooCommerce store

