Image de couverture : Laravel : Mail::alwaysTo() ne protège qu'un seul mailer en staging
PHP & Frameworks

Laravel : Mail::alwaysTo() ne protège qu'un seul mailer en staging

11 octobre 2026
5 min de lecture
14 vues
Sébastien Muler

Vous pensiez avoir verrouillé vos e-mails de staging ? Vérifiez vos mailers secondaires

Une astuce circule partout dans les tutoriels Laravel : appeler Mail::alwaysTo() dans le boot() d'un service provider pour que tous les e-mails d'un environnement de test finissent dans une boîte unique. La recette est reprise de la documentation, relayée par des médias et des blogs, et présentée comme un filet de sécurité complet. Or, quand on regarde de plus près le comportement réel du framework, cette protection a une limite que presque personne ne mentionne. C'est ce qu'a mis en évidence Mail::alwaysTo() Guards One Mailer: The Staging Leak It Leaves Open, publié sur dev.to.

Ce que fait réellement Mail::alwaysTo()

La version habituelle ressemble à ceci :

use Illuminate\Support\Facades\Mail;

public function boot(): void
{
    if (! $this->app->isProduction()) {
        Mail::alwaysTo('staging@example.com');
    }
}

Sur le papier, le résultat est rassurant : le destinataire (to) de chaque message est remplacé par l'adresse de recette, et les champs cc et bcc sont supprimés. Un développeur qui lit ce code en conclut naturellement que plus aucun message ne peut atteindre un vrai client depuis staging.

Le point qui échappe à cette lecture : l'appel configure le mailer sur lequel il est exécuté, pas l'ensemble de ceux déclarés dans votre application. Si votre projet n'utilise qu'un seul transport, le comportement est conforme à ce qu'on attend. Dès qu'il en utilise plusieurs, la garantie n'est plus la même.

Le scénario à risque : un second mailer

Imaginez une configuration courante dans une application qui envoie à la fois des e-mails applicatifs et des factures :

// config/mail.php
'default' => env('MAIL_MAILER', 'smtp'),

'mailers' => [
    'smtp' => [ /* ... */ ],
    'billing' => ['transport' => 'postmark'],
],

Les notifications transactionnelles passent par le mailer par défaut, et les factures par le mailer billing. Selon l'auteur de l'article, qui a reproduit le cas dans un bac à sable avec Laravel 12.43 et deux mailers sur le transport array, l'envoi d'une facture via le mailer secondaire ne reçoit pas la redirection : le message part vers l'adresse réelle du client, alors que Mail::alwaysTo() est bien actif.

Les conséquences sont faciles à imaginer :

  • une facture de test envoyée à un vrai client depuis un environnement de recette ;
  • des données de démonstration ou des montants fictifs reçus par des destinataires réels ;
  • une fuite qui passe inaperçue, puisque tous les tests sur le mailer par défaut semblent corrects.

Le danger vient justement de la fausse sécurité : la protection existe, elle est testée, mais elle ne couvre qu'une partie des chemins d'envoi.

Comment sécuriser durablement votre staging

Plutôt que de compter sur un seul appel, il vaut mieux raisonner en défense en profondeur. Voici des pistes à évaluer selon votre architecture.

Auditer vos mailers déclarés

Commencez par lister tous les mailers de config/mail.php, et identifiez ceux qui sont réellement utilisés dans le code (Mail::mailer('billing'), propriétés mailer sur des notifications, etc.). Chacun est un point de fuite potentiel.

Appliquer la protection par mailer

Si alwaysTo() ne s'applique qu'au mailer sur lequel il est appelé, il faut l'appliquer explicitement à chacun des mailers de l'application. Une boucle sur la liste des mailers dans le boot(), limitée aux environnements hors production, est une approche simple à mettre en place. Testez-la ensuite avec un envoi sur chaque mailer, pas seulement le défaut.

Neutraliser le transport lui-même

La solution la plus robuste consiste souvent à ne pas laisser de vrai transport actif en staging. Faire pointer tous les mailers vers un transport de capture (log, array ou un service de type Mailpit/Mailtrap) rend la fuite impossible par construction, quel que soit le mailer choisi par le code. La redirection devient alors une seconde ligne de défense, pas la seule.

Écrire un test qui garde la porte

Un test automatisé qui envoie un message sur chaque mailer déclaré et vérifie que le destinataire final est bien l'adresse de recette permet de détecter une régression le jour où quelqu'un ajoute un nouveau transport.

À retenir

Mail::alwaysTo() est un bon réflexe pour un projet à mailer unique, mais il ne constitue pas une garantie globale dès que vous séparez vos flux (transactionnel, facturation, marketing) sur plusieurs transports. Un ticket de staging qui envoie une facture à un vrai client n'est pas une simple anomalie : c'est un incident de confiance. Prenez dix minutes pour recenser vos mailers, appliquez la protection sur chacun, et préférez neutraliser les transports réels hors production. Pour le détail du test et le comportement observé dans le framework, consultez l'article d'origine : Mail::alwaysTo() Guards One Mailer: The Staging Leak It Leaves Open.

Partager cet article

Et votre site, il vaut quoi ?

Vitesse, accessibilité, référencement technique. Le rapport est écrit pour un dirigeant, pas pour un développeur. Gratuit, sans inscription.

Tester mon site