Repo: GitHub - overgrow/discourse-bounce-guard · GitHub
Lizenz: MIT
&tldr; Was du bekommst: ein saubereres Fehlerprotokoll (die stündlichen Wiederholungsversuche an nicht mehr existierende Adressen hören auf). Discourse stellt das Senden von E-Mails ein, die nicht zugestellt werden können. Und glücklichere Nutzer: Sie können wieder auf ihr Konto zugreifen, da eine ungültige Adresse rechtzeitig durch eine funktionierende ersetzt wird.
Wenn Ihr ausgehender E-Mail-Versand über ein eigenes Relay läuft (Postfix, Exim, die meisten Self-Hosted-Setups), hast du wahrscheinlich gesehen, wie sich /logs mit Paaren wie diesem füllt:
SMTP Error Net::SMTPServerBusy with message: 450 4.1.2 <someone@gone-domain.com>: Recipient address rejected: Domain not found
Job exception: Net::SMTPServerBusy
Die Domain ist weg und kommt nicht zurück. Aber das Relay antwortet mit einem temporären Fehlercode (450), weil theoretisch eine DNS-Abfrage kurzzeitig fehlschlagen kann. Discourse wertet jeden temporären Fehler als „in einer Stunde erneut versuchen“ und Sidekiq versucht es wochenlang weiter. Die Bounce-Erkennung des Kernels wird nie ausgelöst. Sie reagiert nur, wenn eine Bounce-Nachricht zurückkommt, entweder als E-Mail (VERP) oder als Webhook von deinem E-Mail-Anbieter. Hier wird die Nachricht jedoch sofort abgelehnt, sodass es keine Bounce-Nachricht gibt. Der Bounce-Score bleibt bei null, die Wiederholungsversuche gehen weiter und der Nutzer behält eine Adresse, die nichts empfangen kann, einschließlich eines Passwort-Resets.
Dieses Thema ist hier schon ein paar Mal aufgetaucht, ohne dass es eine eingebaute Lösung gab, zum Beispiel Handling emails to non-existent domain, Deactivate user with hard bounce und How to deactivate accounts of users who are not receiving emails. Wir hatten auf unserem Forum dasselbe Problem, also haben wir ein Plugin entwickelt.
Was es tut
Bounce Guard hakt in den eigentlichen Versandpfad ein und klassifiziert jede SMTP-Ablehnung:
- 5xx-Antworten mit einem fehlerhaften Empfänger-Enhanced Status (
5.1.1,5.1.2,5.2.1und ähnliche) gelten als harte Fehler. - Jede Antwort, die eine konfigurierte Phrasenliste entspricht („domain not found“, „user unknown“, …), gilt unabhängig vom Code als harter Fehler. Das fängt Relays ab, die permanente Bedingungen mit einem 450 als weiche Fehler melden.
- Greylisting, volle Postfächer und Rate-Limits bleiben unberührt. Das Wiederholungsverhalten des Kernels wird nicht verändert.
Aufgezeichnete harte Fehler klettern dann eine Leiter hoch:
- Jeder davon füttert den Bounce-Score des Kernels als harten Bounce (standardmäßig aktiv). Nach zwei Auslösungen wird die eigene Schwelle des Kernels überschritten und Discourse hört auf, dem Nutzer E-Mails zu senden. Das Protokoll-Rauschen endet hier, selbst wenn du nichts weiter aktivierst.
- Nach einer konfigurierbaren Anzahl (Standard: 3), verteilt über einen konfigurierbaren Zeitraum (Standard: 48 Stunden, damit ein kurzer Ausfall niemanden ausschließen kann), greift das Plugin. Die Standardaktion ist
log_only: Ein Staff-Action-Log-Eintrag, der festhält, dass der Nutzer deaktiviert worden wäre. Wechsle zudeactivate, wenn du dem Plugin vertraust. - Die Deaktivierung leitet den Nutzer bei seinem nächsten Login durch den Standard-Aktivierungsfluss, bei dem das Ändern der Adresse integriert ist. Sie verifizieren eine funktionierende E-Mail-Adresse und setzen mit ihrem intakten Konto fort. Der Punkt ist die Wiederherstellbarkeit: Ein aktives Konto, dessen einziger Wiederherstellungskanal ein totes Postfach ist, ist ein bevorstehender Lockout.
Wenn deine Seite Bounces erhält (VERP oder Webhooks), kannst du das Plugin auch dazu bringen, zu handeln, wenn der Bounce-Score des Kernels eine von dir gewählte Schwelle überschreitet, die höher ist als der Score, bei dem der Kernel das Senden stoppt. Überall gelten einige Sicherheitsregeln. Staff und Bots werden nie angefasst. Eine festgefahrene E-Mail, die stündlich wiederholt wird, zählt dank eines Cooldown-Fensters als ein einzelner Fehler. Ein Fehler zählt nur gegen einen Nutzer, wenn die Adresse, die der Server abgelehnt hat, die aktuelle Adresse dieses Nutzers ist. Und jeder aufgezeichnete Fehler wird 90 Tage lang aufbewahrt, damit du nachvollziehen kannst, was passiert ist (Data-Explorer-Abfrage in der README).
Installation
Standard Plugin-Installation:
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
Aktiviere bounce_guard_enabled, lass bounce_guard_action für ein oder zwei Wochen auf log_only, überprüfe, was es markiert, und entscheide dann über die Deaktivierung. Die Einstellungsreferenz findest du in der README.
Nur serverseitig, keine Theme- oder JS-Komponenten. Entwickelt und getestet gegen den aktuellen Core (2026.8), 31 Specs, CI führt den Standard discourse-plugin-Workflow aus. Feedback ist willkommen, insbesondere Ablehnungsformulierungen von anderen Relays, die die Standard-Phrasenliste verfehlt.