Plugin Bounce Guard pour Discourse

Dépôt : GitHub - overgrow/discourse-bounce-guard · GitHub
Licence : MIT

&tldr; Ce que vous obtenez : un journal d’erreurs plus propre (les tentatives horaires vers des adresses mortes cessent). Discourse cesse d’envoyer des e-mails qui ne peuvent pas être livrés. Et des utilisateurs plus satisfaits : ils peuvent retrouver l’accès à leur compte, car une adresse morte est remplacée par une adresse fonctionnelle à temps.

Si votre messagerie sortante passe par votre propre relais (Postfix, Exim, la plupart des configurations auto-hébergées), vous avez probablement constaté que /logs se remplit de paires comme celle-ci :

SMTP Error Net::SMTPServerBusy with message: 450 4.1.2 <someone@gone-domain.com>: Recipient address rejected: Domain not found
Job exception: Net::SMTPServerBusy

Le domaine a disparu et ne reviendra pas. Mais le relais répond avec un code d’erreur temporaire (450), car en théorie, une requête DNS peut échouer momentanément. Discourse interprète toute erreur temporaire comme signifiant « réessayer dans une heure », et Sidekiq continue de tenter pendant des semaines. La détection de rebond du noyau ne se déclenche jamais. Elle ne réagit que lorsqu’un message de rebond est renvoyé, soit sous forme d’e-mail (VERP), soit sous forme de webhook de votre fournisseur de messagerie, et ici, le message est refusé sur le champ, de sorte qu’aucun message de rebond n’existe jamais. Le score de rebond reste à zéro, les tentatives continuent, et l’utilisateur conserve une adresse qui ne peut rien recevoir, y compris un e-mail de réinitialisation du mot de passe.

Cela a été soulevé ici à quelques reprises sans réponse intégrée, par exemple Gestion des e-mails vers un domaine inexistant, Désactiver un utilisateur en cas de rebond définitif et Comment désactiver les comptes des utilisateurs qui ne reçoivent pas d’e-mails. Nous avons eu les mêmes problèmes sur notre forum, nous avons donc développé un plugin.

Ce qu’il fait

Bounce Guard s’intercale dans le chemin d’envoi lui-même et classe chaque rejet SMTP :

  • Les réponses 5xx avec un statut de destinataire invalide étendu (5.1.1, 5.1.2, 5.2.1 et similaires)
    sont comptabilisées comme des échecs définitifs.
  • Toute réponse correspondant à une liste de phrases configurable (« domain not found », « user unknown », …)
    est comptabilisée comme définitive, quel que soit le code. Cela capture les relais qui échouent de manière temporaire avec un 450 pour des conditions permanentes.
  • Le greylisting, les boîtes aux lettres pleines et les limites de débit sont laissés de côté. Le comportement de réessai du noyau reste inchangé.

Les échecs définitifs enregistrés montent alors une échelle :

  1. Chacun alimente le score de rebond du noyau en tant que rebond définitif (activé par défaut). Après deux échecs, le seuil propre du noyau est atteint et Discourse cesse d’envoyer des e-mails à l’utilisateur. Le bruit dans les journaux s’arrête ici, même si vous n’activez rien d’autre.
  2. Après un nombre configurable d’échecs répartis sur une période configurable (par défaut : 2 échecs à au moins 48 heures d’intervalle, pour qu’une panne brève ne puisse pas exclure quiconque), le plugin agit. L’action par défaut est log_only : une entrée dans le journal des actions du personnel enregistrant que l’utilisateur aurait dû être désactivé. Passez à deactivate lorsque vous lui faites confiance.
  3. La désactivation achemine l’utilisateur à travers le flux d’activation standard lors de sa prochaine connexion, où le changement d’adresse est intégré. Ils vérifient un e-mail fonctionnel et continuent avec leur compte intact. L’objectif est la récupérabilité : un compte actif dont le seul canal de récupération est une boîte aux lettres morte est un verrouillage en attente de se produire.

Si votre site reçoit des rebonds (VERP ou webhooks), vous pouvez également laisser le plugin agir lorsque le score de rebond du noyau dépasse un niveau que vous choisissez, supérieur au score auquel le noyau cesse d’envoyer. Quelques règles de sécurité s’appliquent partout. Le personnel et les bots ne sont jamais touchés. Un e-mail bloqué qui retente chaque heure est compté comme un seul échec, grâce à une fenêtre de refroidissement. Un échec n’est compté contre un utilisateur que lorsque l’adresse rejetée par le serveur est l’adresse actuelle de cet utilisateur. Et chaque échec enregistré est conservé pendant 90 jours pour que vous puissiez vérifier ce qui s’est passé (requête Data Explorer dans le README).

Installation

Installation standard du plugin :

hooks:
  after_code:
    - exec:
        cd: $home/plugins
        cmd:
          - git clone https://github.com/discourse/docker_manager.git
          - git clone https://github.com/overgrow/discourse-bounce-guard.git

Activez bounce_guard_enabled, laissez bounce_guard_action sur log_only pendant une ou deux semaines, examinez ce qu’il signale, puis décidez de la désactivation. La référence des paramètres se trouve dans le README.

Côté serveur uniquement, aucun composant de thème ou JS. Construit et testé contre le noyau actuel (2026.8), 31 spécifications, CI exécute le workflow standard discourse-plugin. Les retours sont les bienvenus, en particulier les formulations de rejet d’autres relais que la liste de phrases par défaut ne capture pas.

2 « J'aime »