E-maily idú cez mailové notifikácie Laravelu (TypedMailNotification) v jazyku príjemcu (HasLocalePreference::preferredLocale()).
Deduplikácia v rámci okna
Kľúč deduplikácie má rovnaké časti ako kľúč zlučovania v schránke, takže jedna položka schránky a jedno doručenie vždy patria k sebe:
- Leading (predvolené, notifications.mail.strategy) — prvá udalosť odošle e-mail hneď (alebo na konci tichých hodín); ďalšie udalosti v okne sa doň zlúčia a nič ďalšie neodošlú. Desať udalostí za päť minút → jeden e-mail.
- Trailing (mailStrategy(): MailStrategy::Trailing) — doručenie čaká prvú udalosť + okno; každá udalosť sa zlúči a odíde jeden e-mail s konečným počtom a najnovším obsahom.
- Urgentné druhy posielajú vždy hneď. E-mail, ktorý ešte neodišiel, pohltí ďalšie udalosti (Folded); odoslaný ich len spočíta (Deduplicated). Ak sa pred odoslaním zlúčilo viac udalostí, e-mail uvedie „a N ďalších aktualizácií“.
// Leading (default): the first event mails now; later ones in the window fold into it
Notifications::send('request.awaiting_approval', $request, $approver); // MailOutcome::Pending
Notifications::send('request.awaiting_approval', $request, $approver); // MailOutcome::Folded (or Deduplicated once sent)
// Trailing: one mail after the window, with the final count and the latest content
final class CommentPosted extends NotificationType
{
public function window(): ?string { return 'PT10M'; }
public function mailStrategy(): MailStrategy { return MailStrategy::Trailing; }
// …
}Životný cyklus doručenia
| Stav | Význam |
|---|---|
pending → sending → sent | Bežná cesta. DeliverMailJob prevezme riadok cez compare-and-set, takže opakovaná úloha ani druhý scheduler nič nepošle. |
held | Tiché hodiny — sweep ho uvoľní po ich skončení; pri doručení sa znova overí a ak medzitým začali tiché hodiny, znova sa podrží. |
digest | Odložené do súhrnu používateľa. |
cancelled | recipient_gone, unknown_type, subject_gone, no_access, muted (okrem povinných), revoked — overuje sa tesne pred odoslaním. |
failed | render (háčik druhu vyhodil výnimku — nahlásené, bez opakovania), transport (po mail.max_attempts s mail.backoff medzi pokusmi), unknown (po mail.lease sa stále odosiela — nikdy sa nepošle znova). |
undeliverable | no_address — resolver vrátil null alebo príjemca nemá trasu pre e-mail. |
Adresa sa určí ešte pred mailovým kanálom Laravelu: nakonfigurovaný resolver adries, inak routeNotificationFor('mail'). Pri vypnutom notifications.queue.enabled beží úloha priamo po commite; inak sa odošle na notifications.queue.connection / queue. Udalosti: NotificationMailSent, NotificationMailFailed, NotificationMailHeld.
Vykreslenie
Predmet = title(); oslovenie (s menom príjemcu, ak ho má); prvý riadok = body() (inak nadpis); „a N ďalších aktualizácií“ pri zlúčení; tlačidlo akcie (url() + actionText(), len absolútne http(s)); pätička — upozornenie na povinnosť pri povinných druhoch, inak odkaz na preferencie, ak je nastavené notifications.mail.preferences_url (URL alebo názov route); nakoniec háčik mail($message, $payload) druhu. Text ide cez markdown šablónu Laravelu, ktorá ho escapuje. V teste aplikácie to overíte takto:
use Illuminate\Support\Facades\Notification;
use RoundlyConsulting\Notifications\Mail\TypedMailNotification;
Notification::assertSentTo($user, TypedMailNotification::class, fn ($n) => $n->type === 'security.alert'
&& $n->message->subject === 'Security alert');Minimálny e-mail pre citlivé subjekty
Ak sensitive($subject) druhu vráti true a notifications.mail.minimal_for_sensitive je zapnuté (predvolené), e-mail obsahuje len minimalTitle() („New notification from :app“), jeden riadok a tlačidlo — body() ani mail() sa nevolajú. Riadky citlivých položiek v súhrne používajú tiež minimálny text. Schránky sa to netýka: je za vaším prihlásením.
Resolver adries
notifications.mail.address_resolver určuje ResolvesMailAddress, ktorý rozhodne o adrese každého e-mailu balíka — typovaných aj súhrnov; pri súhrne je payload null. Reťazec pošle na danú adresu; null označí doručenie ako undeliverable (súhrn zlyhá ako no_address). S contacts-for-laravel idú e-maily na primárny e-mailový kontakt používateľa:
class User extends Authenticatable
{
use HasContacts;
use Notifiable;
use ReceivesNotifications;
use RoutesNotificationsViaContacts; // mail goes to the primary email contact
}Ak chcete len overené adresy, naviažte resolver — používateľ bez overeného primárneho e-mailu potom dostane undeliverable a ani súhrn:
use Illuminate\Database\Eloquent\Model;
use RoundlyConsulting\Contacts\Enums\ContactType;
use RoundlyConsulting\Notifications\Contracts\ResolvesMailAddress;
use RoundlyConsulting\Notifications\NotificationPayload;
final class VerifiedEmailResolver implements ResolvesMailAddress
{
public function address(Model $recipient, ?NotificationPayload $payload): ?string // null payload = a digest
{
$contact = $recipient->primaryContact(ContactType::Email);
return $contact?->verified_at !== null ? $contact->value : null;
}
}
// config/notifications.php
'mail' => ['address_resolver' => App\Notifications\VerifiedEmailResolver::class],Prejavte lásku k open source
Tento balík je zadarmo pod licenciou MIT. Ak vám šetrí čas, jednorazový príspevok alebo členstvo na Patreone nám pomôže ho ďalej udržiavať, testovať a dokumentovať.
Ďalšie spôsoby podpory vrátane kryptomienOdoslaním daru súhlasíte s našimi podmienkami prijímania darov.
Chcete to zabudovať do svojho produktu?
Naše balíky integrujeme do zákazkových Laravel a AI riešení. Napíšte nám, na čom pracujete, a ozveme sa do 48 hodín.