Chapitre 12.4 — Mailer & Notifier
Partie 12 : Temps réel & async — Chapitre 4/7 Version de référence : Symfony 7.4 (Mailer, Notifier).
⏱️ TL;DR
- Mailer envoie des e-mails : un objet
TemplatedEmailrendu par Twig), via un transport défini par un DSN (SMTP, ou API : Mailgun/SendGrid/Postmark…).- En dev, Mailpit capture les e-mails (interface web) — on n’envoie rien pour de vrai.
- Couplé à Messenger, l’envoi devient asynchrone : le contrôleur ne l’attend pas.
- Notifier envoie des notifications multi-canal : SMS (Twilio…), Slack, Telegram, push, e-mail, notifications navigateur — via des channels et des recipients.
- Pour un dev Next.js : Mailer ≈ nodemailer / Resend, Notifier ≈ une couche multi-canal unifiée (SMS + chat + push) — le tout intégré et asynchrone via workers.
🎯 Objectifs
- Envoyer un e-mail simple et un e-mail Twig.
- Configurer un transport (SMTP/API) et tester avec Mailpit.
- Rendre l’envoi asynchrone.
- Envoyer une notification multi-canal avec Notifier.
1. Mailer : envoyer un e-mail
composer require symfony/mailerUn e-mail est un objet, envoyé via MailerInterface :
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Email;
$email = (new Email())
->from('no-reply@booklab.test')
->to($booking->getCustomerEmail())
->subject('Votre réservation est confirmée')
->text('Merci ! Votre réservation est confirmée.')
->html('<p>Merci ! Votre réservation est <strong>confirmée</strong>.</p>');
$mailer->send($email);2. E-mails Twig (TemplatedEmail)
Pour du HTML riche, on rend un template Twig :
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
$email = (new TemplatedEmail())
->from('no-reply@booklab.test')
->to($booking->getCustomerEmail())
->subject('Votre réservation est confirmée')
->htmlTemplate('emails/booking_confirmation.html.twig')
->context(['booking' => $booking]); // variables passées au template
$mailer->send($email);{# templates/emails/booking_confirmation.html.twig #}
<h1>Réservation confirmée</h1>
<p>Bonjour, votre réservation du {{ booking.start|date('d/m/Y à H:i') }} est confirmée.</p>On peut y attacher des fichiers (->attach(...)), incorporer des images, et générer un texte alternatif automatiquement.
3. Transports : SMTP ou API
Le transport est un DSN dans .env :
# SMTP classique
MAILER_DSN=smtp://user:pass@smtp.example.com:587
# API d'un fournisseur (recommandé en prod : meilleure délivrabilité)
MAILER_DSN=mailgun+api://KEY@default
# ou sendgrid+api, postmark+api, ses+api (Amazon), brevo+api...
# dev : Mailpit (capture, n'envoie rien)
MAILER_DSN=smtp://localhost:1025En dev, on ajoute Mailpit (un conteneur qui capture les e-mails et les affiche dans une interface web sur :8025) : on voit les e-mails sans en envoyer un seul pour de vrai. En prod, on privilégie l’API d’un fournisseur (Mailgun, Postmark, SES…) pour la délivrabilité (SPF/DKIM, réputation).
⚠️ Piège délivrabilité : envoyer en SMTP direct depuis votre serveur finit souvent en spam (réputation IP, absence de SPF/DKIM). En production, passez par un service d’emailing (API) qui gère l’authentification du domaine et la réputation. C’est un point que beaucoup découvrent trop tard.
4. E-mails asynchrones (via Messenger)
Envoyer un e-mail dans la requête la ralentit et la fait échouer si le service mail est lent/indisponible. Symfony route automatiquement les e-mails via Messenger si vous routez le message SendEmailMessage vers un transport async :
# config/packages/messenger.yaml
framework:
messenger:
routing:
Symfony\Component\Mailer\Messenger\SendEmailMessage: asyncDésormais, $mailer->send($email) enfile l’e-mail (retour immédiat) ; un worker l’envoie réellement (avec retries, chapitre 12.2). C’est la bonne pratique — cohérente avec le principe « travail lent → worker » (Partie 2.7).
5. Notifier : au-delà de l’e-mail
Le Notifier unifie l’envoi de notifications sur plusieurs canaux : e-mail, SMS (Twilio, Vonage…), chat (Slack, Telegram, Discord…), push, notifications navigateur.
composer require symfony/notifieruse Symfony\Component\Notifier\NotifierInterface;
use Symfony\Component\Notifier\Notification\Notification;
use Symfony\Component\Notifier\Recipient\Recipient;
$notification = (new Notification('Réservation confirmée', ['email', 'sms']))
->content('Votre réservation du 12/08 à 14h est confirmée.');
$recipient = new Recipient($booking->getCustomerEmail(), $booking->getPhone());
$notifier->send($notification, $recipient); // envoyé par e-mail ET SMSLes canaux sont configurés par DSN (TWILIO_DSN, SLACK_DSN…). On peut aussi envoyer une alerte d’équipe vers Slack quand un événement important survient (ex. un paiement échoue) — un ChatMessage vers le canal #alertes. Comme Mailer, le Notifier s’intègre à Messenger pour l’async.
💡 Pour un dev Next.js : Mailer ≈ nodemailer/Resend, Notifier ≈ une abstraction multi-canal (un peu comme assembler Twilio + Slack SDK + web-push derrière une seule API). L’atout : un appel
notifier->send()diffuse sur les canaux voulus, et tout passe par vos workers (fiabilité, retries). Pour BookLab : confirmation par e-mail, rappel par SMS, alertes internes sur Slack.
✏️ Exercices
Exercice 1. Envoyez un e-mail de confirmation avec un template Twig emails/booking_confirmation.html.twig recevant la réservation.
✅ Solution
$email = (new TemplatedEmail())
->from('no-reply@booklab.test')
->to($booking->getCustomerEmail())
->subject('Votre réservation est confirmée')
->htmlTemplate('emails/booking_confirmation.html.twig')
->context(['booking' => $booking]);
$mailer->send($email);Idéalement, cet envoi se fait dans un handler Messenger (async), déclenché par un événement BookingConfirmed.
Exercice 2. Pourquoi envoyer les e-mails de façon asynchrone, et comment l’activer ?
✅ Solution
Parce qu’un envoi dans la requête la ralentit et la fait échouer si le service mail est lent/indisponible. On l’active en routant le message Symfony\Component\Mailer\Messenger\SendEmailMessage vers un transport async dans messenger.yaml. Dès lors, send() enfile l’e-mail (retour immédiat) et un worker l’envoie réellement, avec retries.
Exercice 3. Vous envoyez en SMTP direct depuis votre serveur et les e-mails finissent en spam. Que faire ?
✅ Solution
Passer par un service d’emailing via l’API (Mailgun, Postmark, SendGrid, SES…) qui gère l’authentification du domaine (SPF/DKIM/DMARC) et la réputation IP — ce qui améliore fortement la délivrabilité. Le SMTP direct depuis une IP de serveur applicatif est souvent mal réputé et filtré en spam. Configurer aussi les enregistrements DNS SPF/DKIM du domaine expéditeur.
🧠 Quiz de révision
1. Comment envoie-t-on un e-mail rendu par Twig ?
Avec TemplatedEmail : ->htmlTemplate('...')->context([...]), envoyé via MailerInterface::send().
2. Comment configure-t-on le transport d’envoi ?
Par un DSN MAILER_DSN : SMTP (smtp://...) ou API fournisseur (mailgun+api://...) ; en dev, Mailpit.
3. Comment rendre l’envoi d’e-mails asynchrone ?
En routant SendEmailMessage vers un transport async dans messenger.yaml : send() enfile, un worker envoie.
4. Que permet le Notifier de plus que le Mailer ?
L’envoi multi-canal : SMS, Slack/Telegram, push, e-mail, notifications navigateur — via une API unifiée (channels + recipients).
5. Pourquoi éviter le SMTP direct en production ?
Pour la délivrabilité : un SMTP direct depuis un serveur applicatif finit souvent en spam (réputation, pas de SPF/DKIM). On préfère l’API d’un service d’emailing.
Prochain chapitre : 12.5 — Mercure : le temps réel — pousser des mises à jour en direct via SSE.