GAZETTE N°26: Procmail : gestion automatique du courrier

Procmail : gestion automatique du courrier

Par Jim Dennis

Adaptation française : Éric Jacoboni.


Précédent Suivant Table des Matières

4. Procmail : gestion automatique du courrier

4.1 Présentation

procmail est un utilitaire pour la gestion du courrier. Il a été écrit par Stephen van den Berg. Cet article donne quelques explications sur l'utilisation de procmail pour l'utilisateur UNIX moyen.

En tant que langage limité (au sens académique du terme), procmail de dispose pas de la plupart des caractéristiques et constructions des langages généraux traditionnels. Il ne possède ni la boucle tant que ni la boucle pour, mais il connaît beaucoup de choses sur les conventions utilisées par UNIX pour la distribution du courrier et sur les permissions des fichiers/répertoires, en particulier le verrouillage des fichiers.

Bien qu'il soit possible d'écrire un script personnalisé de filtrage du courrier dans tout langage de programmation utilisant les ressources disponibles sur la plupart des systèmes UNIX, nous montrerons que procmail est l'outil de choix parmi les administrateurs systèmes et les utilisateurs avertis.

Les systèmes de courrier UNIX consistent en MTA's (« mail transport agents », comme sendmail, smail, qmail mmdf, etc), MDA's (« mail delivery agents », comme sendmail, deliver et procmail), et MUA's (« mail user agents », comme elm, pine, /bin/mail, mh, Eudora et Pegasus).

sendmail est utilisé comme agent intégré de transport et de distribution du courrier sur de nombreux systèmes UNIX sur l'Internet. Lui et les MTA compatibles peuvent répartir le courrier à travers un filtre personnalisé ou un programme via les mécanismes des alias ou des fichiers .forward.

Le mécanisme des alias utilise un seul fichier (généralement /etc/aliases ou /usr/lib/aliases) pour rediriger le courrier. Ce fichier appartient et est géré par l'administrateur système, un utilisateur ne peut le modifier.

Le mécanisme .forward est décentralisé. Chaque utilisateur d'un système peut créer un fichier nommé .formward dans son répertoire personnel. Ce fichier contient une adresse, un nom de fichier ou un programme (filtre). Habituellement, le fichier doit appartenir à l'utilisateur ou à root et ne doit pas être modifiable par les autres utilisateurs (les versions récentes de sendmail vérifient tout cela pour des raisons de sécurité).

Il est aussi possible, avec certaines versions de sendmail, d'y spécifier plusieurs adresses, programmes ou fichiers, séparés par des virgules. Nous n'étudierons pas cette possibilité ici.

Vous pourriez faire suivre votre courrier via un programme quelconque avec un .forward consistant en une ligne telle que :


"|$HOME/bin/votre.programme -et des paramètres"

Notez les apostrophes et le caractère « pipe ». Ils sont nécessaires.

« votre.programme » peut être un script shell, awk ou perl, un programme C compilé ou tout autre sorte de filtre que vous auriez écrit.

Cependant « votre.programme » devrait avoir été écrit pour gérer une foule de détails sur la façon dont sendmail lui passera les messages (en-têtes et corps), sur les valeurs retournées à sendmail, sur la façon de gérer le verrouillage des fichiers (au cas où du courrier arriverait pendant que « votre.programme » est en train d'en traiter un, etc.).

4.2 Ce qu'offre procmail

Jusqu'à maintenant, j'ai traité des informations générales qui s'appliquent à tous les MTA/MDA's compatibles avec sendmail.

Afin d'être sûr que le courrier est passé à procmail pour être traité, la première étape consiste à créer le fichier .forward (il est plus sûr de le faire avant de configurer procmail, en supposant que les binaires du paquetage sont installés). Voici l'exemple canonique, tiré des pages du manuel de procmail :


"|IFS=' '&&exec /usr/local/bin/procmail -f-||exit 75 #VOTRE_USERNAME"

Cela semble horriblement compliqué par rapport à mon exemple précédent, mais c'est parce que ce dernier était incomplet pour raisons de simplicité.

Voici, en français, ce que tout cela signifie pour sendmail :

  • envoie le courrier aux commandes suivantes 
  • configure le « séparateur de champs » (IFS) du shell pour que ce soit un espace et, si ça marche (&&), exécute le programme nommé « /usr/local/bin/procmail » (ce chemin peut être différent, faites 'which procmail' pour connaître le chemin, ou 'locate procmail' si votre système dispose d'une base de données des emplacements de fichiers).
  • Un ensemble d'options est passé au programme procmail : « -f- » lui indique de mettre à jour la marque temporelle en première position de la ligne « From » de l'en-tête (ce dernier point est plutôt obscur et concerne les messages normalement stockés dans votre « incoming » ou fichier courrier ou « spool », comme UNIX l'appelle).
  • La partie suivante de cette commande .forward est l'opérateur « || » du Bourne shell qui est la suite de l'opérateur « et » (&&) utilisé précédemment. Il signifie « ou » . Si la commande/usr/local/bin/procmail -f- échoue, donc si elle retourne une erreur, on termine (« exit ») le traitement et on retourne un code d'erreur de 75 (nous supposons que cela signifie quelque chose pour sendmail, le programme qui a appelé cette commande).
  • La dernière partie de cette expression .forward est un commentaire qui, selon les pages du manuel :
    « n'est pas réellement un paramètre requis par procmail, il sera en fait ignoré par sh avant que procmail ne le voie ; cependant il est nécessaire pour contrer la sur-optimisation des programmes sendmail  »
  • Vous n'avez qu'à changer VOTRE_USERNAME par votre nom de login sur ce système.

Cette ligne compliquée peut être simplement reproduite dans la plupart des fichiers .forward avec très peu de modification et oubliée.

Si vous avez fait cela et rien d'autre, votre courrier ne sera pas affecté, procmail ne fera que consulter son ficher de recettes par défaut (.procmailrc) et, ne le trouvant pas, il effectuera ses actions par défaut sur chaque message. En d'autres mots, il ajoutera les nouveaux messages dans votre fichier de spool normal.

Si votre FAI utilise procmail comme agent de distribution local du courrier, vous pouvez vous passer de toute la partie sur l'utilisation du fichier .forward, ou vous pouvez quand même l'utiliser.

Dans tous les cas, l'étape suivante pour gérer automatiquement votre courrier est de créer un fichier .procmailrc dans votre répertoire d'accueil. Vous pourriez appeler ce fichier par un autre nom, mais vous devriez alors spécifier ce nom dans le fichier .forward (juste avant l'opérateur « || »). Presque tout le monde utilise le nom par défaut.

Prenons un exemple précis. Jusqu'à maintenant nous n'avons traité que de la façon dont tout est acheminé vers procmail, ce qui implique particulièrement sendmail et la syntaxe du Bourne shell. Presque tous les sendmail's sont configurés pour utiliser /bin/sh (le shell Bourne) afin d'interpréter les alias et les « pipes » du .forward.

Voici un fichier .procmailrc très simple :


:0c:
$HOME/mail.backup

Cela ne fait qu'ajouter une copie supplémentaire de tous les courriers entrants dans un fichier nommé « mail.backup » de votre répertoire d'accueil.

Notez qu'un paquet de variables d'environnement sont pré-configurées pour vous. Il a été suggéré de configurer explicitement SHELL=/bin/sh (ou le dérivé le plus proche du Bourne shell disponible sur votre système). Je n'ai jamais eu à me soucier de ça car les shells que j'utilise sur la plupart des systèmes sont compatibles Bourne.

Cependant, les utilisateurs de csh et d'autres shells doivent faire attention au fait que toutes les recettes procmail que j'ai vues utilisent la syntaxe Bourne.

La ligne :0 marque le début d'une « recette » (procédure, clause, ou autre). :0 peut être suivi par un nombre quelconque d'« options ». Il existe vraiment un nombre incalculable de combinaisons de ces options. La seule que nous utilisons ici est « c » pour « copy ».

Vous pourriez vous demander pourquoi la recette commence par un :0. Historiquement, on avait l'habitude d'utiliser :x (où « x » était un nombre). Cela indiquait à procmail que les « x » lignes suivantes étaient les conditions de cette recette. Plus tard, on ajouta un astérisque au début de chaque condition. Ainsi, elles n'avaient plus besoin d'être comptées à la main. :0 vint alors pour signifier quelque chose comme  « comptez-les vous même ».

Le deuxième deux-points de cette ligne marque la fin des options et le début du nom d'un fichier verrou. Comme l'on n'indique pas de nom, procmail en choisira un automatiquement.

Ce point est un peu compliqué. Le courrier peut arriver en rafale et si un nouveau message arrive pendant que votre script est toujours occupé à traiter le dernier message vous aurez plusieurs processus sendmail. Chacun traitera un message et ce n'est pas un problème en soi, mais si deux processus tentent d'écrire sur le même fichier en même temps, ils risquent de s'emmêler de façon imprévisible (le résultat consistera en un dossier courrier incorrectement formaté).

On indique donc à procmail qu'il devra créer un fichier verrou et vérifier sa présence. Dans ce cas particulier, nous ne nous préoccupons pas du nom de ce fichier (car nous n'aurons pas d'autres programmes écrivant dans le fichier de sauvegarde). Nous laissons donc le dernier champ (après les deux-points) à vide. procmail choisira lui-même le nom de son fichier de verrouillage.

Si nous omettons le : de la ligne d'en-tête de la recette, aucun fichier verrou ne sera utilisé.

Ceci sert lorsque nous voulons seulement lire des fichiers dans la recette, ou lorsque nous voulons seulement écrire des lignes d'entrées courtes dans un fichier et dans un ordre quelconque (comme les entrées des fichiers de trace).

4.3 Fonctionnement de procmail

procmail fonctionne de la façon suivante :

Il reçoit un message de sendmail (ou d'un MTA/MDA compatible sendmail). Plusieurs processus procmail peuvent s'exécuter en même temps car de nouveaux messages arrivent parfois plus vite qu'ils ne sont traités.

Il ouvre son fichier de recettes (.procmailrc par défaut, ou spécifié sur sa ligne de commande) et analyse chaque recette de la première à la dernière jusqu'à ce qu'un message ait été « distribué » (ou « mis à disposition » si le cas se présente).

Toute recette peut être une « mise à disposition » ou une « distribution » du message. Dès que le message est « distribué », procmail ferme ses fichiers, ôte ses verrous et se termine.

Si procmail atteind la fin de son fichier rc (et donc de tous les fichiers INCLUDE) sans « mise à disposition » du message, celui-ci est ajouté à votre fichier de spool (ce qui ressemble à une distribution normale pour vous et tous vos MUA's comme Eudora, elm, etc).

Ceci explique pourquoi procmail est si permissif si vous n'avez pas de .procmailrc. Il distribue simplement votre message au spool car il a atteint la fin de toutes les recettes (il n'y en avait pas).

L'option « c » force une recette à travailler sur une « copie » du message. Cela signifie que les actions de cette recette ne sont pas considérées comme des « mises à disposition » du message.

Sans l'option « c », cette recette récupérerait tous les messages entrants, et tout votre courrier finirait dans mail.backup. Aucun d'eux n'irait dans votre fichier de spool et aucune autre recette ne serait analysée.

La ligne suivante de cette recette exemple est simplement un nom de fichier. Comme les alias et les .forward de sendmail, procmail reconnaît trois types de mises à disposition de message. Vous pouvez l'ajouter à un fichier, le faire suivre à une autre adresse, ou le filtrer via un programme.

En fait, procmail gère une forme spéciale de « distribution » ou de « mise à disposition ». Si vous lui donnez un nom de répertoire (à la place d'un nom de fichier), il ajoutera le message dans ce répertoire sous la forme d'un fichier séparé. Le nom de ce fichier sera basé sur plusieurs facteurs plutôt compliqués dont vous n'avez pas à vous préoccuper, sauf si vous utilisez le système MH de Rand ou tout autre agent courrier « exotique ».

Une recette procmail est généralement formée de trois parties : une ligne de début (:0 et quelques options), certaines conditions (lignes commençant par « * » : caractère astérisque) et une ligne de « distribution » qui peut être un nom de fichier/répertoire ou une ligne commençant par un « ! » (point d'exclamation) ou un « | » (caractère pipe).

Voici un autre exemple :


:0
* ^From.*quelqu_un.que.je.n_aime.pas@quelquepart.org
/dev/null

C'est une recette simple, sans option, avec une condition et une distribution vers un fichier. Elle rejette simplement tout courrier en provenance de « quelqu'un que je n'aime pas » (/dev/null, sous UNIX, est une « corbeille à bits » sans fond, bien pratique pour se débarrasser de toute sortie indésirable ; MS-DOS utilise une concept identique mais il n'est pas aussi pratique).

En voici une plus compliqué :


:0
* !^FROM_DAEMON 
* !^FROM_MAILER
* !^X-Loop: monadresse@mamachine.mondomaine.org
| $HOME/bin/mon.script

Elle comprend un ensemble de conditions négatives (notez que celles-ci commencent toutes par le caractère « ! »). Cela signifie : pour tout courrier ne venant pas d'un « démon » (un processus automatique), ni d'un « mailer » (un autre processus automatique) et ne contenant aucune ligne d'en-tête de la forme : « X-Loop: monadresse...», envoie-le via le script qui se trouve dans mon répertoire bin.

Je pourrais mettre le script directement dans le fichier rc (ce que font beaucoup d'utilisateurs de procmail la plupart du temps). Ce script peut tout faire sur le courrier. Ici, ce qu'il fait a intérêt à être correct car procmail considèrera un tel courrier comme devant être distribué et toutes les recettes suivantes ne seront atteintes que par les courriers des DAEMONs, MAILERs et par les courriers ayant cette ligne X-Loop: particulière dans son en-tête.

En fait, ces deux conditions FROM_ particulières sont « spéciales ». Elles sont pré-configurées par procmail et font en fait référence à deux expressions rationnelles plutôt compliquées, conçues pour correspondre à ce que l'on peut trouver dans les en-têtes de la plupart des messages venant des démons et des mailers.

La ligne X-Loop: est une condition procmail normale. D'après le document RFC822 (qui décrit les en-têtes du courrier sur l'Internet), toute ligne commençant par X- est une en-tête « personnalisée ». Ceci signifie que tout programme de courrier peut ajouter autant de lignes X- qu'il le souhaite.

Un idiome procmail correct est d'ajouter une ligne X-Loop: à l'en-tête de tout message que nous envoyons et de vérifier notre propre ligne X-Loop: avant d'envoyer quoi que ce soit. Cela protège des « boucles de courrier », situations où notre message a été fait suivre ou « rebondit » vers nous et que nous lui répondons sans fin.

Voici donc un exemple détaillé de la façon d'utiliser procmail pour répondre automatiquement au courrier d'une personne particulière. Commençons par l'en-tête de la recette.


:0

... puis nous ajoutons notre seule condition (que le message soit de la personne en question) :


* ^FROMemmerdeur@spamhome.com

FROM est une valeur « magique » pour procmail, elle vérifie les lignes d'en-tête from, resent-by, et similaires. Vous pourriez aussi ajouter ^From: qui ne correspondrait qu'aux lignes de l'en-tête commençant par la chaîne « From: »

Le ^ (« caret ») est un « ancrage d'expression rationnelle » (phrase technique signifiant « il spécifie le motif doit être trouvé pour correspondre »). Un livre entier est consacré aux expressions rationnelles : « Mastering Regular Expressions » (O'Reilly & Associates). Celles-ci imprègnent beaucoup d'utilitaires Unix, langages de script et autres programmes. Il y a de légères différences entre les syntaxes des expressions rationnelles pour chaque application. Les pages de manuel de grep ou egrep sont un très bon endroit pour en apprendre plus.

Ici le caret signifie que le motif doit se trouver en début de ligne (c'est sa signification habituelle avec grep, edsed, awk/ et autres).

... et nous ajoutons deux conditions pour éviter les boucles et pour éviter de répondre aux systèmes automatiques.


* !^FROM_DAEMON 
* !^FROM_MAILER

(ce sont deux valeurs encore plus « magiques ». Les pages du manuel donnent les expressions rationnelles exactes assignées à ces mots-clés, si vous êtes curieux ou si vous avez besoin de bricoler une condition spéciale qui ressemble à l'une ou l'autre de celles-ci).

... et une de plus pour éviter un boucle ennuyeuse :


* !^X-Loop: monadresse@mamachine.mondomaine.org

(Tous ces motifs commencent par « ! » (point d'exclamation) car la condition énonce qu'aucune ligne de l'en-tête ne doit débuter par ces motifs. Ici (et dans la plupart des expressions rationnelles), le point d'exclamation « nie » ou « inverse » la signification du motif).

... ajoutons maintenant une « mise à disposition » : la réponse automatique.


| (formail -rk \
-A "X-Loop: votrenom@votreadresse.com" \
-A "Precendence: junk"; \
echo "Ne m'envoyez plus de courrier svp";\
echo "Ceci est une réponse automatisée";\
echo "Je ne verrai jamais votre message";\
echo "Donc, PASSEZ VOTRE CHEMIN" ) | $SENDMAIL -t -oi

C'est plutôt compliqué, mais voici comment ça fonctionne :

  • Le caractère « pipe » indique à procmail qu'il devra lancer un programme et lui fournir un message.
  • La parenthèse ouvrante est une construction du shell Bourne permettant de regrouper un ensemble de commandes de façon à ce que toutes les sorties de celles-ci se combinent en un seul « flot ». Nous expliquerons cela plus loin.
  • La commande formail est un programme très pratique, inclus dans le paquetage procmail. Il « formate » les en-têtes de courrier en fonction des options qui lui sont passées et de son entrée.
    • -rk indique à formail' qu'il doit formater une « réponse » et « garder » le corps du message. Avec ces options, formail attend un en-tête et un corps en entrée.
    • Les paramètres -A indique qu'il faut « ajouter » le paramètre suivant comme ligne d'en-tête. Les paramètres donnés à l'option -A doivent être entourés de guillemets pour que le shell traite la chaîne entière (espaces compris) comme un seul paramètre.
    • Les backslashs à la fin de chaque ligne indique qu'il faut traiter la ligne suivante comme la suite de celle-ci. Ainsi, toutes les lignes se terminant par un backslash sont passées au shell comme une seule longue ligne.
    • Ce caractère « backslash de fin » ou « continuation de ligne » est un idiome Unix fréquemment utilisé dans de nombreux langages de programmation et formats de fichiers de configuration.
    • Les points-virgules indiquent au shell d'exécuter une autre commande, elles permettent à plusieurs commandes d'être lancées sur la même ligne de commande.
    • Chaque commande echo devrait être raisonnablement compréhensible. Nous aurions pu utiliser une commande cat et mettre notre texte dans un fichier. Nous pouvons aussi appeler d'autres programmes ici, comme fortune ou date pour combiner leurs sorties avec le reste).
    • Venons-en maintenant à la parenthèse fermante. Elle marque la fin du bloc de commandes qui ont été combinées. La sortie de toutes celles-ci est envoyée dans le pipe suivant, qui lance la copie locale de sendmail (remarquez qu'il s'agit d'une autre variable que procmail configure gentiment pour nous).
    • L'option -t de sendmail lui indique de prendre l'adresse « To: » dans l'en-tête de son entrée (où formail -r l'a mis) et l'option -oi valide l'« option » de sendmail pour « ignorer » les lignes qui ne sont formées que d'un point (ne vous souciez pas de ce détail).

La plus grande difficulté dans la compréhension de procmail n'a rien à voir avec procmail lui-même. Les parties nécessitant le plus d'explication sont les expressions rationnelles (ces drôles de trucs sur les lignes de conditions « * »), les apostrophes du shell, la syntaxe des commandes et la façon de formater correctement un en-tête de réponse acceptable par sendmail (tout ce qui concerne formail' et sendmail).

La meilleure information que j'ai pu trouver sur les en-têtes de courrier est maintenue par Nancy McGough (sp??) sur les pages Web d'Infinite Ink :

http://www.jazzie.com/ii/

Des informations supplémentaires sur procmail se trouvent dans la Mini-FAQ d'Era Eriksson.

Il y a aussi quelques liens sur procmail sur mes pages personnelles


Précédent Suivant Table des Matières

Copyright (c) 1997, James T. Dennis -- Publié dans le n°14 de la Linux Gazette

Adaptation française : Éric Jacoboni.