Ludovic ROLAND

Blog technique sur mes expériences de développeur.

Envoyer et recevoir des e-mails en Perl 5 (4/5) : TP : zSpam, le filtre anti-spam du zéro

9 août 2022

Avant de s’attaquer à la consultation de ses e-mails via le protocole IMAP, je vous propose un petit exercice qui va nous permettre de retravailler avec le module Net::POP3.

L’objectif étant bien évidemment de vous faire manipuler ce que nous venons de voir dans le chapitre précédent !

Plan

L’énoncé

Le but de ce TP est de créer une sorte de filtre anti-spams ultra simple.

Notre zSpam fonctionne suivant les étapes suivantes :

  • le programme demande à l’utilisateur de saisir une adresse e-mail suspecte ;
  • le programme se connecte au serveur et supprime tous les e-mails provenant de l’adresse électronique saisie lors l’étape précédente.

Une solution

Je vous fais part de ma solution. Bien évidemment, il ne s’agit pas de LA solution !

#!/usr/bin/perl -w

use strict;
use Net::POP3;

my $mail;

#Saisie de l'adresse
print "Saisir l'adresse électronique qui vous spamme : ";
$mail = <STDIN>;
chop($mail);

#Connexion au serveur
my $pop = Net::POP3->new('pop.wanadoo.fr') or die 'Impossible de se connecter au serveur : '.$!;

#Connexion au compte
$pop->login('*****@wanadoo.fr', '*****') or die 'Erreur d\'identification !';

#Récupération de la liste des messages
my $index = $pop->list() or die 'Impossible de lister les messages !';

#On boucle sur la liste des e-mails
foreach my $msgnum (keys %$index) {
        my $msg = $pop->top($msgnum) or die 'Impossible de récupérer le message n°'.$msgnum.' !';
        my $tmp = sprintf("@$msg");

        #On cherche l'expéditeur dans les en-têtes des mails
        if($tmp =~ m/.*From: .*<$mail>.*/) {
                #On supprime le message
                if($pop->delete($msgnum)) {
                        print 'Message n°'.$msgnum." supprimé avec succès\n";
                }
                else {
                        print 'Impossible de supprimer le message n°'.$msgnum."\n";
                }
        }
}

#On quitte le serveur pour que les modifications s'effectuent
$pop->quit() or die 'Un problème est survenu avec la méthode quit() !';

Quelques explications

Le contenu de la boucle foreach n’est peut-être pas évident pour tout le monde. C’est pourquoi je vous propose quelques explications.

Étape 1 : récupération de l’en-tête

La première étape consiste à récupérer l’en-tête de notre message puisque c’est dans cette en-tête que l’on trouve les différentes informations sur l’expéditeur de l’e-mail.

Comme nous l’avons vu au cours du chapitre précédent, c’est la fonction top() qui nous permet de récupérer l’en-tête. Dans notre cas, nous la stockons dans la variable du nom de $msg.

$msg = $pop->top($msgnum);

Étape 2a : comparaison de l’en-tête

La seconde étape consiste à vérifier l’expéditeur du message dont nous venons de récupérer l’en-tête. La variable $msg étant une référence à un tableau, nous ne pouvons pas l’utiliser directement dans une expression rationnelle, même sous la forme @$msg.

Vous pouvez toujours essayer, mais voici ce que risque de vous pondre votre programme lors de son exécution :

Applying pattern match (m//) to @array will act on scalar(@array)

Afin de pouvoir effectuer la comparaison, vous pouvez utiliser ma petite astuce qui consiste à écrire la valeur de référence dans une variable temporaire (ici $tmp) grâce à la fonction sprintf().

Voici la fameuse ligne dans mon programme :

my $tmp = sprintf("@$msg");

Étape 2b : comparaison de l’en-tête (suite)

Nous pouvons maintenant chercher l’expéditeur dans la valeur de la variable $tmp. Pour cela, nous utilisons une expression rationnelle.

A noter que l’expéditeur suit le mot clef From: et peut se trouver sous plusieurs formes :

From: <*****@wanadoo.fr>
From: Wapiti 89 <*****@wanadoo.fr>

Voici donc ce que donne la recherche dans mon programme :

$tmp =~ m/.*From: .*<$mail>.*/

Étape 3 : suppression des e-mails

Lorsque l’expéditeur est trouvé dans l’en-tête, nous supprimons l’e-mail grâce à la fonction delete().

Tout comme moi, vous pouvez imbriquer tout ça dans un if afin de vérifier que la suppression a bien eu lieu, mais ce n’est en aucun cas une obligation.

if($pop->delete($msgnum)) {
	print 'Message n°'.$msgnum." supprimé avec succès\n";
}
else {
    print 'Impossible de supprimer le message n°'.$msgnum."\n";
}

Si vous avez des problèmes, des doutes ou des questions, je vous encourage à les poser sur le forum du site !

Quelques améliorations possibles

Pour améliorer ce petit programme, vous pouvez par exemple :

  • vérifier que l’adresse électronique saisie est correcte à l’aide d’une expression rationnelle ;
  • permettre à l’utilisateur de régler l’anti-spam sur une adresse e-mail, un sujet ou encore un mot clef (dans le corps ou le sujet du message) ;
  • permettre à l’utilisateur de confirmer ou non la suppression d’un e-mail en l’affichant à l’écran.

Maintenant que vous êtes plus familier avec le protocole POP3 et le module Net::POP3, je vous propose de s’attaquer au protocole IMAP grâce au module Net::IMAP::Simple.

Commentaires