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 deprocmail
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 », commesendmail, deliver
etprocmail
), et MUA's (« mail user agents », commeelm, pine, /bin/mail, mh, Eudora
etPegasus
).
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 desendmail
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 configurerprocmail
, en supposant que les binaires du paquetage sont installés). Voici l'exemple canonique, tiré des pages du manuel deprocmail
 :
"|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 de75
(nous supposons que cela signifie quelque chose poursendmail
, 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é parsh
avant queprocmail
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èrementsendmail
et la syntaxe du Bourne shell. Presque tous lessendmail
'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 recettesprocmail
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 compatiblesendmail
). Plusieurs processusprocmail
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 commeEudora
,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
desendmail
,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épertoirebin
.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 carprocmail
considèrera un tel courrier comme devant être distribué et toutes les recettes suivantes ne seront atteintes que par les courriers desDAEMON
s,MAILER
s et par les courriers ayant cette ligneX-Loop:
particulière dans son en-tête.En fait, ces deux conditions
FROM_
particulières sont « spéciales ». Elles sont pré-configurées parprocmail
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 conditionprocmail
normale. D'après le document RFC822 (qui décrit les en-têtes du courrier sur l'Internet), toute ligne commençant parX-
est une en-tête « personnalisée ». Ceci signifie que tout programme de courrier peut ajouter autant de lignesX-
qu'il le souhaite.Un idiome
procmail
correct est d'ajouter une ligneX-Loop:
à l'en-tête de tout message que nous envoyons et de vérifier notre propre ligneX-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 » pourprocmail
, elle vérifie les lignes d'en-têtefrom, 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 où 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 degrep
ouegrep
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, ed
sed, 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 paquetageprocmail
. 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 commandecat
et mettre notre texte dans un fichier. Nous pouvons aussi appeler d'autres programmes ici, commefortune
oudate
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 queprocmail
configure gentiment pour nous).- L'option
-t
desendmail
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 » desendmail
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 avecprocmail
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 parsendmail
(tout ce qui concerneformail
' etsendmail
).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.