Recevoir les e-mails en développement¶
Vous êtes développeur·se sur Kirexo et vous attendez un e-mail (réinitialisation de mot de passe, par exemple) qui n'apparaît jamais dans Mailpit. Ce guide explique pourquoi et comment le faire arriver.
Prérequis¶
- La stack Docker est démarrée (
castor docker:up). - Vous savez ouvrir l'UI Mailpit : http://localhost:8025.
Pourquoi l'e-mail n'arrive pas tout de suite¶
En développement, le Mailer de Kirexo est asynchrone. L'e-mail n'est pas envoyé pendant la requête HTTP : un message Symfony\Component\Mailer\Messenger\SendEmailMessage est dispatché sur le bus Messenger, routé vers le transport async qui pointe sur RabbitMQ (config/packages/messenger.yaml).
# config/packages/messenger.yaml
routing:
Symfony\Component\Mailer\Messenger\SendEmailMessage: async
Le transport async utilise le DSN AMQP de MESSENGER_TRANSPORT_DSN (.env), soit amqp://guest:guest@rabbitmq:5672/%2f/messages.
Conséquence : tant qu'aucun worker ne consomme la file, le message reste en attente dans RabbitMQ et aucun e-mail n'atteint Mailpit. Et en dev, aucun worker n'est lancé automatiquement — c'est à vous de le démarrer.
En test, c'est synchrone
En environnement de test, messenger.yaml (bloc when@test) force async: 'sync://' : l'e-mail part immédiatement, sans worker. C'est pour ça que les tests n'ont jamais à drainer de file. Le comportement asynchrone décrit ici ne concerne que le dev. (En test, MAILER_DSN=null://null : rien n'est réellement émis.)
Faire arriver les e-mails¶
Option A — laisser un worker tourner¶
Démarrez un worker et laissez-le ouvert dans un terminal dédié pendant votre session de dev :
La cible consomme le transport async avec une limite de temps interne (le process s'arrête au bout d'une heure et doit être relancé — c'est volontaire, pour éviter les fuites mémoire d'un process long). Dès qu'un e-mail est dispatché, il est consommé et apparaît dans Mailpit.
Pour suivre en détail ce que le worker traite (utile au diagnostic), passez par castor console avec la verbosité :
Option B — drainer ponctuellement la file¶
Si vous ne voulez pas garder un worker ouvert, videz la file à la demande puis rendez la main :
Le worker s'arrête après 10 messages ou 15 secondes, selon ce qui survient en premier. Pratique juste après avoir déclenché un envoi : vous drainez, puis vous allez lire l'e-mail dans Mailpit.
Diagnostiquer¶
Combien de messages attendent ?¶
Un Count supérieur à 0 sur la ligne async signifie que des e-mails (ou d'autres messages) sont en attente : aucun worker ne les a encore consommés.
Côté Symfony Profiler¶
Comme rien n'est envoyé pendant la requête HTTP, l'envoi n'apparaît pas dans l'onglet Mailer du profiler. Il apparaît dans l'onglet Messenger, sous la forme d'un message SendEmailMessage dispatché sur le transport async. Si vous cherchez la preuve qu'un e-mail a bien été « parti » côté application, c'est là qu'il faut regarder, pas dans Mailer.
Gotcha : le worker garde les templates Twig en mémoire¶
Un worker messenger:consume est un process long : il charge le kernel une fois et conserve les templates Twig d'e-mail compilés en mémoire. Si vous modifiez un template d'e-mail (par exemple templates/email/base.html.twig ou templates/reset_password/email.html.twig) pendant qu'un worker tourne, le worker continue de rendre l'ancienne version compilée.
Un cache:clear ne suffit pas : le process a déjà chargé l'ancienne classe compilée en mémoire. Il faut redémarrer le worker :
castor console "messenger:stop-workers" # signale aux workers de s'arrêter proprement
castor messenger:consume # relancer un worker neuf
C'est l'équivalent, côté Messenger, du rechargement du worker FrankenPHP après modification d'une route.
SMTP de développement (Mailpit)¶
En dev, MAILER_DSN=smtp://mailer:1025 (.env) pointe sur le service mailer, qui est Mailpit (compose.override.yaml). Mailpit capture tous les e-mails sortants sans jamais les délivrer réellement :
- UI web : http://localhost:8025 (port
MAILPIT_UI_PORT). - SMTP : port
1025côté conteneur (MAILPIT_SMTP_PORTcôté hôte).
Une fois le worker passé sur la file, l'e-mail s'affiche dans cette boîte.
Le transport failed n'est pas opérationnel en dev
messenger.yaml déclare un transport failed sur doctrine://default, mais symfony/doctrine-messenger n'est pas installé. Un castor console "messenger:stats failed" échoue donc, et surtout un e-mail dont l'envoi échouerait après ses tentatives de retry ne serait pas routé vers une file d'échec consultable. En dev, si un e-mail « disparaît » sans erreur visible, vérifiez d'abord qu'un worker tourne (messenger:stats async) avant de soupçonner un échec.
Voir aussi¶
- Réinitialiser son mot de passe — le parcours fonctionnel qui déclenche le premier e-mail transactionnel de Kirexo.
- Variables d'environnement —
MAILER_DSN,MESSENGER_TRANSPORT_DSN,MAILPIT_SMTP_PORT,MAILPIT_UI_PORT. - Apparence des e-mails (design system) — pourquoi les e-mails portent l'accent d'instance ou l'identité admin.