utilisateurs postfix virtuels : ajouter un répondeur « vacation »
Avec mes précédents articles ci-dessous, vous avez de quoi monter une architecture complète de mails avec utilisateurs virtuels. Pour faire simple.
- configurer postfix pour gérer des utilisateurs virtuels
- monter une architecture complète « postfix / postgrey / amavisd-new / clamav / spamassassin »
Il manque cependant un morceau : la possibilité de faire appel à des « procmail » personnalisés pour ces utilisateurs virtuels.
Lorsqu’on n’est pas avec des utilisateurs virtuels, chaque utilisateur réel (ayant un compte utilisateur, donc) utilise généralement son ~/.procmailrc
pour trier un peu ou - cas qui m’intéresse particulièrement – activer son répondeur d’absence, « vacation
« pour ne pas le nommer.
Dans le cas d’utilisateurs virtuels, c’est sensiblement différent. C’est ce que je décrirai dans cet article. Ce n’est au final pas compliqué, mais il faut comprendre le rôle de chaque composant et les limites de fonctionnement de chaque outil.
En effet, je n’ai pas trouvé de doc ultra-claire sur le sujet sur le web, surtout les bricoles de chacun. Avec un peu de recul, et, voyant ma propre solution, j’ai l’impression qu’il y a tellement de configurations possibles (maildrop et pas procmail, mes utilisateurs virtuels comme ci, pas comme ça, il utilise postfixadmin et pas moi etc) qu’il est impossible d’écrire un truc qui n’est pas spécifique.
Le plus dur est donc de comprendre ce qu’on fait pour transposer à sa conf. Je tâcherai donc, comme d’hab, d’expliquer ce que je fais plutôt que de copier-coller les fichiers de conf.
Allez, let’s go pour la mise en place sur la base d’une archi postfix & co comme décrite dans les docs mentionnées en début de cet article.
Ah, dernier point : à la base, et tel que je le décris, l’utilisateur ne pourra pas mettre lui même son répondeur en place. Dans mon cas, ce n’est pas important. En effet, j’utilise des utilisateurs virtuels car il s’agit d’un serveur frontal de mails (qui trie le spam, en gros), livre les messages dans des arborescences virtuelles en attendant d’être POPées depuis un backend de mails quelconque (un vilain Exchange ). Donc, le répondeur d’absence des utilisateurs « physiques » est géré par eux-mêmes dans Outlook « normalement », et je n’applique ce principe de répondeur qu’exceptionnellement, à quelques boîtes mails IMAP génériques, qui n’ont pas vraiment de notion de « vacances ». Des boîtes partagées entre plusieurs personnes, si vous voulez, mais stockées sur le frontal et pas dans le backend, pour diverses raisons dont on se moque ici. Après vous pourrez toujours bricoler un truc pour que tout un chacun accède à son procmail ou son message d’asbence pour le mettre, l’enlever etc.
Le principe
On veut activer le répondeur de toto@domaine.fr en utilisant l’outil « vacation
» qui gère très bien les réponses. « vacation
» ne joue qu’avec des comptes utilisateurs existants. Premier problème.
Pour y arriver, on va créer des alias pour ce compte virtuel « toto@domaine.fr » afin que postfix « forward » (du nom de la table « forwardings » gérant les alias des utilisateurs virtuels) tout mail à destination de toto@domaine.fr vers 2 endroits :
- le réel toto@domaine.fr, histoire de délivrer le mail quand même, au final
- et en plus vers un certain toto@vacation.domaine.fr qui n’existe pas
Ce dernier nom « vacation.domaine.fr » n’a pas besoin d’exister au sens DNS et ne correspond pas non plus à un MX réel. On va juste créer un « transport » (du nom de la table MySQL qu’on a créée avec les docs précédentes) particulier afin de router les messages à destination du domaine « vacation.domaine.fr » vers un « pipe
» particulier de postfix qu’on va créer pour l’occasion.
Ce « pipe
» UNIX, composant qu’on ajoute à la chaîne postfix, gèrera en fait l’appel à procmail
configuré d’une manière globale (un gros procmailrc
générique, si vous voulez).
Ce procmail
fera ensuite un tri sur le nom du destinaire et appellera « vacation
» lorsqu’on le veut avec un message personnalisé.
C’est ce procmail global qu’il conviendrait de découper (avec des INCLUDE), ainsi que les fichiers de messages d’absence qui vont avec, si on voulait donner la main d’une manière pas super pratique (FTP ? samba ?) à des utilisateurs réels sur leur répondeur de compte virtuel…
Je me suis basé sur pas mal de docs bizarroïdes, et surtout sur les quelques explications trouvées ici. Le cheminement y est, mais c’est pas détaillé sur le principe et le type propose son propre script de répondeur ; script qui peut générer une belle boucle infinie entre répondeurs, à mon humble avis. Ce risque n’existe pas avec « vacation
« , car il garde une liste des gens « déjà répondus », sauf si vous forcez à répondre à chaque fois.
Mise en place
Paquets, utilisateur etc
Au besoin, suivant l’état de votre installation :
aptitude install procmail vacation
Ensuite, j’ai expliqué que « vacation
» ne travaillait que sur un compte réel. Je lui dédie donc un compte :
useradd -m vacation -s /bin/nologin -c "Utilisateur vacation"
Création du pipe UNIX
On crée le processus qui sera en charge de router (de manière interne à postfix) les messages arrivant dans un pipe
qu’on nomme « repondeur » vers procmail
(lui même appelant le cas échéant le programme de répondeur « vacation
« ).
Dans /etc/postfix/master.cf
, à la fin (peu importe), on définit ce pipe comme suit :
#ajout d'un appel à procmail pour gérer certains 'vacation' sur les boites IMAP #attention, l'appel à ce pipe est géré dans la table des transports virtuels + des forwardings qui vont bien repondeur unix - n n - 10 pipe flags=Rq user=vacation argv=/usr/bin/procmail -Y -m /etc/postfix/procmail-global-repondeur.rc ${sender} ${recipient}
Les espaces avant « flags » sont importants, c’est ce qui explique à postfix qu’il s’agit d’option du pipe
nommé « repondeur ».
Je décrirai le fichier /etc/postfix/procmail-global-repondeur.rc
plus tard. C’est lui qui contiendra les appels aux « vacation
» de tels et tels utilisateurs.
J’avoue ne pas être super sûr des flags utilisés, voyez man pipe
au besoin.
transport virtuel
Si votre base MySQL est exactement celle que je décris dans mes précédentes documentations, insérez une ligne dans la table « transport » afin d’avoir :
mysql> select * from transport; +---------------------+-----------+ | domain | transport | +---------------------+-----------+ | vacation.domaine.fr | repondeur | +---------------------+-----------+ 1 row in set (0.00 sec)
Pour bien relier cette table à votre configuration « virtuelle », la table « transport » dont je parle est celle décrite comme ça dans postfix :
[extraits de fichiers] main.cf:transport_maps = proxy:mysql:/etc/postfix/mysql-virtual_transports.cf mysql-virtual_transports.cf:query = SELECT transport FROM transport WHERE domain='%s'
Création des alias pour router vers le « pipe » « repondeur »
Pour chaque utilisateur virtuel qui devra avoir un répondeur actif (ou potentiellement actif), il faudra ajouter 2 alias le concernant dans la table des alias (« forwardings » dans mon cas, là encore, ça dépend de votre conf de « postfix virtuel »). Ajoutez donc les lignes pour avoir :
mysql> select * from forwardings where source like 'j%doma%'; +--------------------+-----------------------------+ | source | destination | +--------------------+-----------------------------+ | jacques@domaine.fr | jacques@domaine.fr | | jacques@domaine.fr | jacques@vacation.domaine.fr | +--------------------+-----------------------------+ 2 rows in set (0.00 sec)
J’ai eu un souci pour insérer ces 2 lignes, car il y a une contrainte de clef primaire sur « source », ce qui semble logique, mais qui est en fait bloquant pour nous et inutile dans un cas normal d’alias d’utilisateurs virtuels (on pourrait faire une liste de diffusion en créant plusieurs lignes pour une même source car postfix gère très bien le fait d’avoir plusieurs destination pour une même source).
Bref, j’ai fait sauté la contrainte PK que j’avais mise dans mes docs précédents :
ALTER TABLE forwardings DROP PRIMARY KEY;
Rassurez-vous, ça ne fait pas sauter les entrées déjà stockées dans la table si vous en avez.
procmailrc et vacation
On y est presque.
Reste à définir le procmail
global appelant vacation :
Dans mon « pipe
« , j’appelle ce fichier :
servr:/etc/postfix# cat /etc/postfix/procmail-global-repondeur.rc SHELL=/bin/sh :0c * ^(To|Cc).*jacques@domaine.fr | vacation -f /home/vacation/jacques@domaine.fr.db -m /home/vacation/jacques@domaine.fr.msg -a jacques@domaine.fr vacation :0c * ^(To|Cc).*autre_type@domaine.fr | vacation -f /home/vacation/autre_type@domaine.fr.db -m /home/vacation/autre_type@domaine.fr.msg -a autre_type@domaine.fr vacation :0 /dev/null
Alors, c’est presque le plus compliqué car ce fichier est plein de petites ruses. Il vous montre comment procéder lorsque vous aurez plusieurs boîtes concernées par un vacation.
Je rappelle que de cette manière, c’est un peu pénible à maintenir car c’est l’admin qui gère. Là il s’agit de boîte IMAP partagées et peu nombreuses, donc c’est gérable.
Le détail est donc :
- Je stocke tous mes messages de « vacances » dans ~vacation/
- -f : pour indiquer dans quelle « base de données » on stocke les gens à qui on a déjà répondu
- -m : pour indiquer le mail de réponse d’un utilisateur donné, je le détaille plus bas
-
-a : hyper important : en effet,
vacation
ne travaille que sur un utilisateur réel. Donc obligé de spécifier un utilisateur réel en fin de commandevacation
, c’est l’utilisateur « vacation » himself qui figure en dernier argument de la ligne de commande. Donc, pour quevacation
travaille, j’explique aussi que cet utilisateur réel peut être connu sous l’alias (-a) jacques@domaine.fr (ou autre_type@domaine.fr dans la 2è règle). Sinon aucune règle ne s’appliquera jamais. -
« :0c » : OUI : il faut activer le « carbon copy ». J’ai constaté ça à force de tests. En effet, un message arrivant dans postfix a un ID, il est dédoublé avec le même ID, l’un part vers l’utilisateur réel pour livraison, l’autre vers le «
pipe
« , puisprocmail
, puisvacation
. «vacation
» arrête les règles (si on ne met pas le « c » de carbon copy) dès que ça « match ». Si un expéditeur envoi un unique mail à en même temps jacques@domaine.fr et autre_type@domaine.fr, la première règle va marcher, donc procmail arrêtera de bosser. Résultat : pas de répondeur pour « autre_type ». On ne sait pas qu’il est en vacances. -
Et enfin, le piège des « carbon copy » : si on ne fait pas une dernière règle virant vers /dev/null tout message au final, un message légitime auquel on aura répondu par « vacation » sortira de procmail et continuera sa route : il sera donc livré. Mais c’est un utilisateur complètement bidon, untel@vacation.domaine.fr, domaine inexistant => erreur de livraison => log dans
/var/log/mail.info
et surtout, mail d’erreur bien crade informant l’expéditeur…
fichier .msg de vacation
Voici à quoi doit ressembler un fichier de réponse minimaliste :
servr:/etc/postfix# cat ~vacation/jacques\\@domaine.fr.msg From: jacques@domaine.fr (Jacques) Subject: Re: $SUBJECT Precedence: Bulk Votre mail a bien été reçu, blablablabla -- Jacques
reload postfix et tests
A la fin, /etc/init.d/postfix reload
et zou, testez des envois de mails, de réenvois de mails (pour n’avoir qu’une fois la réponse etc).
Le plus risqué dans cette manip’ sur un serveur en production, c’est que tout les adresses normales commencent à merdouiller. Le plus rapide pour annuler tout ça le temps de réfléchir, est de commenter les 2 lignes définissant le pipe et de rechargez postfix.
Autres remarques
Réinit d’un répondeur
A une époque, il me semblait qu’en modifiant le fichier .msg, vacation
détectait le changement et donc ne tenait plus compte des expéditeurs « déjà répondus ». Après quelques tests, je n’en suis plus si sûr. Le plus simple pour relancer un répondeur « pour tous » : supprimez le fichier .db correspondant.
Permissions
Attention, j’ai interdit le login pour l’utilisateur vacation. Donc tout ce que vous créerez dans ~vacation/*msg sera sûrement au nom de « root », par exemple. Pensez à changer les droits.
Si vous avez raté un truc, les logs sont très explicites dans /var/log/mail.info
.
Je crois aussi me rappeler que si vacation
ne voit pas le fichier .msg, il ne fera rien. A vérifier, mais c’est une méthode simple (et crade car ça va faire du log à coup sûr) pour activer/désactiver un répondeur
un log complet pour illustrer
Si tout se passe bien, vous avez ça :
Connexion du serveur expéditeur :
Jun 14 17:10:21 servr postfix/smtpd[20107]: connect from expediteur.org[xx.yy.zz.tt] Jun 14 17:10:21 servr postgrey[12166]: action=pass, reason=client AWL, client_name=expediteur.org, client_address=xx.yy.zz.tt, sender=exped@expediteur.org, recipient=jacques@domaine.fr Jun 14 17:10:21 servr postfix/smtpd[20107]: C2B829C4081: client=expediteur.org[xx.yy.zz.tt] Jun 14 17:10:21 servr postfix/cleanup[20065]: C2B829C4081: message-id=<20100614151021.AF0F0EEC57C@mail.expediteur.org> Jun 14 17:10:21 servr postfix/qmgr[19547]: C2B829C4081: from=, size=515, nrcpt=2 (queue active) Jun 14 17:10:21 servr postfix/smtpd[20107]: disconnect from expediteur.org[xx.yy.zz.tt] Jun 14 17:10:23 servr postfix/smtpd[20208]: connect from localhost.localdomain[127.0.0.1] Jun 14 17:10:23 servr postfix/smtpd[20208]: 8A0E69C4085: client=localhost.localdomain[127.0.0.1] Jun 14 17:10:23 servr postfix/cleanup[20065]: 8A0E69C4085: message-id=<20100614151021.AF0F0EEC57C@mail.expediteur.org> Jun 14 17:10:23 servr postfix/smtpd[20208]: disconnect from localhost.localdomain[127.0.0.1] Jun 14 17:10:23 servr postfix/qmgr[19547]: 8A0E69C4085: from= , size=1045, nrcpt=3 (queue active)
Pas de greylisting, car c’est un pote. Analyse par amavis OK, on dédouble le message vers jacques@domaine.fr et jacques@vacation.domaine.fr.
Chaque file suivra alors sa route :
Jun 14 17:10:23 servr amavis[18918]: (18918-18) Passed CLEAN, [xx.yy.zz.tt] [xx.yy.zz.tt]-> , , Message-ID: <20100614151021.AF0F0EEC57C@mail.expediteur.org>, mail_id: uuW4XqNAoH7S, Hits: 1.714, size: 515, queued_as: 8A0E69C4085, 1902 ms Jun 14 17:10:23 servr postfix/smtp[20190]: C2B829C4081: to= , relay=127.0.0.1[127.0.0.1]:10024, delay=1.9, delays=0.03/0/0/1.9, dsn=2.0.0, status=sent (250 2.0.0 Ok, id=18918-18, from MTA([127.0.0.1]:10025): 250 2.0.0 Ok: queued as 8A0E69C4085) Jun 14 17:10:23 servr postfix/smtp[20190]: C2B829C4081: to= , orig_to= , relay=127.0.0.1[127.0.0.1]:10024, delay=1.9, delays=0.03/0/0/1.9, dsn=2.0.0, status=sent (250 2.0.0 Ok, id=18918-18, from MTA([127.0.0.1]:10025): 250 2.0.0 Ok: queued as 8A0E69C4085) Jun 14 17:10:23 servr postfix/qmgr[19547]: C2B829C4081: removed
La partie « utilisateur virtuel de postfix » traite le « mail normal » => « delivered to maildir ». Ca roule :
Jun 14 17:10:23 servr postfix/virtual[20212]: 8A0E69C4085: to=, relay=virtual, delay=0.3, delays=0.15/0.01/0/0.14, dsn=2.0.0, status=sent (delivered to maildir)
La partie « vacation » (pipe repondeur) route vers le « relay=repondeur ». Le job s’accomplit correctement « (delivered via repondeur service) ». Là on n’a pas d’autre erreur, sinon on pourrait voir vacation ou procmail pas content :
Jun 14 17:10:23 servr postfix/pickup[19550]: ECF179C408A: uid=5001 from=Jun 14 17:10:23 servr postfix/pipe[20209]: 8A0E69C4085: to= , orig_to= , relay=repondeur, delay=0.41, delays=0.15/0/0/0.25, dsn=2.0.0, status=sent (delivered via repondeur service) Jun 14 17:10:23 servr postfix/pipe[20209]: 8A0E69C4085: to= , relay=repondeur, delay=0.41, delays=0.15/0/0/0.25, dsn=2.0.0, status=sent (delivered via repondeur service) Jun 14 17:10:23 servr postfix/cleanup[20065]: ECF179C408A: message-id=<20100614151023.ECF179C408A@domaine.fr> Jun 14 17:10:23 servr postfix/qmgr[19547]: 8A0E69C4085: removed Jun 14 17:10:24 servr postfix/qmgr[19547]: ECF179C408A: from= , size=343, nrcpt=1 (queue active)
Deux secondes plus tard, « vacation » a détecté qu’il fallait répondre à « exped@expediteur.org », donc on envoit un mail :
(le champ From sera jacques@domaine.fr, seul Return-Path sera à vacation@domaine.fr)
Jun 14 17:10:26 servr postfix/smtpd[20208]: connect from localhost.localdomain[127.0.0.1] Jun 14 17:10:26 servr postfix/smtpd[20208]: 174A99C4081: client=localhost.localdomain[127.0.0.1] Jun 14 17:10:26 servr postfix/cleanup[20065]: 174A99C4081: message-id=<20100614151023.ECF179C408A@domaine.fr> Jun 14 17:10:26 servr postfix/qmgr[19547]: 174A99C4081: from=, size=770, nrcpt=1 (queue active) Jun 14 17:10:26 servr amavis[20202]: (20202-01) Passed CLEAN, -> , Message-ID: <20100614151023.ECF179C408A@domaine.fr>, mail_id: xw6dpgfdz+b5, Hits: -0.001, size: 343, queued_as: 174A99C4081, 2197 ms Jun 14 17:10:26 servr postfix/smtp[20190]: ECF179C408A: to= , relay=127.0.0.1[127.0.0.1]:10024, delay=2.3, delays=0.14/0/0/2.2, dsn=2.0.0, status=sent (250 2.0.0 Ok, id=20202-01, from MTA([127.0.0.1]:10025): 250 2.0.0 Ok: queued as 174A99C4081) Jun 14 17:10:26 servr postfix/qmgr[19547]: ECF179C408A: removed Jun 14 17:10:26 servr postfix/smtp[20219]: 174A99C4081: to= , relay=mail.expediteur.org[xx.yy.zz.tt]:25, delay=0.21, delays=0.14/0/0.02/0.05, dsn=2.0.0, status=sent (250 2.0.0 Ok: queued as 4337FEEC560) Jun 14 17:10:26 servr postfix/qmgr[19547]: 174A99C4081: removed