Test that your WooCommerce order emails actually arrive
WooCommerce order emails are the most reliably broken transactional email on the web, and
the failure is silent by design: WordPress sends with wp_mail(), wp_mail() hands off to
PHP’s mail(), mail() hands off to whatever the host has configured, and every layer
reports success. The customer just never gets a receipt.
Nothing in the WordPress admin will tell you. The order is marked complete. The log, if there is one, says the mail was sent. It was — into a void, or into a spam folder, because the host’s IP has no SPF alignment with your domain.
Two ways to actually find out.
The quick way: send a real order email to a real inbox
Install the InboxDome Email Tester plugin and open Tools → Email Tester. It sends a genuine WooCommerce order-confirmation template to a temporary inbox and reports back:
- whether the message arrived at all, and how long it took
- what the customer would actually see
- the SPF, DKIM and DMARC results as the receiving server evaluated them
That last one is the part a local “test email” button can never tell you, and it is usually where the answer is. A store whose mail arrives but fails DMARC is one policy change at Gmail away from silently vanishing.
The thorough way: assert on it in CI
If you deploy the store, test the order email like any other critical path. Create an inbox, place an order against it, and assert on what comes back.
<?php
// A real address that will receive.
$inbox = json_decode(wp_remote_retrieve_body(wp_remote_post(
'https://inboxdome.com/v1/inboxes',
[
'headers' => [
'Authorization' => 'Bearer ' . getenv('INBOXDOME_KEY'),
'Content-Type' => 'application/json',
],
'body' => '{}',
]
)), true)['inbox'];
// … place an order with $inbox['emailAddress'] (WC_Order, WP-CLI, or a checkout run) …
Then assert — one call waits for the mail and checks every condition:
curl -X POST "https://inboxdome.com/v1/inboxes/$INBOX_ID/assert" \
-H "Authorization: Bearer $INBOXDOME_KEY" \
-H "Content-Type: application/json" \
-d '{
"timeoutSeconds": 60,
"assertions": [
{ "type": "containsText", "text": "Thank you for your order" },
{ "type": "containsText", "text": "Order #" },
{ "type": "auth", "check": "spf", "expect": "pass" },
{ "type": "auth", "check": "dkim", "expect": "pass" },
{ "type": "auth", "check": "dmarc", "expect": "pass" }
]
}'
{
"passed": false,
"arrived": true,
"arrivalSeconds": 4.2,
"results": [
{ "type": "containsText", "passed": true, "detail": "found" },
{ "type": "containsText", "passed": true, "detail": "found" },
{ "type": "auth", "passed": true, "detail": "spf=pass" },
{ "type": "auth", "passed": false, "detail": "dkim=none" },
{ "type": "auth", "passed": true, "detail": "dmarc=pass" }
]
}
That is the useful failure. The mail arrived, in four seconds, with the right content — and it is not DKIM-signed. Which means the moment the store’s volume gets a mailbox provider’s attention, receipts start going to spam. You would never have learned that from the order screen.
Give it 60 seconds rather than 30: WooCommerce sends order mail on a hook during checkout, and on a busy or cheap host that can queue behind other work.
What to test, in priority order
- The order confirmation arrives. Everything else is secondary.
- DKIM passes. This is the one that is most often quietly absent, and it is the one that gets a store’s mail filtered.
- The order number and total are in it. Catches a broken template that renders but loses its variables.
- Password reset arrives. A locked-out customer is a support ticket. See how to test a password reset email.
- The “new order” mail to the admin arrives. A store that has stopped notifying its owner of orders is a store losing orders.
Fix the usual cause first
If DKIM or SPF is failing, the fix is upstream of any test: stop sending through the host’s
mail() and send through a provider that signs your mail (SendGrid, Postmark, Mailgun, SES)
with an SMTP plugin. Then re-run the assertions and watch them turn green — which is the
point of having them.
See also: WordPress and WooCommerce guide · PHP client · API reference
Get a free API key — 50 inboxes a day, no card. Orgrab a temporary inbox without signing up at all.