Historiquement, j’utilise une adresse mail en free.fr. Malheureusement celle-ci était plus que spammée, environ 30 mails de spams par jour. Ce qui est drôle c’est que Free utilise un anti-spam mais ne fait pas l’effort de l’utiliser pour classifier automatiquement les mails afin d’avoir une boite propre et des clients heureux. J’ai donc utilisé les informations retournées par l’anti-spam dans chaque email pour les classifier. Pour ça il y a le super outil imapfilter, le tout packagé dans un container Docker et vous pouvez de nouveau utiliser votre email en free.fr.

Le projet complet est disponible sur mon gitlab1.

La classification du SPAM chez free.fr

En ouvrant le source de chaque mail de votre boite Free il y a un header qui catégorise le mail. Une petite recherche sur le net avec X-ProXaD-SC et vous trouverez des infos diverses sur les valeurs que peut prendre ce champ. Commençons par analyser le format de ce header, il est définit ainsi state=<state>:<category> score=<score>. Après observation sur un échantillon de mail voici comment Free fait varier les champs de ce header.

state category score
HAM CommercialEmailGeneric, CommercialEmailKnown, SocialNetwork 0 .. n
SPAM 0 .. n

Ci-dessous des exemples, la catégorie n’est pas forcément ajoutée. Plus la valeur du score est importante moins le mail à d’importance. Un mail de type HAM avec un score à 0 est un mail légitime.

X-ProXaD-SC: state=HAM score=0
X-ProXaD-SC: state=HAM:CommercialEmailKnown score=7
X-ProXaD-SC: state=HAM:CommercialEmailGeneric score=17
X-ProXaD-SC: state=HAM:SocialNetwork score=10
X-ProXaD-SC: state=HAM score=99

Classifer vos mails avec imapfilter

Dans mon cas j’ai effectué mon filtre avec imapfilter mais vous pouvez très bien utiliser les règles de filtrage depuis un webmail ou client mail. J’utilise imapfilter pour être sûr que mes mails seront classifiés vu que j’utilise un client mail lourd comme Thunderbird.

Pour faire simple je redirige tous les emails commerciaux dans le répertoire Junk, les mails des réseaux sociaux dans un répertoire que j’ai créé Social et tous les mails considérés comme SPAM ou HAM avec un score supérieur à 75 directement dans la poubelle aka Trash.

Avec imapfilter vous pouvez donc définir les règles de filtrage dans un fichier de config en Lua. L’ensemble des primitives pour filtrer sont disponibles sur le manuel d’imapfilter_config. Ci-dessous un extrait du code Lua pour classifier votre spam après avoir décoder le header. A savoir c’est mon premier script Lua il est certainement pas optimal mais pour le moment il tourne depuis plus de 6 mois sans accrocs.

spam = Set {}
social = Set {}
commercial = Set {}

results = account.INBOX:is_unseen()

for _, msg in ipairs(results) do
    mbox, uid = table.unpack(msg)
    spamcause = mbox[uid]:fetch_field("X-ProXaD-SC")
    print(os.date("%c") .. " headers >> " .. spamcause)
    fullstate, score = string.match(spamcause, "state=([a-zA-Z0-9 :]+) score=(%d+)")
    score = tonumber(score) or 0
    state, category = get_state(fullstate)

    print(os.date("%c") .. " state(" .. state .. ") category(" .. category .. ") score(" .. score .. ")")

    if state == "HAM" and (category == "CommercialEmailGeneric" or category == "CommercialEmailKnown")  then
        table.insert(commercial, msg)
    elseif state == "HAM" and category == "SocialNetwork" then
        table.insert(social, msg)
    elseif (state == "SPAM" or state == "HAM") and score > 75 then
        table.insert(spam, msg)
    end

end
commercial:move_messages(account.Junk)
social:move_messages(account.Social)
spam:move_messages(account.Trash)

Lancer l’ensemble dans un container Docker

Une fois le script de filtrage fait il faut le déployer quelque part. Pour m’assurer que ça marche partout sur mon laptop ou serveur j’ai packagé ça avec Docker. La version d’imapfilter est donc figée et le certificat SSL de Free est également ajouté. L’image de base est de type alpine, après build l’image Docker fait à peine 8MB. L’image est construite avec une étape intermédiaire de pre-build pour ne pas embarquer les dépendances de build dans l’image de production.

FROM alpine as builder
ARG version=v2.6.12
ARG archive=$version.tar.gz

ADD https://github.com/lefcha/imapfilter/archive/$archive /ws/
RUN apk add build-base openssl-dev lua-dev pcre-dev \
 && tar xvf /ws/$archive -C /ws/ \
 && cd /ws/imapfilter-${version#v} \
 && make install DESTDIR=/install

FROM alpine

COPY --from=builder /install /

RUN apk add pcre lua openssl \
 && addgroup -S imapfilter \
 && adduser -S imapfilter -G imapfilter
USER imapfilter
COPY --chown=imapfilter:imapfilter config.lua /home/imapfilter/.imapfilter/
RUN openssl s_client -connect free.fr:443 </dev/null 2>/dev/null|openssl x509 -outform PEM > /home/imapfilter/.imapfilter/certificates

ENTRYPOINT ["imapfilter"]

Une fois l’image dispo il suffit d’exécuter le container avec les 2 variantes qui nous intéresses, à savoir le login de votre boite et son mot de passe.

docker run --rm -it -e FREE_USERNAME=$FREE_USERNAME -e FREE_PASSWORD=$FREE_PASSWORD imapfilter-free.fr
Fetched field "X-ProXaD-SC" of username@imap.free.fr/INBOX[80732].
Thu Oct 10 05:32:41 2019 headers >> X-ProXaD-SC: state=HAM:CommercialEmailGeneric score=17
Thu Oct 10 05:32:41 2019 state(HAM) category(CommercialEmailGeneric) score(17)
1 messages moved from username@imap.free.fr/INBOX to username@imap.free.fr/Junk.
Fetched field "X-ProXaD-SC" of username@imap.free.fr/INBOX[80734].
Thu Oct 10 07:12:42 2019 headers >> X-ProXaD-SC: state=HAM:CommercialEmailGeneric score=17
Thu Oct 10 07:12:42 2019 state(HAM) category(CommercialEmailGeneric) score(17)
1 messages moved from username@imap.free.fr/INBOX to username@imap.free.fr/Junk.

Conclusion

Évidemment il n’y a plus beaucoup de monde qui utilise une boite Free, mais si vous voulez effectuer des post-traitements sur une boite mail que vous n’hébergez pas imapfilter est une solution. Ça a donné une seconde vie à ma boite Free, ce qui implique que je ne m’en suis toujours pas débarrassé !