Přeskočit obsah
V
Pro vývojáře
Architektura, konvence, jádro systému a bezpečnost
Jádro / Odesílání e-mailů

Odesílání e-mailů#

E-mail se v tomhle systému nikdy neposílá přímo z presenteru. Manager zavolá jednu ze tří metod z SendEmailTrait, ta zprávu sestaví a podle nastavení ji buď zařadí do fronty, nebo odešle hned. Frontu pak rozesílá cron.

Kód: app/Core/Traits/Api/System/Models/Managers/SendEmailTrait.php (Api varianta) a app/Core/Traits/Shared/System/Models/Managers/SendEmailTrait.php (sdílená).

Tři metody#

Metoda Kdy ji použít
sendEmail($langId, $emailKey, $to, $values, …) výchozí volba — šablona z databáze podle klíče, v jazyce příjemce
sendEmailFromText($subject, $body, $from, $to, $values, …) text sestavený v kódu; šablona v databázi neexistuje
sendEmailToAll($emailKey, $recipients, $values, …) hromadné rozeslání téže šablony více příjemcům

Všechny berou $values (zástupné texty do šablony), $files (přílohy) a $replyTos.

Adresa pro odpověď se hodí tam, kde má příjemce psát někomu jinému než systému

Typicky u odpovědi na inzerát: zprávu odešle systém, ale odpovědět se má inzerentovi.

Kam zpráva jde: nastavení 1/emailSending#

Tohle je jediné místo, které rozhoduje mezi frontou a okamžitým odesláním:

Hodnota Chování
1 všechno do fronty (výchozí)
2 do fronty jen nepřednostní; přednostní odchází okamžitě
jinak vše se odesílá okamžitě, fronta se nepoužije

Proč vůbec fronta

Odeslání trvá vteřiny. Objednávka posílající dva e-maily by se odbavovala znatelně déle — a při výpadku poštovního serveru by spadla celá. Takhle jen počká zpráva.

Přednostní zpráva má smysl jen u režimu 2

Příznak preferred odlišuje potvrzení registrace nebo obnovu hesla od hromadné rozesílky. Při emailSending: 1 jde do fronty i ta — a předběhne newsletter až tam, ne dřív.

Fronta#

Entita EmailQueue nese příjemce, odesílatele, předmět, tělo, přílohy, adresy pro odpověď a k tomu provozní pole:

Pole Význam
sent, sendDatetime odesláno a kdy
attempts počet pokusů
errorLog poslední chyba
preferred přednost před hromadnou rozesílkou
stopped ruční zastavení — zpráva se nebude zkoušet dál
newsletter vazba na rozesílku, když jde o newsletter

Rozesílá cron /cron/system/email-queue/sendà minutu.

Bez běžícího cronu neodejde nic a nikdo se to nedozví

Fronta jen roste. Uživatel neuvidí chybu, protože z pohledu aplikace se odeslání povedlo — zpráva se přece uložila. Po nasazení proto ověřte, že úloha běží, a pak to ověřte znovu.

Newsletter je záměrně pomalý

Tisíce zpráv během vteřiny vypadají poštovním serverům jako spam. Dávkování je ochrana reputace domény, ne nedodělek.

Šablony#

Šablony jsou v databázi, klíčované řetězcem, s textem pro každý jazyk zvlášť a zástupnými texty, které se nahradí z $values.

Klíč šablony se nepřejmenovává

Kód si šablonu hledá právě podle něj (findBy([new EqualFilter(['key'], [$emailKey])])). Po přejmenování sendEmail() šablonu nenajde, vrátí neúspěch — a protože se návratová hodnota často nekontroluje, zpráva prostě přestane chodit.

Chybějící překlad šablony znamená e-mail v jiném jazyce, ne chybu

Text se hledá pro $langId příjemce. Není-li, použije se fallback — příjemce dostane zprávu v hlavním jazyce.

Postup: přidávám nový e-mail#

  1. Založ šablonu v administraci (Systém → E-maily) a dej jí klíč, který už neexistuje.
  2. Vyplň text pro všechny jazyky — ne jen pro hlavní.
  3. Zavolej sendEmail() z manageru, ne z presenteru:
$this->sendEmail(
    langId: $user->getLanguageId(),
    emailKey: 'order.confirmation',
    toEmailAddrr: $order->getEmail(),
    values: ['orderNumber' => $order->getNumber()],
);
  1. Volej to z completedSave / completedDelete, tedy až po commitu.
  2. Vyhodnoť výsledek — neúspěch znamená, že se zpráva ani nezařadila do fronty.
  3. Ověř na vývojovém stroji, kam zpráva doopravdy odešla (viz níž).

E-mail v afterSave odejde i tehdy, když se transakce vrátí zpět

afterSave běží uvnitř transakce. Zpráva o vzniklé objednávce se odešle, objednávka se rollbackne — a zákazník má v ruce potvrzení něčeho, co neexistuje. Nevratné efekty patří za commit, viz Životní cyklus manageru.

V cronu se pole NEfiltrují podle publika

Rozesílka běží mimo požadavek, takže #[FieldAccess] se neuplatní — a je to záměr, aktivační e-mail potřebuje activationKey. Znamená to ale, že co se dostane do těla zprávy, si musí ohlídat autor šablony a $values.

Vývojové prostředí#

Dev a produkce sdílejí databázi

Zkušební rozesílka může dorazit skutečným zákazníkům. Než něco odešlete, ověřte hodnotu 1/emailSending a obsah fronty — a u hromadné rozesílky raději zkontrolujte i seznam příjemců.

Kam sáhnout#

Chci Kde
tři metody odesílání app/Core/Traits/Api/System/Models/Managers/SendEmailTrait.php
rozhodnutí fronta × okamžitě app/Core/Traits/Shared/System/Models/Managers/SendEmailTrait.php
entitu fronty app/Core/Base/Shared/System/Models/Entities/EmailQueue.php
rozesílací cron app/UI/Cron/System/Presenters/EmailQueuePresenter.php
správu šablon administrace → Systém → E-maily

Navazující kapitoly: Životní cyklus manageru · Cron presentery · Naplánované úlohy · Překlady