Plugin Bounce Guard per Discourse

Repo: GitHub - overgrow/discourse-bounce-guard · GitHub
Licenza: MIT

&tldr; Cosa ottieni: un log degli errori più pulito (cessano i tentativi di invio orari a indirizzi inesistenti). Discourse smette di inviare email che non possono essere consegnate. E utenti più felici: possono rientrare nel loro account, perché un indirizzo inesistente viene sostituito in tempo con uno funzionante.

Se la posta in uscita passa attraverso il tuo relay (Postfix, Exim, la maggior parte delle configurazioni self-hosted), probabilmente hai visto /logs riempirsi di coppie come questa:

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

Il dominio è sparito e non tornerà. Ma il relay risponde con un codice di errore temporaneo (450), perché in teoria una ricerca DNS può fallire per un momento. Discourse interpreta qualsiasi errore temporaneo come “riprova tra un’ora” e Sidekiq continua a tentare per settimane. Il rilevamento dei rimbalzi (bounce) del core non si attiva mai. Reagisce solo quando torna un messaggio di rimbalzo, sia come email (VERP) sia come webhook dal tuo provider di posta, e qui il messaggio viene rifiutato sul posto, quindi nessun messaggio di rimbalzo viene mai generato. Il punteggio di rimbalzo resta a zero, i tentativi continuano e l’utente mantiene un indirizzo che non può ricevere nulla, inclusa una reimpostazione della password.

Questo è già emerso qui alcune volte senza una risposta integrata, ad esempio Gestione delle email verso domini inesistenti, Disattiva utente con hard bounce e Come disattivare gli account di utenti che non ricevono email. Abbiamo avuto lo stesso problema sul nostro forum, quindi abbiamo creato un plugin.

Cosa fa

Bounce Guard aggancia il percorso di invio stesso e classifica ogni rifiuto SMTP:

  • Le risposte 5xx con uno stato esteso di destinatario non valido (5.1.1, 5.1.2, 5.2.1 e simili)
    vengono conteggiate come fallimenti definitivi (hard failure).
  • Qualsiasi risposta che corrisponda a un elenco di frasi configurabili (“domain not found”, “user unknown”, …)
    viene conteggiata come definitiva indipendentemente dal codice. Questo cattura i relay che segnalano condizioni permanenti con un errore soft (450).
  • Greylisting, caselle piene e limiti di frequenza (rate limits) vengono lasciati intatti. Il comportamento di retry del core non viene toccato.

I fallimenti definitivi registrati salgono quindi una scala:

  1. Ciascuno di essi alimenta il punteggio di rimbalzo del core come hard bounce (attivo di default). Dopo due, la soglia del core stesso viene raggiunta e Discourse smette di inviare email all’utente. Il rumore nel log finisce qui, anche se non attivi nulla di ulteriore.
  2. Dopo un numero configurabile di fallimenti distribuiti su un intervallo configurabile (default: 2 fallimenti a distanza di almeno 48 ore, in modo che un’interruzione breve non possa escludere nessuno), il plugin agisce. L’azione predefinita è log_only: una voce nel log delle azioni del personale che registra che l’utente sarebbe stato disattivato. Passa a deactivate quando ti fidi di esso.
  3. La disattivazione instrada l’utente attraverso il flusso di attivazione standard al suo prossimo accesso, dove la modifica dell’indirizzo è integrata. Verificano un’email funzionante e continuano con il loro account intatto. Il punto è la recuperabilità: un account attivo il cui unico canale di recupero è una casella di posta morta è un blocco in attesa di verificarsi.

Se il tuo sito riceve rimbalzi (VERP o webhook), puoi anche consentire al plugin di agire quando il punteggio di rimbalzo del core supera un livello che scegli, superiore al punteggio a cui il core smette di inviare. Vanno applicate ovunque alcune regole di sicurezza. Il personale e i bot non vengono mai toccati. Un’email bloccata che riprova ogni ora conta come un singolo fallimento, grazie a una finestra di raffreddamento (cooldown). Un fallimento conta contro un utente solo se l’indirizzo rifiutato dal server è l’indirizzo corrente di quell’utente. E ogni fallimento registrato viene conservato per 90 giorni in modo da poter verificare cosa è successo (query Data Explorer nella README).

Installazione

Standard installazione 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

Abilita bounce_guard_enabled, lascia bounce_guard_action su log_only per una o due settimane, rivedi cosa viene segnalato, poi decidi sulla disattivazione. Il riferimento alle impostazioni è nella README.

Solo lato server, nessun componente di tema o JS. Costruito e testato contro il core attuale (2026.8), 31 specifiche, CI esegue il workflow standard discourse-plugin. Feedback benvenuti, in particolare le formulazioni di rifiuto da parte di altri relay che l’elenco di frasi predefinito non cattura.

2 Mi Piace