Transactional emails
Email sending system with HTML/TXT biformat templates, shared layout, and per-user localization.
Overview
Transactional emails are sent via Symfony Mailer (SMTP) with Twig HTML and TXT templates. Each email is triggered by a Symfony event.
Templates
| Role | Detail |
|---|---|
| Shared HTML layout (table-based, responsive, logo, footer) | templates/emails/_layout.html.twig |
| Email address verification email sent on registration | templates/emails/auth/verification.html.twig |
| Password reset email | templates/emails/auth/password_reset.html.twig |
| Confirmation email when changing email address | templates/emails/auth/email_change.html.twig |
| Invitation email to join an organization | templates/emails/organization/invitation.html.twig |
Mailers
| Role | Detail |
|---|---|
| Sends the verification email | src/Mail/Auth/VerificationEmailMailer.php |
| Sends the password reset email | src/Mail/Auth/PasswordResetEmailMailer.php |
| Sends the email change confirmation | src/Mail/Auth/EmailChangeMailer.php |
| Sends the invitation email | src/Mail/Organization/InvitationMailer.php |
Architecture
Each email follows the same pattern: a Mailer injects a TemplatedEmail with an HTML template and its TXT equivalent. The shared layout handles the logo header, responsive wrapper, and footer.
HTML + TXT format
Each email has an HTML template (rich rendering) and a TXT template (plain text fallback). Symfony Mailer automatically generates both MIME parts.
templates/emails/auth/verification.html.twig
templates/emails/auth/verification.txt.twig
Shared layout (_layout.html.twig)
The layout uses nested HTML tables for maximum client compatibility (Outlook, Apple Mail). It exposes the body block for content and the footer block for the footer. The accent colour (#7c6af7) is inlined to guarantee rendering across all email clients.
templates/emails/_layout.html.twig
Event-driven triggers
Emails are not sent directly from controllers. Each send is decoupled via a Symfony event and its dedicated subscriber.
| Event | Subscriber | Email sent |
|---|---|---|
UserRegisteredEvent |
src/EventSubscriber/Auth/SendVerificationEmailSubscriber.php |
emails/auth/verification.html.twig |
PasswordResetRequestedEvent |
src/EventSubscriber/Auth/SendPasswordResetEmailSubscriber.php |
emails/auth/password_reset.html.twig |
EmailChangeRequestedEvent |
src/EventSubscriber/SendEmailChangeEmailSubscriber.php |
emails/auth/email_change.html.twig |
InvitationCreatedEvent |
src/EventSubscriber/Organization/SendInvitationEmailSubscriber.php |
emails/organization/invitation.html.twig |
Localization
Each email is sent in the user's preferred language (getPreferredLocale()). The locale is passed as context to the Twig template and to TranslatorInterface::trans() when building the subject.
Auth email translation keys are in auth.fr.yaml / auth.en.yaml. Invitation keys are in boilerplate.fr.yaml / boilerplate.en.yaml.
translations/auth.fr.yaml
translations/auth.en.yaml
translations/boilerplate.fr.yaml
translations/boilerplate.en.yaml