Filtrage du courrier électronique

Procmail
Mail::Audit
Mettre de l'ordre dans mon répertoire Mail
Configuration de Gnus
Rafinements
Installation du filtre
Que se passe-t-il en cas d'erreur ?
Obsolete

Ces notes expliquent comment je me suis débarassé de Procmail.

Procmail

On peut faire deux critiques à procmail.

D'une part, sa syntaxe est particulièrement cryptique. Ainsi, mon ~/.procmailrc commençait par des rappels de cette syntaxe.

# b  Feed the body to the pipe (default).
# f  Consider the pipe as a filter.
# h  Feed the header to the pipe (default).
# w  Wait for the filter or program to finish 
#    and check its exitcode  (normally  ignored); 
#    if the filter is unsuccessful, then the 
#    text will not have been filtered.
# A  This recipe will depend on the last preceding 
#    recipe (on  the  current block-nesting level) 
#    without the `A' or `a' flag. This allows you to
#    chain actions that depend on a common condition.

Plus loin, dans le même fichier (auquel je n'ai pas vraiment touché depuis près de trois ans), je constate que les règles commencent l'une des trois lignes suivantes. Quelle est la différence ? Que signifient les deux points au début ? à la fin ? le zéro ?

:0
:0 c
:0:
:0 B :

D'autre part, ce n'est pas un vrai langage de programmation, il y a donc certaines choses que l'on ne peut pas faire (on peut toujours s'en tirer en écrivant un programme externe, qui va lire un message ou son en-tête puis dire à procmail (à l'aide de son code de retour) ce qu'il faut en faire).

Mail::Audit

Mail::Audit est un module Perl permettant d'écrire des programmes de filtrage de courrier électronique.

http://www.perl.com/pub/a/2001/07/17/mailfiltering.html

Voici le programme que j'utilise réellement.

#!/share/nfs/users1/umr-tge/zoonek/gnu/Linux/bin/perl -w
use strict;
use Mail::Audit;
  
sub mess {
  my $mess = shift;
  open(A, '>>', "/share/nfs/users1/umr-tge/zoonek/log");
  print A "$mess\n";
  close A;
}
  
mess("begin");
  
my $mail = Mail::Audit->new(emergency=>"~/Mail/emergency_mbox");
  
$mail->noexit(1); 
$mail->accept("~/Mail/backup");
$mail->noexit(0);
  
# Mailing lists
my %lists = qw( 
                omega-admin      Omega
                pstricks-admin   pstricks
                owner-ctan-ann   CTAN-Announce
                owner-maple-list maple
              );
foreach my $a (keys %lists){
  # PROBLEME: il faudrait une méthode "sender"
  $mail->accept("~/Mail/$lists{$a}.spool") 
    if $mail->header =~ m/^Sender:.*$a/m;
}
  
mess("  not a mailing list");
  
# Important mails that should be _copied_ in a folder
my %important = qw( paypal    Argent
                    florachanxxx Argent
                    ebay      Argent
                    amazon    Argent
                    jamall    Argent
                    bk1       Argent
                );
$mail->noexit(1);
foreach my $a (keys %important) {
  $mail->accept("~/Mail/$important{$a}.spool") 
    if $mail->from =~ m/$a/i 
    or $mail->to   =~ m/$a/i;
}
$mail->noexit(0);
  
mess("  perhaps not something important");
  
# Poubelle
my @poubelle = qw/glegrand@ccr.jussieu.fr/;
foreach my $a (@poubelle) {
  $mail->accept("~/Mail/poubelle") 
    if $mail->from =~ m/$a/;
}
my $body = join('', @{ $mail->body });
$mail->accept("~/Mail/poubelle") 
  if $body =~ m/armée|militaire/;
  
mess("  It dit not go into the trash can");
  
## Probablement du spam
# Reconnu par son sujet
$mail->accept("~/Mail/spam.spool") 
  if $mail->subject =~ m/\b(congratulation|breast|money|mortgage|viagra|sex|cigar)s?\b/i;
$mail->accept("~/Mail/spam.spool") 
  if $mail->subject =~ m/\$\s*[0-9,]{3,}/;
# Reconnu par son absence de destinataire
$mail->accept("~/Mail/spam.spool") 
  unless $mail->to   =~ m/(zoonek|jussieu)/
      or $mail->from =~ m/(zoonek|jussieu)/
      or $mail->cc   =~ m/(zoonek|jussieu)/;
  
mess("  no spam");
  
## Probablement quelque chose de correct
#$mail->accept();
  
$mail->noexit(1); 
$mail->accept("~/Mail/zoonek");
$mail->noexit(0);
  
# This should be the very last line
mess("  accepting");
$mail->accept();
mess("accepted -- you should NOT be reading this");

Le programme est encore perfectible : j'ai envie de surcharger la méthode accept dans une sous-classe pour indiquer dans un journal (log) ce qui est advenu des messages (cela rendrait mon code plus simple : il n'y aurait plus de mess(...) partout).

Je pourrais aussi me débarasser des $mail->noexit() en définissant deux méthodes $mail->accept_and_leave et $mail->accept_and_continue.

On pourrait aussi rajouter un appel à Mail::SpamAssassin.

A FAIRE

Mettre de l'ordre dans mon répertoire Mail

Pour l'instant, il y a : des répertoires correspondant aux diverses mailing lists auxquelles je suis abonné, des fichiers de sauvegarde (sauvegarde des messages avant qu'ils ne passent par procmail, au début de leur passage dans procmail, à la fin de leur passage dans procmail, et aussi les messages rejetés par procmail), des fichiers de sauvegardes divers (innombrables), quelques répertoires de sauvegarde (en particulier pour les sites de commerce élecrtonique que j'utilise).

Les fichiers sont au format mailbox (tout dans un seul fichier, les messages se terminent par une ligne blanche et commencent par m/^From /), les répertoires sont au format nnmh, i.e., un fichier par message.

Je vais changer tout cela. Il y aura juste : les fichiers de sauvegarde automatique, les fichiers *.spool qui contiendront les messages non encore vus par Gnus, un répertoire mail contenant des répertoires correspondant aux différentes mailing lists ainsi que des répertoires : misc, pour le courrier normal, Argent, pour tout ce qui est commerce électronique, spam pour le spam ou les messages qui y ressemblent, Divers pour les messages sauvegardés (je sauvegarderai tout en même temps, en vrac, sans classer les choses par sujet, de manière à pouvoir faire des recherches à l'aide d'un simple grep).

Il faut donc convertir les différents format des fichiers utilisés en quelque chose d'uniforme.

cat **/*(.) > ALL.spool
perl -p -i -e 's/^X-From-Line:/From/; s/^From /\n\nFrom /' ALL.spool

Je me retrouve donc avec les fichiers

Mail/Argent.spool
Mail/CTAN-Announce.spool
Mail/Divers.spool
Mail/maple.spool
Mail/Omega.spool
Mail/pstricks.spool

Configuration de Gnus

Je veux que Gnus fasse les choses suivantes.

1. Prendre le courrier dans $MAIL et le mettre dans ~/Mail/mail/misc

2. Prendre le courrier dans les différents ~/Mail/*.spool et le mettre dans le répertoire correspondant ~/Mail/mail/$1

Je commence par effacer complètement la partie de mon ~/.emacs (en fait, ~/.xemacs/init.el) correspondant à Gnus.

(autoload 'gnus "gnus" "The Gnus Newsreader" t)
(setq gnus-nntp-server (or (getenv "NNTPSERVER") "news"))
(setq gnus-local-domain (or (getenv "DOMAINNAME") "math.jussieu.fr"))
(setq gnus-local-organization (or (getenv "ORGANIZATION")
                                  "Universite Paris VII"))
(setq gnus-default-article-saver 'gnus-summary-save-in-file)
(setq gnus-use-generic-from t)
(setq gnus-use-generic-path t)
(setq gnus-auto-select-same t)
(setq news-reply-header-hook nil)
(setq gnus-use-long-file-name t)
(setq gnus-default-subscribed-newsgroups
        '("nndoc:gnus-help" "fr.comp.text.tex" "comp.text.tex"))
(add-hook 'gnus-post-prepapare-hook 'mime-editor/set-transfer-level-8bit)
(add-hook 'gnus-article-display-hook 'gnus-article-highlight)
(add-hook 'gnus-article-display-hook 'gnus-article-hide-headers)
(setq gnus-group-sort-groups '(gnus-group-sort-by-real-name gnus-group-sort-by-level))
(add-hook 'gnus-summary-exit-hook 'gnus-summary-bubble-group)
(add-hook 'gnus-group-mode-hook 'gnus-topic-mode)
  
(add-hook 'gnus-summary-mode-hook 'my-alter-summary-map)
(defun my-alter-summary-map ()
  (local-set-key "E" 'gnus-summary-put-mark-as-expirable-next))
  
; Essayons de lire notre courrier avec Gnus...
; Je suggère d'utiliser nnmh qui va mettre un fichier par message
; (il y a aussi nnml, qui est beaucoup plus rapide, mais il 
;  s'attend à trouver une base de données contenant la liste 
;  des messages. C'est peut-etre un peu difficile à créer automatiquement 
;  et un peu long à créer lorsque l'on lande Gnus...)
(setq gnus-secondary-select-methods
      '((nnmh "private")))
;(setq nnmail-spool-file nil) ; Sinon Gnus prend le courrier dans $MAIL
                             ; et je ne le vois pas...
(setq nnmail-procmail-directory "Mail")
(setq nnmail-use-procmail t)
(setq nnmail-procmail-suffix ".procmail")

J'efface les autres fichiers de configuration de gnus

rm ~/.newsrc*

Dans le ~/.xemacs/init.el, on rajoute

(autoload 'gnus "gnus" "The Gnus Newsreader" t)

Ce n'est bien évidemment pas suffisant : quand je lance Gnus, il me propose un unique groupe (l'étoile devant indique le nombre d'articles contenus dans ce groupe : ici, le groupe n'a pas été trouvé).

*: nndraft:drafts

Pour charger les Niouzes, on pourrait ajouter dans le ~/.gnus

(setq gnus-select-method '(nntp "news.jussieu.fr"))

Mais ce n'est pas nécessaire, car ma variable d'environement NNTPSERVER a déjà la bonne valeur

% echo $NNTPSERVER
news.jussieu.fr

Il est possible d'avoir un serveur NNTP principal et d'autres secondaires (pour des groupes qui ne sont pas sur le serveur principal : il fut un temps où le groupe fr.lettres.langue.japonaise n'était pas sur news.jussieu.fr), simplement en tapant B une fois Gnus lancé.

Si c'est l'IS qui définit un fichier de configuration général, il peut renseigner la variable gnus-default-subscribed-newsgroups qui contient la liste des groupes par défaut (mais je n'en aurai pas besoin).

(setq gnus-default-subscribed-newsgroups
        '("nndoc:gnus-help" "fr.comp.text.tex" "comp.text.tex"))

On peut s'inscrire à quelques groupes, en tapant j (jump) pour trouver le groupe puis u (unsubscribe) pour le retenir.

     *: nndraft:drafts
   249: fr.lettres.langue.japonaise
   697: fr.comp.text.tex
   221: fr.comp.lang.perl
  1092: comp.text.tex
   157: comp.lang.perl
     4: comp.lang.perl.announce
  1568: comp.lang.perl.misc
   198: comp.lang.perl.modules
   149: comp.lang.perl.tk
    40: comp.lang.perl.moderated

Ah, mais ça n'est pas dans l'ordre !

C-c C-s

C'est mieux.

   157: comp.lang.perl
     4: comp.lang.perl.announce
  1568: comp.lang.perl.misc
    40: comp.lang.perl.moderated
   198: comp.lang.perl.modules
   149: comp.lang.perl.tk
  1092: comp.text.tex
   221: fr.comp.lang.perl
   697: fr.comp.text.tex
   249: fr.lettres.langue.japonaise
     *: nndraft:drafts

(On peut aussi sélectionner certains groupe, à l'aide de la commande # pour marquer un groupe ou à l'aide de la commande M w (attention, c'est bien M w et pas M-w) (la commande M U enlève toutes les marques) puis les trier à l'aide de la commande G P a.)

Commandes diverses

a    Ecrit un article (dans le groupe courrant)
M-g  Regarde s'il y a quelque chose de nouveau 
     dans le groupe courrant
q    Quitte le groupe courrant ou gnus
c    Quitte le groupe courrant en décrétant que 
     tous les articles ont été lus
R    répond à l'auteur d'un article en le citant
F    répond à un article (au groupe entier si c'est 
     un message des Niouzes, à l'auteur et aux gens 
     mis en copie si c'est un courriel).
C-k  Marque comme lus tous les articles suivants 
     du fil de discussion courrant
u    Marque l'article courrant comme "non lu"
d    Marque l'article courrant comme lu (attention : 
     il ne sera pas effacé)
E    Marque l'article courrant comme expiré (il sera effacé)
=    Rentre dans un groupe
-=   Rentre dans un groupe en affichant tous les 
     articles, y compris ceux qui ont déjà été lus

Ajoutons maintenant le mail. Le manuel nous dit que

It's quite easy to use Gnus to read your new mail. 
You just plonk the mail back end of your choice 
into gnus-secondary-select-methods, and things 
will happen automatically.

Par exemple, la ligne suivante prend le courrier dans $MAIL et le met dans ~/Mail/mail/misc

(setq gnus-secondary-select-methods '((nnml "")))

Voilà :

   110: comp.lang.perl
     2: comp.lang.perl.announce
  1235: comp.lang.perl.misc
    35: comp.lang.perl.moderated
   144: comp.lang.perl.modules
   119: comp.lang.perl.tk
 80376: comp.text.tex
   187: fr.comp.lang.perl
   597: fr.comp.text.tex
   197: fr.lettres.langue.japonaise
     6: nndraft:drafts
  1477: nnml:mail.misc

Le problème, c'est que les anciens messages ont disparu ???

Ah, oui : avant j'utilisais nnmh et pas nnml. Dans les deux cas, les messages sont mis chacun dans un fichier, mais avec nnml, il y a en plus une base de données qui permet de les manipuler plus facilement. Il suffit de recréer cette base de données.

M-x nnml-generate-nov-databases

Il reste maintenant le plus dur : ajouter les fichiers *.spool

Après avoir consulté

http://www.gnusfr.org/gen.php4/2002/02/27/27,0,1,0.html
http://www.gjefle.com/emacs/dot-gnus-v1.el

j'essaye

(setq mail-sources
      '((file)
        (directory :path "~/Mail" :suffix ".spool")
       )
)

Oui, ça marche ! (La toute première fois, il doit lire et indexer les quelques 30 Mo de Mail qui trainent sur mon compte, cela prend une trentaine de secondes.

Rafinements

UTF8

Problème : il n'utilise pas naturellement UTF8 quand on mélange du japonais et du français dans un même message, il découpe le message en plusieurs morceaux MIME...

Cela semble être géré par la variable gnus-group-charset-alist, qui contient une liste de couple groupe/codage (en fait, ce ne sont pas les noms exacts des groupes mais des expressions régulières) et dont la valeur par défaut est

( 
  ("^hk\\>\\|^tw\\>\\|\\<big5\\>" cn-big5)
  ("^cn\\>\\|\\<chinese\\>" cn-gb-2312)
  ("^fj\\>\\|^japan\\>" iso-2022-jp-2)
  ("^tnn\\>\\|^pin\\>\\|^sci.lang.japan" iso-2022-7bit)
  ("^relcom\\>" koi8-r)
  ("^fido7\\>" koi8-r)
  ("^\\(cz\\|hun\\|pl\\|sk\\|hr\\)\\>" iso-8859-2)
  ("^israel\\>" iso-8859-1)
  ("^han\\>" euc-kr)
  ("^alt.chinese.text.big5\\>" chinese-big5)
  ("^soc.culture.vietnamese\\>" vietnamese-viqr)
  ("^\\(comp\\|rec\\|alt\\|sci\\|soc\\|news\\|gnu\\|bofh\\)\\>" iso-8859-1)
  (".*" iso-8859-1)
)

On va simplement rajouter, au début de la liste, le couple

  ("^fr.lettres.langue.japonaise\\>" utf-8)

Cela peut se faire ainsi :

(require 'gnus-sum)
(setq gnus-group-charset-alist
      ( cons
        '("^fr.lettres.langue.japonaise\\>" utf-8)
        gnus-group-charset-alist
      )
)

Ou alors, si on veut rajouter plusieurs groupes

(require 'gnus-sum)
(setq gnus-group-charset-alist
      ( append
        (list 
          '("^fr.lettres.langue.japonaise\\>" utf-8)
          '("^fr.test\\>" utf-8)
        )
        gnus-group-charset-alist
      )
)

On aurait aussi pu modifier la variable de manière un peu plus interactive :

M-x customize-variable gnus-group-charset-alist

Mais ça ne marche pas : d'une part, ca lui demande d'ignorer le codage normalement indiqué dans l'en-tete des messages, d'autre part, il n'utilise pas utf8 lorsqu'il en envoie.

Essayons avec la variable gnus-group-posting-charset-alist.

(require 'gnus-sum)
(setq gnus-group-posting-charset-alist
      ( append
        (list
          '("^fr.lettres.langue.japonaise\\>" utf-8)
          '("^fr.test\\>" utf-8)
        )
        gnus-group-charset-alist
      )
)

Ca ne marche pas non plus.

A FAIRE

(On me dit qu'il suffit de charger ucs avant gnus, mais c'est bien ce que je fais...)

Défilement

Problème : quand je lis un message, les commandes pour le faire défiler ne marchent pas (SPC ou RET, par contre > marche). Je suis obligé d'utiliser la souris...

Je vérifie, en tapant C-h k SPC puis C-h k RET que ces touches sont bien liées aux bonnes fonction.

SPC runs `gnus-summary-next-page'
`gnus-summary-next-page' is an interactive compiled Lisp function
  -- loaded from "gnus-sum"
(gnus-summary-next-page &optional LINES CIRCULAR)

Documentation:
Show next page of the selected article.
If at the end of the current article, select the next article.
LINES says how many lines should be scrolled up.

If CIRCULAR is non-nil, go to the start of the article instead of
selecting the next article when reaching the end of the current
article.


RET runs `view-scroll-lines-up'

`view-scroll-lines-up' is an interactive compiled Lisp function
  -- loaded from "view-less"
(view-scroll-lines-up P)

Documentation:
Scroll up prefix-arg lines, default 1.


> runs `gnus-summary-end-of-article'

`gnus-summary-end-of-article' is an interactive compiled Lisp function
  -- loaded from "gnus-sum"
(gnus-summary-end-of-article)

Documentation:
Scroll to the end of the article.

On regarde donc dans le fichier gnus-sum.el quelles sont les différences entre les fonctions gnus-summary-end-of-article (qui marche) et gnus-summary-next-page (qui ne marche pas).

(defun gnus-summary-end-of-article ()
  "Scroll to the end of the article."
  (interactive)
  (gnus-summary-select-article)
  (gnus-configure-windows 'article)
  (gnus-eval-in-buffer-window gnus-article-buffer
    (widen)
    (goto-char (point-max))
    (recenter -3)
    (when gnus-page-broken
      (gnus-narrow-to-page))))

La fonction gnus-summary-next-page a une définition beaucoup trop longue. Je vais donc la redéfinir moi-même.

(defun my-gnus-summary-next-page ()
  "Scroll down the article"
  (interactive)
  (gnus-summary-select-article)
  (gnus-configure-windows 'article)
  (gnus-eval-in-buffer-window gnus-article-buffer
    (widen)
    ;(goto-char (point-max))
    (next-line (- (window-height) next-screen-context-lines))
    (recenter -3)
    (when gnus-page-broken
      (gnus-narrow-to-page))))

Je constate qu'en tapant M-x my-gnus-summary-next-page à l'endroit voulu, ça marche. On peut maintenant la lier à la touche SPC.

(defun my-alter-summary-map ()
  ; pour les deux lignes suivantes, voir ci-dessous
  ;(local-set-key "E" 'gnus-summary-put-mark-as-expirable-next)
  ;(local-set-key "d" 'gnus-summary-put-mark-as-read-next)
  (local-set-key " " 'my-gnus-summary-next-page)
)

Exercice : faire la même chose pour avancer d'une ligne.

ISO-8859-15

Problème : il ne reconnait pas le codage ISO-8859-15. Ca vient d'Emacs, pas de Gnus... (il faudra regarder avec une version un peu plus récente).

Marquage des messages

Problème : la commande E (pour faire expirer les messages) se positionne ensuite sur le message non lu suivant -- je préfèrerais le message suivant. Idem pour la commande d (pour dire qu'un message est lu).

(add-hook 'gnus-summary-mode-hook 'my-alter-summary-map)
(defun my-alter-summary-map ()
  (local-set-key "E" 'gnus-summary-put-mark-as-expirable-next)
  (local-set-key "d" 'gnus-summary-put-mark-as-read-next
)

Sauvegarde

Problème : quand on veut sauvegarder des messages (pas pour le mail, mais pour les Niouzes), le fichier qu'il propose par défaut n'est plus le même.

(setq gnus-default-article-saver 'gnus-summary-save-in-file)
(setq gnus-file-save-name 'gnus-plain-save-name)

Maintenant, les articles du groupe foo.bar seront sauvegardés dans le fichier ~/News/foo.bar.

Le problème, c'est que j'ai déjà plein de fichiers sous un format différent : ~/News/foo.bar/1

cd ~/News
mkdir TMP
mv *(/) TMP/
rename 's#^TMP/(.*)/1$#$1# TMP/*/1
rm -rf TMP

Hiérarchie

Il est possible de répartir les groupes en une hiérarchie. Il faut pour cela être dans le mode (mineur) "topic".

(add-hook 'gnus-group-mode-hook 'gnus-topic-mode)

Quand on lance Gnus, on voit alors

[ Gnus -- 3950 ]
  [ misc -- 3950 ]
       123: comp.lang.perl
         6: comp.lang.perl.announce
      1443: comp.lang.perl.misc
        35: comp.lang.perl.moderated
       168: comp.lang.perl.modules
       135: comp.lang.perl.tk
        73: comp.text.tex
        25: fr.comp.lang.perl
        69: fr.comp.text.tex
       227: fr.lettres.langue.japonaise
        91: fr.rec.anime
*        0: fr.rec.anime.selection
*        0: nnml:Argent
       221: nnml:CTAN-Announce
       837: nnml:Divers
       230: nnml:Omega
         2: nnml:mail.misc
       142: nnml:maple
       122: nnml:pstricks
         1: nnml:spam

Ensuite, on joue avec les commandes

T n   crée un Topic
C-k   Cut
C-y   Paste

Voici le résultat :

[ Gnus -- 3950 ]
  [ Mail -- 1555 ]
       221: nnml:CTAN-Announce
       837: nnml:Divers
       230: nnml:Omega
         2: nnml:mail.misc
       142: nnml:maple
       122: nnml:pstricks
         1: nnml:spam
  [ News -- 2395 ]
       123: comp.lang.perl
         6: comp.lang.perl.announce
      1443: comp.lang.perl.misc
        35: comp.lang.perl.moderated
       168: comp.lang.perl.modules
       135: comp.lang.perl.tk
        73: comp.text.tex
        25: fr.comp.lang.perl
        69: fr.comp.text.tex
       227: fr.lettres.langue.japonaise
        91: fr.rec.anime
*        0: fr.rec.anime.selection

On peut ouvrir ou fermer un Topic (i.e., afficher ou cacher ses éléments) à l'aide de la commande = ou en cliquant dessus avec la touche du milieu de la souris.

[ Gnus -- 3950 ]
  [ Mail -- 1555 ]
       221: nnml:CTAN-Announce
       837: nnml:Divers
       230: nnml:Omega
         2: nnml:mail.misc
       142: nnml:maple
       122: nnml:pstricks
         1: nnml:spam
  [ News -- 2395 ]...

Cette hiérarchie (ainsi qu'une grande partie de la configuration de Gnus, ainsi que la liste des messages lus, expirables, sauvegardés, auxquels on a répondu, etc.) est stoquée dans le fichier ~/.newsrc.eld, sous la forme suivante.

(setq gnus-topic-topology 
      '(
         ("Gnus" visible) 
         (("Mail" visible nil nil)) 
         (("News" visible nil nil))
       )
)

(setq gnus-topic-alist 
      '(
         ("Mail" "nnml:Argent" "nnml:CTAN-Announce" 
          "nnml:Divers" "nnml:Omega" "nnml:mail.misc" 
          "nnml:maple" "nnml:pstricks" "nnml:spam"
         ) 
      ("News" "comp.lang.perl" "comp.lang.perl.announce" 
          "comp.lang.perl.misc" "comp.lang.perl.moderated" 
          "comp.lang.perl.modules" "comp.lang.perl.tk" 
          "comp.text.tex" "fr.comp.lang.perl" 
          "fr.comp.text.tex" "fr.lettres.langue.japonaise" 
          "fr.rec.anime" "fr.rec.anime.selection" 
          "nndraft:drafts"
        ) 
        ("Gnus")
      )
)

Installation du filtre

Il tournera sur la machine qui gère le mail, i.e.,

% host smtp
smtp.institut.math.jussieu.fr. is an alias for smtp.math.jussieu.fr.
smtp.math.jussieu.fr. is an alias for riemann.math.jussieu.fr.
riemann.math.jussieu.fr. has address 134.157.13.100

Ca n'est pas comme ça qu'on est sensé trouver la machine qui gère le mail. Le plus simple est de regarder l'en-tête des messages qu'on reçoit.

From nobody@mailgate.org  Fri Jun 14 12:05:30 2002
Return-Path: <nobody@mailgate.org>
Received: from shiva.jussieu.fr (shiva.jussieu.fr [134.157.0.129])
          by riemann.math.jussieu.fr (8.12.1/jtpda-5.3.3) with ESMTP id g5EA5TTp084132
          for <zoonek@borel4.institut.math.jussieu.fr>; Fri, 14 Jun 2002 12:05:30 +0200 (CEST)
Received: from mail.mailgate.org (mail.mailgate.org [212.177.105.138])
          by shiva.jussieu.fr (8.12.4/jtpda-5.4) with ESMTP id g5EA5T2D032720
          for <zoonek@borel4.institut.math.jussieu.fr>; Fri, 14 Jun 2002 12:05:29 +0200 (CEST)
Received: (from news@localhost)
        by mail.mailgate.org (8.11.3/8.11.3) id g5EA5NR00843
        for zoonek@borel4.institut.math.jussieu.fr; Fri, 14 Jun 2002 12:05:23 +0200

Une autre manière de trouver cette machine (mais qui ne donne pas la bonne réponse : on n'a pas la machine qui gère le courrier en ...@math.jussieu.fr, mais celle qui sait trouver la machine qui le gère), est de taper

host -t mx math.jussieu.fr

Revenons donc à riemann.math.jussieu.fr. D'après http://www.institut.math.jussieu.fr/informatique/serveurs.html il s'agit d'un PC sous FreeBSD 4.2.

Pour pouvoir installer mon filtre, il me faut Perl et Mail::Audit. Le problème, c'est que certains modules (pas Mail::Audit, mais peut-petre certains des modules qu'il utilise) contiennent des morceaux en C, qu'il faut compiler pour une plateforme donnée. De surcroit, pour que les dépendances entre modules se résolvent toutes seules, je préfère utiliser le module CPAN, qui suppose que c'est moi-même qui ai installé Perl. Enfin, je ne pense pas avoir le droit de me logguer sur cette machine (mais je n'ai pas vérifié -- en tout cas, un utilisateur normal n'a aucune raison de vouloir se logguer sur cette machine). Je vais donc essayer de tout compiler sur cantor (qui est sous FreeBSD 4.3, ce n'est pas la même version, mais j'espère que ça marchera).

sh Configure -Dprefix=$HOME/gnu/`uname` -Uinstallusrbinperl -des
make
make test
make install

Ensuite on essaye d'installer Mail::Audit

perl -MCPAN -e shell
  install Mail::Audit

Mais ça plante complètement : les chemins d'accès aux différents exécutables sont faux.

perl -MCPAN -e shell
  o conf ftp      /usr/local/bin/ncftp
  o conf gzip     /usr/bin/gzip 
  o conf ncftpget /usr/local/bin/ncftpget
  o conf lynx     /usr/local/bin/lynx
  o conf tar      /usr/bin/tar
  install Mail::Audit

Ca plante toujours, car lynx décompresse les fichiers *.gz sans le dire.

rename 's/\.gz$//' `file ~/.cpan/**/*.gz | grep ASCII | sed 's/:.*//'`
gzip ~/.cpan/**/*.(txt|data) 

perl -MCPAN -e shell
  install Mail::Audit

Lors de l'installation, on constate qu'il est effectivement amené à compiler certaines choses.

Je met mon script de filtrage de mail dans ~/bin/scripts/mail_filter.pl

Je l'appelle depuis le ~/.forward de la manière suivante

/share/nfs/users1/umr-tge/zoonek/Mail/dot_forward_backup
/share/nfs/users1/umr-tge/zoonek/Mail/SAVE_qskdbgskdgf
"|IFS=' ' && f=/share/nfs/users1/umr-tge/zoonek/bin/scripts/mail_filter.pl && test -f $f && p=/share/nfs/users1/umr-tge/zoonek/gnu/`uname`/bin/perl && test -x $p && exec $p $f || exit 75 #zoonek"

On remarquera les deux première lignes du ~/.forward : la première est toujours là et garde une copie de chaque message ; la seconde n'est là que le temps d'installer le filtre -- c'est là, par exemple, qu'on trouvera les messages d'erreur, qui sont envoyés par mail à l'expéditeur du message qui n'est pas passé. Voici un exemple de tel message.

From Mailer-Daemon  Thu Jun 13 16:00:52 2002
Return-Path: <Mailer-Daemon>
Received: from localhost (localhost)
          by riemann.math.jussieu.fr (8.12.1/jtpda-5.3.3) id g5DE0qTp084765
          ; Thu, 13 Jun 2002 16:00:52 +0200 (CEST)
Date: Thu, 13 Jun 2002 16:00:52 +0200 (CEST)
From: Mailer-Daemon (Mail Delivery Subsystem)
Subject: Returned mail: see transcript for details
Message-Id: <200206131400.g5DE0qTp084765@riemann.math.jussieu.fr>
To: <zoonek>
MIME-Version: 1.0
Content-Type: multipart/report; report-type=delivery-status;
        boundary="g5DE0qTp084765.1023976852/riemann.math.jussieu.fr"
Auto-Submitted: auto-generated (failure)
  
This is a MIME-encapsulated message
  
--g5DE0qTp084765.1023976852/riemann.math.jussieu.fr
  
The original message was received at Thu, 13 Jun 2002 16:00:51 +0200 (CEST)
from borel4.institut.math.jussieu.fr [134.157.13.114]
  
   ----- The following addresses had permanent fatal errors -----
"|IFS=' ' && f=/share/nfs/users1/umr-tge/zoonek/bin/scripts/mail_filter.pl
&& test -f $f && p=/share/nfs/users1/umr-tge/zoonek/gnu/`uname`/bin/perl &&
test -x $p && exec $p $f || exit 75 #zoonek"
    (expanded from: <zoonek>)
  
   ----- Transcript of session follows -----
Semicolon seems to be missing at /share/nfs/users1/umr-tge/zoonek/bin/scripts/mail_filter.pl line 81.
syntax error at /share/nfs/users1/umr-tge/zoonek/bin/scripts/mail_filter.pl line 82, near ") mess"
Execution of /share/nfs/users1/umr-tge/zoonek/bin/scripts/mail_filter.pl aborted due to compilation errors.
554 5.3.0 unknown mailer error 255
  
--g5DE0qTp084765.1023976852/riemann.math.jussieu.fr
Content-Type: message/delivery-status
  
Reporting-MTA: dns; riemann.math.jussieu.fr
Received-From-MTA: dns; borel4.institut.math.jussieu.fr
Arrival-Date: Thu, 13 Jun 2002 16:00:51 +0200 (CEST)
  
Final-Recipient: rfc822; zoonek@riemann.math.jussieu.fr
X-Actual-Recipient: rfc822; |IFS=' ' && f=/share/nfs/users1/umr-tge/zoonek/bin/scripts/mail_filter.pl && test -f $f && p=/share/nfs/users1/umr-tge/zoonek/gnu/`uname`/bin/perl && test -x $p && exec $p $f || exit 75 #zoonek@riemann.math.jussieu.fr
Action: failed
Status: 5.0.0
Last-Attempt-Date: Thu, 13 Jun 2002 16:00:52 +0200 (CEST)
  
--g5DE0qTp084765.1023976852/riemann.math.jussieu.fr
Content-Type: message/rfc822
  
Return-Path: <zoonek>
Received: from borel4.math.jussieu.fr (borel4.institut.math.jussieu.fr [134.157.13.114])
          by riemann.math.jussieu.fr (8.12.1/jtpda-5.3.3) with ESMTP id g5DE0pTp084764
          for <zoonek>; Thu, 13 Jun 2002 16:00:51 +0200 (CEST)
From: zoonek (Vincent Zoonekynd)
Received: from (zoonek@localhost)
          by borel4.math.jussieu.fr (8.11.6/jtpda-5.3.2) id g5DE0o800791
          for zoonek; Thu, 13 Jun 2002 16:00:50 +0200
Date: Thu, 13 Jun 2002 16:00:50 +0200
Message-Id: <200206131400.g5DE0o800791@borel4.math.jussieu.fr>
To: zoonek
Subject: llllllllllll
  
lllllllll
  
--g5DE0qTp084765.1023976852/riemann.math.jussieu.fr--

Que se passe-t-il en cas d'erreur ?

Si l'erreur est dans le script, celui-ci se terminera avec un code de retour égal à 255 et Sendmail concluera à une erreur fatale permanente ("The following addresses had permanent fatal errors", comme dans l'exemple ci-dessus) et renverra le message à son expéditeur.

Si l'erreur est ailleurs, par exemple, si le script n'est plus à cet endroit, ou si perl n'est plus là, la ligne correspondante du ~/.forward renverra un code de retour égal à 75, qui désigne une erreur temporaire (voir sysexits.h pour les détails). Dans ce cas, Sendmail met le message en attente et réessaye de l'envoyer trois heures plus tard. En cas de nouvel échec, il est renvoyé à l'expéditeur.

Obsolete

Notes prises il y a quelques années (été 1999)

Pour invoquer procmail à la main...

ORGMAIL=/var/spool/mail/$LOGNAME
lockfile -l3600 -ml
cat $ORGMAIL >> .newmail && cat /dev/null >$ORGMAIL
lockfile -mu
formail -s procmail <.newmail && rm -f .newmail




Sur gauss :
 - procmail n'est pas installé au même endroit
 - procmail n'est pas installé correctement (si je le compile moi-même, ça
   marche très bien)

Voir si on a le droit de mettre $HOME/gnu/bin/`uname`/procmail dans ~/.forward

Oui, on peut.

Quelques explications sur le contenu du ~/.forward
"|/usr/bin/procmail -Yf- || exit 75 #zoonek"

Il faut que tout soit compris entre guillemets.
Le début de la commande est relativement clair.
La liste des codes d'erreurs est dans le fichier sysexits.h.
Celui qui nous intéresse correspond à
  #define EX_TEMPFAIL     75      /* temp failure; user is invited to retry */
On lui demande donc de recommencer en cas d'erreur, un peu plus tard,
généralement une heure, 
en espérant que l'erreur soit corrigée entre temps.
Si trois jours plus tard l'erreur n'est pas corrigée, 
on abandonne et le message revient à l'envoyeur.

Attention : cela permet de repérer des erreurs dans le programme lancé 
dans le .forward, par exemple dans le fichier de configuration.
Si on commet un erreur dans le ~/.forward lui-meme, par exemple sur 
l'emplacement de procmail, ça ne marchera pas :
le .forward peut contenir plusieures lignes, on va réessayer celle qui
a posé problème ; si elle a été modifiée entre temps, on n'en tient pas compte.
 
Quant à la fin de la ligne, à savoir #zoonek, 
je ne sais pas du tout ce que c'est.
Je constate que dans les messages d'erreur, c'est remplacé par
 ...#zoonek@math.jussieu.fr

Vincent Zoonekynd
<zoonek@math.jussieu.fr>
latest modification on ven jun 14 12:26:48 CEST 2002