Le composant Mailer de Symfony
Comment envoyer des e-mails depuis une application Symfony grâce au composant Mailer et au service MailerInterface
Notions théoriques
Le composant Mailer
Beaucoup d'applications ont besoin d'envoyer des e-mails : confirmation d'inscription, réinitialisation de mot de passe, notification... Symfony fournit pour cela son propre composant, Mailer, intégré au conteneur de services et à Twig.
Vous avez déjà croisé une bibliothèque d'envoi d'e-mails en PHP procédural : PHPMailer. C'est une bibliothèque générique, indépendante de tout framework. Le composant Mailer de Symfony joue le même rôle, mais s'intègre nativement au conteneur de services, à la configuration par variables d'environnement et à Twig — exactement comme les autres composants que vous utilisez déjà dans vos projets Symfony.
Installation et configuration
On installe le composant avec Composer :
composer require symfony/mailer
La configuration se fait via une seule variable d'environnement dans le fichier .env : MAILER_DSN.
Ce DSN (Data Source Name) décrit comment se connecter au serveur d'envoi (SMTP, service tiers...).
# Exemple avec un serveur SMTP classique
MAILER_DSN=smtp://user:password@smtp.example.com:587
Comme pour la connexion à la base de données, ne jamais committer de véritables identifiants SMTP
dans le fichier .env versionné. On place les vraies valeurs dans .env.local, qui reste hors de Git.
Créer et envoyer un e-mail simple
La classe Email représente un e-mail : expéditeur, destinataire, sujet et contenu. On l'envoie
grâce au service MailerInterface, injecté comme n'importe quel autre service.
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Email;
public function envoyerBienvenue(MailerInterface $mailer): void
{
$email = (new Email())
->from('contact@monblog.fr')
->to('nouvel.utilisateur@example.com')
->subject('Bienvenue sur le blog !')
->text('Merci de vous être inscrit.')
->html('<p>Merci de vous être <strong>inscrit</strong>.</p>');
$mailer->send($email);
}
Utiliser un template Twig avec TemplatedEmail
Écrire le contenu HTML d'un e-mail directement dans le code PHP devient vite difficile à maintenir.
Symfony propose la classe TemplatedEmail, qui délègue le corps de l'e-mail à un template Twig,
exactement comme on le fait déjà pour une page web classique.
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
$email = (new TemplatedEmail())
->from('contact@monblog.fr')
->to($utilisateur->getEmail())
->subject('Bienvenue sur le blog !')
->htmlTemplate('emails/bienvenue.html.twig')
->context([
'pseudo' => $utilisateur->getPseudo(),
]);
$mailer->send($email);
Le template Twig reçoit les variables passées dans context(), comme n'importe quel template rendu par un contrôleur :
<p>Bonjour {{ pseudo }},</p>
<p>Merci de vous être inscrit sur le blog !</p>
Un TemplatedEmail peut définir à la fois un template pour la version HTML et un template pour
la version texte brut, avec htmlTemplate() et textTemplate(). Cela garantit un affichage correct
même sur les clients de messagerie qui n'affichent pas le HTML.
Envoi bloquant : une sensibilisation
Par défaut, $mailer->send($email) bloque l'exécution de la requête HTTP jusqu'à ce que l'e-mail
soit effectivement transmis au serveur SMTP.
En production, un envoi bloquant ralentit la réponse renvoyée à l'utilisateur, et peut même faire échouer toute la requête si le serveur SMTP est lent ou indisponible. Symfony propose une solution à base de file d'attente (le composant Messenger) pour envoyer les e-mails de façon asynchrone — un sujet qui dépasse le cadre de cette séance, mais qu'il est utile de garder en tête pour vos futurs projets.
Exemple de mise en application
Un cas d'usage très courant : envoyer un e-mail de confirmation juste après l'inscription d'un utilisateur.
// src/Service/InscriptionManager.php
namespace App\Service;
use App\Entity\Utilisateur;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Component\Mailer\MailerInterface;
use Symfony\Component\Mime\Address;
class InscriptionManager
{
public function __construct(
private EntityManagerInterface $entityManager,
private MailerInterface $mailer
) {}
public function inscrire(Utilisateur $utilisateur): void
{
$this->entityManager->persist($utilisateur);
$this->entityManager->flush();
$email = (new TemplatedEmail())
->from(new Address('contact@monblog.fr', 'Le Blog'))
->to($utilisateur->getEmail())
->subject('Confirmez votre inscription')
->htmlTemplate('emails/confirmation_inscription.html.twig')
->context([
'pseudo' => $utilisateur->getPseudo(),
]);
$this->mailer->send($email);
}
}
La classe Address permet d'associer un nom affiché (« Le Blog ») à une adresse e-mail.
C'est ce nom qui apparaît dans la boîte de réception du destinataire, plutôt que l'adresse brute.
Test de mémorisation/compréhension
TP pour réfléchir et résoudre des problèmes
Votre défi pour aujourd'hui consiste à envoyer un e-mail de bienvenue à chaque nouvel abonné à la newsletter du blog, à partir d'un template Twig.
Étape 1 — Compléter le DSN de configuration
Pour un environnement de développement, on utilise souvent un service local de capture d'e-mails.
Étape 2 — Injecter le service MailerInterface
Le service AbonneNewsletterManager doit recevoir le service d'envoi de mails par injection de dépendance.
Toujours injecter l'interface (MailerInterface) et non une implémentation concrète.
C'est le principe déjà rencontré avec les repositories et les services : dépendre d'une interface
permet à Symfony de choisir l'implémentation adéquate, et facilite les tests (on peut simuler
l'interface sans envoyer de vrais e-mails pendant les tests automatisés).
Étape 3 — Construire et envoyer le TemplatedEmail
Après avoir enregistré l'abonné en base, il faut construire l'e-mail de bienvenue à partir du template
emails/bienvenue_newsletter.html.twig et l'envoyer.
Exactement comme pour dispatcher un événement métier : on envoie l'e-mail une fois les données
réellement enregistrées en base. Si l'inscription échoue avant le flush(), on évite d'envoyer
un e-mail de confirmation pour une inscription qui n'a finalement pas eu lieu.