Nettoyer la file des courriels

Rédigé par Alexandre le 28/10/2020

Mis à jour le 25/11/2020

#travail #hébergement #outil

Au travail, nous avons une sonde sur nos passerelles de courriels qui passe en critique lorsque plus de 3000 courriels sont en file. Généralement, lorsque cette sonde se déclenche, c'est qu'un client fait de l'envoi de courriels de masse ou qu'un des formulaires de son site web est mal protégé.

Récemment lors d'un week-end, la sonde s'est déclenchée et un client a rapidement pu être pointé du doigt. En astreinte, mes collègues ont bloqué le port SMTP (25) des serveurs du client incriminé pour arrêter le remplissage de la file sur les passerelles.

Une fois le port SMTP bloqué, la file se remplit sur les serveurs du client, ce qui décale le problème, mais ne génère pas de congestion particulière. Il est alors nécessaire de travailler de concert avec le client et donc de lui fournir une liste des courriels dans la file d'attente de ces serveurs.

Afficher les courriels présents dans la file d'attente :

mailq

Voici un extrait de lignes concernant un courriel précis :

-Queue ID- --Size-- ----Arrival Time---- -Sender/Recipient-------
7807B1967C7B     6715 Sat Oct 24 19:12:52  expediteur@domaine.fr
                      (connect to 192.168.1.89[192.168.1.89]:25: Connection refused)
                                         destinataire@domaine.com

Cet extrait permet d'identifier l'expéditeur, le destinataire, la passerelle et l'erreur. Ici l'erreur Connection refused indique que la passerelle est injoignable. Ce résultat est intéressant mais peu complet. Afficher l'ensemble des détails concernant un courriel en file se fait via la commande suivante :

sudo postcat -q <id du courriel>

En réalité, le client n'a pas vraiment besoin de toutes ces informations, nous allons donc extraire le destinataire, le sujet et l'expéditeur via la commande suivante :

sudo postcat -q 7807B1967C7B | egrep "From:|To:|Subject:"

Le résultat est le suivant :

To: Destinataire <destinataire@domaine.com>
Subject: =?utf-8?B?U3Vic2NyaXB0aW9uIHRvIHRoZSBuZXdzbGV0dGVyIGNvbmZpcm1hdGlvbg==?=
From: Expediteur <expediteur@domaine.fr>

Le sujet n'est pas très lisible, mais cela s'arrange avec un petit bout de script perl :

nano /tmp/decode.pl

Copier le contenu suivant :

#!/usr/bin/env perl
use open qw(:std :utf8);
use Encode qw(decode);

while (my $line = <STDIN>) {
  print decode("MIME-Header", $line);
}

Récupérer les informations intéressantes en utilisant le script :

sudo postcat -q 7807B1967C7B | egrep "From:|To:|Subject:" | perl /tmp/decode.pl

Cela devient tout de suite plus lisible :

To: Destinataire <destinataire@domaine.com>
Subject: Subscription to the newsletter confirmation
From: Expediteur <expediteur@domaine.fr>

Maintenant que c'est fait pour un courriel, il est possible de le faire pour l'ensemble des courriels en file d'attente. Afin de pouvoir fournir le résultat au client, définir un fichier de journalisation :

log_file="/home/alegall/mails_en_file-$(date +'%F').log"

Récupérer les informations sur l'ensemble de la file d'attente :

for mailID in $(mailq | awk '/^[0-9A-F][0-9A-F]/{print $1}'); do
  [[ $mailID =~ "*" ]] && continue
  echo "-----------] ${mailID}" | tee --append $log_file
  sudo postcat -q $mailID | egrep "From:|To:|Subject:" | perl /tmp/decode.pl | tee --append $log_file
done

Une fois l'ensemble des informations récupérées, il peut être intéressant de compter le nombre d'itérations d'un même sujet par exemple :

grep "Subject: " $log_file | sort | uniq -c | sort -bgr

Faire un retour au client avec l'ensemble des informations récoltées en lui proposant de supprimer des courriels en se basant sur l'une des informations fournie (sujet, expéditeur ou destinataire).

Dans l'exemple suivant, le client a demandé à ce que l'ensemble des courriels ayant pour sujet Subscription to the newsletter confirmation soient supprimés. Cela se fait comme ceci :

for mailID in $(mailq | awk '/^[0-9A-F][0-9A-F]/{print $1}'); do
  [[ $mailID =~ "*" ]] && continue
  subject=$(sudo postcat -q $mailID | egrep "Subject:" | perl /tmp/decode.pl);
  [[ "${subject}" == "Subject: Subscription to the newsletter confirmation" ]] && sudo postsuper -d $mailID;
done

Une fois le nettoyage effectué, le port SMTP est ouvert et la sonde des passerelles surveillée jusqu'à ce que la file d'attente des serveurs du client soit vide.