Verze: 1.0 Datum: 29. 6. 2026 Oblast: WordPress / WooCommerce, doručování transakčních e-mailů Závažnost: střední (provozní – část zákazníků nedostane notifikaci)
Při hromadné změně stavu velkého počtu objednávek (100+) na stav „Dokončeno"
se WooCommerce pokouší odeslat zákaznickou notifikaci o dokončení objednávky pro
každou objednávku. Všechna volání wp_mail() proběhnou synchronně v rámci
jediného HTTP requestu, prakticky v jeden okamžik. Poskytovatel hostingu tento
nárazový tok vyhodnotí jako potenciální zneužití (spam burst) a z bezpečnostních
důvodů funkci odchozí pošty dočasně zablokuje / rate-limituje.
Důsledkem je, že část zákazníků e-mail nedostane, request může spadnout do timeoutu a chování je nedeterministické (záleží, kdy limit hostingu „spadne").
Doporučené řešení: odpojit synchronní odesílání a notifikace zařadit do rate-limitované fronty (Action Scheduler) s pevným odstupem mezi e-maily. Dlouhodobě navíc přejít na externí transakční SMTP/API službu.
| Aspekt | Pozorování |
|---|---|
| Spouštěč | Hromadná akce v adminu: Objednávky → vybrat 100+ → Změnit stav na „Dokončeno" |
| Projev | Část e-mailů se neodešle; v logu hostingu/MTA chyby typu rate-limit / „too many connections" / dočasné odmítnutí |
| Práh | Závisí na limitu hostingu (typicky desítky e-mailů za minutu na sdíleném hostingu) |
| Reprodukovatelnost | Vysoká při dostatečném počtu objednávek v jedné dávce |
Při změně stavu objednávky proběhne uvnitř jednoho requestu řetězec:
WC_Order::update_status('completed')
└─ status_transition()
└─ do_action('woocommerce_order_status_completed', $order_id, $order)
└─ WC_Emails::send_transactional_email()
└─ do_action('woocommerce_order_status_completed_notification', …)
└─ WC_Email_Customer_Completed_Order::trigger()
└─ ->send()
└─ wp_mail() ← skutečné odeslání
Při hromadné akci se tento řetězec provede N-krát za sebou v témže PHP procesu.
Mezi jednotlivými wp_mail() není žádná prodleva ani dávkování.
Příčina tedy není v hostingu jako takovém – ten se chová správně. Problém je, že aplikace generuje neregulovaný burst, který do bezpečnostního limitu naráží.
max_execution_time).| # | Řešení | Tvrdý strop/min | Odpojení od requestu | Náročnost | Poznámka |
|---|---|---|---|---|---|
| A | Filtr woocommerce_defer_transactional_emails |
✗ | ✓ | velmi nízká | Jednořádek; dávky AS ale stále mohou poslat ~25 najednou |
| B | Vlastní rate-limitovaná fronta (Action Scheduler) | ✓ | ✓ | nízká–střední | Doporučeno – pevný odstup mezi e-maily |
| C | Externí transakční SMTP/API (SES, Mailgun, Brevo…) | ~ | ✗* | střední | Obejde limit hostingu, zlepší deliverability; *bez fronty pořád burst |
| D | Menší dávky ručně | ✗ | ✗ | nulová | Obejití, ne řešení; lidská chyba |
| E | Hotový plugin třetí strany | dle pluginu | dle pluginu | nízká | Závislost navíc, různá kvalita |
add_filter( 'woocommerce_defer_transactional_emails', '__return_true' );
WooCommerce e-maily zařadí jako asynchronní akce Action Scheduleru → odpojí je od requestu hromadné akce. Omezení: Action Scheduler zpracovává dávky (default ~25 akcí na běh), takže při jednom běhu cronu může odejít několik desítek e-mailů téměř naráz. Negarantuje tedy strop „X e-mailů za minutu" a u přísného limitu hostingu nemusí stačit.
Princip:
Counter dalšího slotu se sám „uzdravuje" (max(now, next_slot)), takže po vyprázdnění
fronty se tempo resetuje na aktuální čas.
Referenční implementace je v přiloženém mu-pluginu wc-mail-throttle.php.
Tempo se ladí filtrem:
add_filter( 'wcmt_interval_seconds', function () { return 12; } ); // 5/min
Napojení na Amazon SES / Mailgun / Brevo / SendGrid přesune odchozí poštu mimo
lokální sendmail hostingu, čímž odpadne jeho bezpečnostní blok a výrazně se zlepší
doručitelnost. Ale: samotný přechod neřeší burst – každé wp_mail() při bulku
proběhne dál synchronně (u SMTP dokonce pomaleji kvůli handshake). I providers mají
rate-limity (často per-second). Proto se varianta C kombinuje s frontou (B).
Primárně: nasadit variantu B (rate-limitovaná fronta) – řeší jádro problému deterministicky a bez závislosti na třetích stranách.
Sekundárně / dlouhodobě: přejít na variantu C (externí transakční SMTP/API) pro lepší doručitelnost a odolnost, ponechat frontu z B jako regulátor tempa.
Variantu A lze použít jako okamžitou úlevu, než se nasadí B.
Frontu vyprazdňuje Action Scheduler nad WP-Cronem, který se spouští jen při návštěvě stránky. Pro spolehlivé tempo:
Vypnout WP-Cron ve wp-config.php:
define( 'DISABLE_WP_CRON', true );
Nastavit systémový cron (každou minutu), např. přes WP-CLI:
* * * * * cd /cesta/k/webu && wp action-scheduler run >/dev/null 2>&1
nebo HTTP variantou:
* * * * * wget -q -O - "https://web.tld/wp-cron.php?doing_wp_cron" >/dev/null 2>&1
Bez spolehlivého cronu throttling funguje, ale fronta se vyprazdňuje jen nárazově.
interval = 12 s ⇒ 5 e-mailů/min ⇒ 300/h. Hodnotu nastavit podle reálného limitu
hostingu (vyžádat si od podpory přesné číslo odchozích zpráv za minutu/hodinu).
Stejnou logiku lze použít i pro „Zpracovává se", „Vráceno" apod. – v detach_default
odpojit příslušnou e-mailovou třídu (WC_Email_Customer_Processing_Order, …) a přidat
hook na její _notification. Sdílení jednoho slot counteru zajistí, že se rate-limit
počítá globálně napříč typy e-mailů.
| Co sledovat | Kde |
|---|---|
| Stav fronty (pending/complete/failed), rozestupy | WooCommerce → Status → Scheduled Actions, skupina wcmt |
| Skutečné odeslání | Log MTA / hostingu, příp. log transakční služby |
Chyby wp_mail |
Vlastní logování v wp_mail_failed hooku |
| Timeout hromadné akce | PHP error log (max_execution_time) – po nasazení B by měl zmizet |
Doporučený test: na staging spustit hromadnou změnu 100+ objednávek a ověřit, že e-maily ve frontě odcházejí v očekávaném tempu a všechny dojdou.
detach_default.max(now, next); po vyprázdnění se resetuje.array( $order_id )), ne asociativním.Problém vzniká neregulovaným nárazovým odesíláním transakčních e-mailů v rámci jednoho requestu, který naráží na bezpečnostní limit hostingu. Nejde o chybu hostingu, ale o chybějící regulaci tempa na straně aplikace. Nasazením rate-limitované fronty (varianta B) se odesílání odpojí od requestu a rozloží do deterministicky řízeného tempa; dlouhodobě je vhodné doplnit externí transakční službu (varianta C) pro doručitelnost a odolnost. Tím se chování stane stabilním a předvídatelným.
wc-mail-throttle.php – referenční mu-plugin (rate-limitovaná fronta, varianta B)