WooCommerce 11.0 continues Checkout Recovery as a beta feature. The risky edge is not only eligibility. A scheduled job, a manual admin action, and a retry worker can all see the same abandoned checkout before the first send has written its completion state.
Use this for stores piloting checkout recovery with Action Scheduler, custom order statuses, mail retries, multiple web workers, or support staff who can trigger manual sends.
Quick answer
Create one synthetic abandoned checkout, pause the outbound mail layer, and release the scheduled job plus manual action inside the same minute. The test passes only when one durable idempotency record produces one provider message, one order note, and one customer email.
What to check first
- Create a synthetic eligible checkout and record its recovery identifier, order ID, scheduled action ID, recipient, eligibility state, and previous-send count.
- Pause outbound delivery or route it to a test inbox, then queue the scheduled job and prepare a manual send for the same record.
- Release both paths close together and capture worker timestamps, lock acquisition, database writes, action attempts, mail IDs, order notes, and provider events.
- Repeat with a temporary mail failure so the retry path overlaps a second manual action.
- Change the order to paid between eligibility evaluation and send, then prove the final guard blocks an outdated recovery message.
Diagnostic table
Use this table to keep the work practical. It connects the symptom to evidence and a verification step.
| Action | Evidence to collect | How to verify |
| Create one controlled order | Create a synthetic eligible checkout and record its recovery identifier, order ID, scheduled action ID, recipient, eligibility state, and previous-send count. | Only one provider message ID exists for the recovery key. |
| Align competing triggers | Pause outbound delivery or route it to a test inbox, then queue the scheduled job and prepare a manual send for the same record. | The order or recovery record has one consistent send note and timestamp. |
| Capture lock evidence | Release both paths close together and capture worker timestamps, lock acquisition, database writes, action attempts, mail IDs, order notes, and provider events. | A retry does not create a second message after the original later succeeds. |
| Repeat with retry | Repeat with a temporary mail failure so the retry path overlaps a second manual action. | An order paid before delivery does not receive the recovery email. |
Why this usually happens
- Eligibility can be checked before another worker records that a send started.
- A retry queue may use a different identifier than the manual admin path.
- Database locks can expire before a slow email provider returns.
- Status changes between scheduling and execution can make a once-valid message inappropriate.
Useful command or data shape
Adapt paths, IDs, and privacy handling to the site before running commands or storing data on production.
case_id: REC-RACE-11
order_id: 18422
recovery_key: rec_18422_v1
scheduled_action: 90881
manual_action_at: 2026-07-21T11:45:05Z
worker_started_at: 2026-07-21T11:45:04Z
expected_provider_messages: 1
Safe fix order
Do the work in a sequence that makes each result easy to prove. Stop if a step produces new evidence that changes the incident scope.
- Create one controlled order
- Align competing triggers
- Capture lock evidence
- Repeat with retry
- Retest a paid transition
Decision rule
Use one stable recovery key across scheduled, manual, and retry paths. Recheck status and suppression immediately before delivery, and make the send state durable enough that a second worker can see it.
What to tell the client or owner
Provide the order and recovery IDs, trigger timestamps, worker IDs, Action Scheduler rows, lock state, mail IDs, provider events, status transitions, order notes, and final inbox count.
Production verification checklist
- Only one provider message ID exists for the recovery key.
- The order or recovery record has one consistent send note and timestamp.
- A retry does not create a second message after the original later succeeds.
- An order paid before delivery does not receive the recovery email.
Mistakes to avoid
- Do not count button clicks as delivered messages.
- Do not test only with a single PHP worker.
- Do not use different recipient aliases that hide a duplicate-send defect.
- Do not skip the paid-between-check-and-send case.
Questions teams ask during testing
Is an Action Scheduler claim enough to prevent duplicates?
Not by itself. A manual path or provider retry may not share the same claim. Verify the durable send key across every entry point.
Should the store automatically retry every mail failure?
Retry only failures classified as temporary, and use the same idempotency key. A timeout can occur after a provider accepted the message, so status reconciliation matters.
When HandL WP should help
HandL WP can trace duplicate recovery emails through WooCommerce, Action Scheduler, custom status filters, and the mail provider, then test the idempotency guard under real concurrency.
If this is active on a production site, stop duplicate WooCommerce recovery emails.
Related HandL WP guides
Use these related guides when the same issue touches tracking, security, checkout, or crawler visibility.
Helpful references