Skip to Content

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 Email (ou TemplatedEmail rendu 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/mailer

Un 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:1025

En 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: async

Dé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/notifier
use 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 SMS

Les 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.