Article publié dans Linux Magazine 79, janvier 2006.
La perle de ce mois-ci a été rédigée par Sébastien Aperghis-Tramoni, de Marseille.pm.
Avec un titre pareil, vous allez vous dire que ça part mal : pour récupérer ses mails, on utilise son client mail (quel qu'il soit), et ça marche très bien. Exact, je préfère ça aussi. Mais récemment, suite à un déménagement, je me suis retrouvé coupé de tout accès au net, et donc dans l'impossibilité de récupérer mes mails. Or je reçois environ 200 mails par jour et autant de spam. Et le quota sur Free n'est que de 25 Mo.
Donc au bout de d'un mois, mon compte s'est dangereusement rapproché
de la limite supérieure, et il me fallait récupérer mes mails avant
que les suivants ne soient refusés. La réponse toute faite de la
plupart des personnes est d'utiliser Fetchmail. Sauf que Fetchmail
tient absolument à renvoyer les mails sur un serveur qui se chargera
de les délivrer (un MDA, Mail Delivery Agent).
C'est une solution, mais je voulais simplement récupérer
mes mails, les stocker tous dans un simple fichier au classique format
mbox
. A priori, Fetchmail ne permet pas de faire ça. Voici donc un petit
script Perl pour récupérer les mails par POP3.
#!/usr/bin/perl use strict; use Email::Simple; use Net::POP3; sub usage { die "usage: getmail file\n" } my $server = 'pop.free.fr'; my $login = 'maddingue'; my $passwd = '5eckr3t'; my $mbox = shift or usage(); $| = 1; print "connecting to $server.. "; my $pop = new Net::POP3 $server or die "error: can't connect to $server: $!\n"; print "ok\n"; $pop->login($login, $passwd); $pop->ok or die "error: wrong username or password\n"; my ($undeleted, $size) = $pop->popstat; my $last = $pop->last; print "mail box size: $size\n", "$undeleted unread mail(s).\n", "last read mail was number $last\n\n"; open(MBOX, '>', $mbox) or die "error: can't write '$mbox': $!\n"; my $fetched = 0; for my $num (1..$undeleted) { my $msg = $pop->get($num); next unless ref $msg; mbox_envelope($msg); print MBOX @$msg, $/; $fetched += $pop->list($num); printf "\rfetched %2.0f%%", $fetched*100/$size; $pop->delete($num); } close(MBOX); print $/; $pop->quit; sub mbox_envelope { my $text = $_[0]; my $msg = new Email::Simple join '', @$text; my $date = $msg->header('Date'); my $from = $msg->header('Return-Path'); $from = $msg->header('From') unless $from; $from =~ s/[<>]//g; $from =~ /(\S+\@\S+)/ and $from = $1; unshift @$text, "From $from $date\n" }
Vous reconnaîtrez dans le début du script celui présenté il y a un an et demi pour vérifier son compte POP3. Il est augmenté d'une boucle qui récupère les messages l'un après l'autre et les stocke dans le fichier dont le nom a été donné en argument du script. Détaillons son déroulement.
Après s'être connecté ($pop = new Net::POP3 $server
), authentifié
($pop->login($login, $passwd)
) et avoir récupéré le nombre
de mails à lire ($pop->popstat
), une boucle se charge de traiter
chaque message. À noter qu'elle commence à 1 et non 0. On télécharge
chaque message avec $pop->get($num)
, qui le renvoie sous la
forme d'une référence à tableau de lignes. On le passe à la fonction
mbox_envelope()
dont le rôle est d'ajouter une ligne au format
From EXPEDITEUR DATE
.
Cette ligne, dite d'enveloppe, contient l'adresse de l'expéditeur telle
qu'elle a été donnée au serveur mail d'envoi avec la commande SMTP
MAIL FROM:
, suivie de la date d'envoi. On la reconstitue en prenant
la valeur du champ Return-Path:
, s'il est présent, qui contient
justement cette adresse, et sinon en prenant celle du champ From:
.
Cela peut sembler inutile mais cette ligne d'enveloppe, qui précède
les entêtes RFC-822, est nécessaire pour que le fichier soit au format
mbox
et que les clients mails puissent ensuite le lire.
Cette ligne est ensuite insérée en début du tableau qui contient le
message. Puis celui-ci est stocké dans le fichier, et le message est
marqué pour destruction sur le serveur POP3. À noter que les messages
ne sont effectivement détruits que lorsqu'on exécute $pop->quit()
,
donc jusqu'à ce moment-là, le script peut à tout moment être interrompu
sans que cela n'affecte vos mails sur le serveur.
On peut noter que ce script utilise, en plus du module Net::POP3
,
le module Email::Simple
du projet PEP[1] (Perl Email Project).
Ce projet initié par Simon Cozens consiste à fournir des modules plus
propres et plus simples que ceux qui existaient avant dans Mail::*
(y compris les siens). Il faut reconnaître qu'ici, son nom en
::Simple
n'est pas abusif puisque l'interface est très naturelle :
on passe le message en argument de new()
, et on peut récupérer
chaque entête avec la méthode header()
. La prochaine fois que vous
avez besoin d'un module Perl pour manipuler les mails, je vous
recommande donc très chaudement de regarder d'abord les modules
du projet PEP, qui sont véritablement simples à utiliser, même
s'ils souffrent parfois d'un certain manque de documentation.
Enfin, pour ceux qui se demanderaient si j'ai vraiment utilisé ce script, je réponds oui, et même plus d'une fois. Au total, j'ai ainsi pu récupérer les quelques 6000 mails (hors spam) qui se sont accumulés en deux mois sur mon compte.
Envoyez vos perles à perles@mongueurs.net
, elles seront peut-être
publiées dans un prochain numéro de Linux Magazine.
Copyright © Les Mongueurs de Perl, 2001-2011
pour le site.
Les auteurs conservent le copyright de leurs articles.