Artisan Numérique

/système/courrier/postfix/smtp/ Son propre serveur de courrier avec PostFix

Postfix est un serveur libre de messagerie électronique développé à l'origine comme une alternative, plus simple et plus sécurisée, à sendmail. Aujourd'hui c'est une énorme usine à gaz qui demanderait quelques bonnes vies de chat pour être correctement maîtrisée.

L'objectif de ce tutoriel est de voir comment nous pouvons utiliser cet outil de manière très fortement allégée dans le seul but de gagner en indépendance vis à vis d'un fournisseur, mais aussi en puissance et en souplesse.

DNS et enregistrement MX

Pour recevoir du courrier un prérequis est de disposer d'une IP fixe, ce qui est automatique avec une dédibox ou une freebox. Il est cependant possible d'utiliser des IP variables en passant par des services comme DynDNS.org mais de nos jours, avec le volume de SPAM et la violence des contre-mesures, ce n'est clairement pas conseillé.

Pour pouvoir utiliser notre IP, il nous faut aussi acheter un nom de domaine. Il s'agit là d'une formalité qui ne coûte pas le service qu'il rend (12€ chez Gandi pour un .fr ou un .net). Et une fois ce domaine en poche, il ne nous reste plus qu'à configurer ses zones de sorte à ce que notre nouveau nom pointe sur notre IP.

Chez Gandi cela se fait très facilement avec un peu de courage et de gougueulage en passant par l'interface "gestion des Zones", en mode Avancé ou Expert. La version la plus simple que nous devons obtenir pour le routage du courrier doit ressembler à cela :

mon_server 300 IN A 11.22.33.44
smtp.mon_domaine.net 300 IN CNAME mon_server
@ 300 IN MX 10 smtp.mon_domaine.net.

Sans rentrer dans les arcanes de la syntaxe DNS, tout ceci indique que la machine mon_serveur pointe sur l'adresse IP 11.22.33.44 de sorte à ce qu'un ping mon_server.mon_domaine.net réponde positivement. C'est ce que l'on appelle une enregistrement A (principal).

Ensuite vient un enregistrement CNAME qui n'est autre q'un alias sur un enregistrement A. Ce n'est pas strictement nécessaire mais c'est plus propre ainsi, notre serveur SMTP sera donc accessible par smtp.mon_domaine.net.

Enfin vient un enregistrement MX qui définit le nom qualifié de la machine qui prend en charge le courrier entrant (n'oubliez pas le . final). Notez le chiffre 10 qui définit la priorité de cet enregistrement. L'idée est que si vous avez des amis qui ont eux aussi un domaine et un serveur courriel, vous pouvez ajouter d'autres enregistrement MX pointant chez eux. Ainsi si le MX de plus forte priorité ne répond pas, le courrier est envoyé à celui qui une priorité inférieur. Ainsi il est possible de renforcer mutuellement plusieurs serveurs pour être certain de ne rien perdre.

Pour chacun des enregistrements 300 indique un délai en secondes que les serveurs utilisent comme base de temps pour les mises à jour. Ici, la mise à jour est faite, en cas de changement des données DNS, toutes les 5 minutes.

Une fois que vos modifications sont correctement propagées sur le net (comptez 24 heures pour la première fois). Ceci fait, la mécanique fonctionne de la manière suivante:

  1. Lorsqu'un utilisateur du Net veut vous envoyer un courriel, il le fait à l'adresse gaston@mon_domaine.net.
  2. Son client de courriel va poster le courrier au serveur SMTP (Simple Mail Transport Protocol) de son fournisseur d'accès.
  3. Le SMTP du FAI va extraire le domaine du destinataire et analyser la définition de zone associée (celle que nous venons de propager).
  4. S'il trouve un enregistrement MX il remonte (je simplifie, hein ;-)) à l'enregistrement CNAME pour finalement récupérer son IP par son enregistrement A.
  5. Le serveur SMTP du FAI va alors se connecter sur l'adresse IP du serveur de Gaston, sur le port 25.

Et là, il faut bien que quelqu'un lui réponde sinon c'est la cata, courriel perdu, amis fâchés, tout ça, tout ça. Nous allons donc donc passer à l'installation chez nous de ce fameux serveur SMTP, M. Postfix.

L'organisation de postfix

Postfix est donc un serveur de messagerie qui a la particularité de se composer d'une série de sous-démons travaillant de concert pour former une véritable chaîne de traitement du courrier entrant. Dans le graphique ci-dessus, en vert sont les entrées de courrier, en orange les démons traitant les messages, en chocolat les différentes files de stockages, et en prune les sorties.

Les messages peuvent ainsi être distribués soit localement en les insérant dans la file maildrop ou à distance en passant par le service SMTP. Dans les deux cas, les messages finissent par être pris en charge par le démon cleanup qui les stocke dans la file incoming. Ensuite le démon qmrg ventile les messages vers du stockage local, un autre serveur SMTP ou vers le démon lmtp communiquant via le protocole LMTP (Light Mail Transport Protocol) très bien adapté au transport local du courrier, par exemple vers le serveur dovcot (imap).

Installation de postfix

Ici rien de sorcier, tout est dans le même paquet sur la grande majorité des distributions, sur une debian cela donnerait donc

$ sudo aptitude install postfix
installation de postfix

Le résultat sera une installation quasi vierge que nous allons pouvoir paramétrer proprement.

Paramétrage de postfix

L'installation de postfix ne pose aucun problème, c'est plus sa configuration qui rend va vous dégarnir prématurément.

Pour rentrer directement dans le vif de sujet, allons jeté un oeil à ce que devra être la configuration principale du serveur, le fichier /etc/postfix/main.cf. Ce qui suit est une configuration qui fonctionne sur trois serveurs dont j'ai la charge et ce sans problème depuis des années.

L'identité du serveur

Pour éviter de trop donner d'informations au monde extérieur sur ce qui tourne sur notre machine, nous donnons allons donner ici à notre serveur PostFix de charmants petits noms d'oiseaux :

smtpd_banner = $myhostname Tagazok !
mail_name = PiouPiou
mail_version = 6.6.6
limitation de l'identification au strict minimum

Voilà, comme cela, ce sera difficile à un attaquant potentiel de comprendre ce qui tourne exactement chez nous.

Paramétrage du réseau

Nous allons maintenant spécifier la manière dont postfix "écoute" le réseau. Cela consiste basiquement à le connecter à toutes les IP de la machine (c'est un serveur ouvert sur l'extérieur) et à se concentrer sur IPV4.

inet_interfaces = all
inet_protocols = ipv4
Paramétrage de l'écoute

Gestion du domaine

Le paramétrage du domaine pris en charge par postfix reste assez simple nous concernant :

# définis le nom Internet (fqdn) de la machine.
myhostname = mon_serveur.mon_domaine.net

# spécifie le nom du domaine local (myhostname moins le nom de la bécane)
mydomain = mon_domaine.net

# définit l'adresse d'émission des messages postés localement
myorigin = mon_domaine.net

# définit une liste de domaine ou nom de bécanes que postfix
# considérera comme la destination finale des messages.
# Il faut donc mettre ici la liste des domaines qui <b>ne sont pas relayés</b>
# sur d'autres machines.
mydestination = mon_domaine.net, mon_second_domaine.net
définition du domaine

Il faut maintenant définir nos "réseaux de confiances", c'est à dire les plages d'adresses IP pour lesquels postfix vous autorisera par exemple l'envoi de courriels vers d'autres serveurs. On y ajoute donc notre réseau local car c'est de là que sera expédié le courrier (plus la peine d'utiliser le SMTP de votre FAI). L'ajout du localhost nous permettra d'installer par exemple un WebMail comme Roundcube sur la même machine que postfix.

mynetworks = 127.0.0.0/8,192.168.154.0/28
réseaux de confiance

Ensuite nous indiquons les domaines que postfix a le droit de relayer. Attention à ce paramétrage car il ne faudrait pas que votre serveur devienne ce que l'on appelle un "relais ouvert" permettant aux spammeurs d'accomplir leur méfaits. Vous allez y mettre bien sur votre domaine (mydestination), mais vous pouvez aussi ajouter les domaines "amis" que nous prenons en charge que ce soient ceux correspondant à nos enregistrements MX de backup ou simplement des domaines que vous hébergez chez vous.

relay_domains = $mydestination domaine_ami.net
définition des domaines relayables

Lorsque vous avez terminé votre configuration, vérifiez systématiquement que votre serveur n'est pas une porte ouverte aux spams avec des outils en ligne comme celui-ci.

Normalement lorsque l'on utilise notre postfix pour envoyer un mail, il va chercher directement à contacter le serveur SMTP du destinataire. Si vous préférez utiliser un serveur SMTP mandataire, par exemple celui de votre FAI, il suffit d'ajouter la ligne suivante :

relayhost = smtp.free.fr
définition d'un serveur SMTP de relais

Avant poste du filtrage des SPAM

Notre ennemi juré, c'est le SPAM. Nous verrons dans un autre papier comment s'en prémunir avec SpamAssassin. Mais en attendant, il est possible d'applique à notre serveur PostFix une bon hygiène.

Nous allons donc adjoindre au module SMTP un ensemble de règles lui permettant de qualifier le courrier entrant. Le principe est que c'est très mais alors très rapide en comparaison de SpamAssassin car directement intégré au moteur SMTP de postfix. Si le test ne passe pas, le vilain est jeté sans somation.

smtpd_recipient_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_unauth_destination
check_recipient_access hash:/etc/postfix/spam,
permit
Qualification des courriels entrant

Alors j'ai mis ici les règles les plus "safe" en ajoutant un "plus" particulièrement intéressant, la référence à un fichier /etc/postfix/spam pouvant contenir des motifs d'adresse cible à rejeter. Cela va nous permettre d'éliminer des adresses non utilisées mais très polluées, typiquement des adresses que vous avez "grillées" et qui sont pourries de SPAM.

Pour initier cette liste, commencez par la créer (avec nano, vi, etc.) et y ajouter une adresse suivie d'une action REJECT. Le principe sera que dés que le serveur SMTP verra arriver cette adresse cible (dans le champ TO), il arrêtera tout traitement concernant ce courriel. Brutal mais efficace.

vielle_adresse@mon_domaine.net      REJECT
exemple de fichier /etc/postfix/spam

En l'état cette liste n'est pas utilisable par postfix. Elle doit préalablement être "compilée" en une base de donnée. Pour cela, utilisez la commande postmap

rootpostmap spam
rootls spam*
spam    spam.db
Compilation d'une table postfix

Comme vous le voyez, la commande à généré un fichier spam.db, la version indexée de la liste d'origine. A chaque fois que vous modifiez une table, vous devrez lancer cette commande dessus.

Gestion des alias

Les alias sont une étape optionnelle si vous ne gérez qu'un domaine et que vous n'avez au final qu'un compte mail cible par adresse source. En réalité ce cas n'est jamais vérifié car nous avons tous besoin au minimum de rediriger une série d'adresses sur un même compte (ex. root@mon_domain.com vers mon adresse standard). Les alias permettent donc de jouer le rôle de redirecteur d'une adresse, d'un groupe d'adresse ou même d'un domaine complet vers une autre adresse.

Pour mettre ceci en oeuvre, nous ajoutons allons ajouter une autre liste (comme pour les spams) qui va nous permettre cette mise en relation :

virtual_alias_maps = hash:/etc/postfix/aliases
Définition des aliases

Reste maintenant à nourrir ce fichier :

# tous les courriers pour le domaine mon_domaine.net et mon_second_domaine.net va en priorité à gaston
@mon_domaine.net             gaston
@mon_second_domaine.net     gaston

# le courrier de robert lui revient
robert@mon_domaine.net       robert
exemple de fichier /etc/postfix/aliases

Comme pour la liste des spams, nous devons compiler cette liste après modification à l'aide de la commande postmap.

rootpostmap aliases
rootls aliases
aliases    aliases.db
Compilation d'une table postfix

Limitations de taille

Pour terminer, vous pouvez aussi modifier les limites de tailles imposées à un message et une boîte aux lettres (en octets). Cette opération nous permet de recevoir de très gros fichiers sans encombres, ce qui est un autre avantage à posséder son propre serveur :

message_size_limit = 104857600
mailbox_size_limit = 104857600
limitation de la taille des messages et des boîtes aux lettres

Placer l'une de ses valeurs à 0 pour ne pas avoir de limitation du tout.

Gestion des erreurs

Le soft bounce est à manier avec beaucoup de précaution. D'une certaine manière, il assure que vos courriels ne seront jamais rejetés mais stocké en queue si par exemple votre espace disque est totalement consommé ou que SpamAssassin est parti en vrille. En contrepartie, il va ré-émettre comme un sauvage les courriels à "faux numéro", ce qui a le don d'exaspérer les serveurs d'en face avec le risque de vous faire marquer comme spammeur. Personnellement je le laisse à no et le passe à yes lorsque je fais des opérations de maintenance pour ne pas perdre de courrier.

soft_bounce=no
définition du 'soft bounce'

Lorsque soft bounce est à no, nous avons donc le risque de perdre du courrier si un élément est défaillant dans la chaîne de traitement des messages (spamassassin en carafe, disque plein, etc). Pour contrer cela, l'astuce est de changer le code d'erreur généré pour un destinataire invalide de 550 (ce qui veut dire "mail rejeté") à 450 (ce qui veut dire "essayez un peu plus tard"). Du coup le serveur d'en face va (de mémoire) retenter l'envoi toutes les 10 minutes pendant 4 heures, avant de déclarer que votre courrier est vraiment mort.

unknown_local_recipient_reject_code = 450
stratégie de récupération d'erreurs

Test de l'installation

Maintenant que nous avons paramétré notre serveur, il nous reste à vérifier que cela fonctionne. La première chose à faire sera évidement de le (re)démarrer

root/etc/init.d/postfix restart
Stopping Postfix Mail Transport Agent: postfix.
Starting Postfix Mail Transport Agent: postfix.
Redémarrage de postfix

Vous pouvez aussi utiliser la commande /etc/init.d/postfix reload si postfix est déjà lancé, c'est un peu moins bourrin.

Ensuite pour tester, le plus simple dans un premier temps est d'utiliser l'antique client telnet que nous allons connecter au port 25 (SMTP) de notre serveur :

roottelnet smtp.mon_domaine.net 25
Trying 11.22.33.44...
Connected to smtp.mon_domaine.net (11.22.33.44).
Escape character is '^]'.
220 mon_serveur.mon_domaine.net Tagazok !!
>ehlo son_domaine.net
250-smtp.mon_domaine.net
250-PIPELINING
250-SIZE 1004857600
250-VRFY
250-ETRN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250 DSN
>mail from: robert@son_domaine.net
250 2.1.0 Ok
>rcpt to: gaston@mon_domaine.net
250 2.1.5 Ok
>data
354 End data with <CR><LF>.<CR><LF>
>Robert parle à gaston !!
>$
>.
250 2.0.0 Ok: queued as D421D908DA0
>quit
221 2.0.0 Bye
Connection closed by foreign host.
root#
Session de test de notre serveur Telnet

Si tout c'est bien passé, gaston devrait ainsi recevoir un courriel de robert. Cette approche peut aussi être utilisée pour tester les barrières anti-spam. Toujours est-il que cela fonctionne, nous pouvons donc passer à la suite, le stockage du courrier.

Redirection du courrier

A ce stade, notre serveur postfix est capable de prendre en charge le courrier entrant, c'est déjà une bonne chose. Côté stockage, si rien n'est fait, le courrier de gaston est posé, à l'ancienne, dans le dossier /var/mail/gaston. gaston peut donc lire son mail, avec l'ancestrale commande 'mail', ou alors avec Pine ou Mutt. Ou alors vous allez devoir installer un serveur IMAP tel que DoveCot ou Cyrus.

En revanche si votre serveur postfix est sur une machine distante (ex. une dédibox), il va falloir trouver un moyen pour que votre courriers soient ré-acheminés sur votre serveur local.

Pour y arriver, une solution assez simple est d'installer un second serveur postfix sur votre réseau local. Ce serveur postfix sera configuré pour ne prendre en charge que le courrier de votre domaine ce qui au fond reprend à peu prés (au delta du paramétrage des domaines amis) la configuration que nous venons de voir.

Ensuite, la seule chose à faire est d'indiquer au postfix distant comment ré-acheminer le courriels de votre domaine. Pour cela nous allons rajouter une nouvelle table transport

transport_maps = hash:/etc/postfix/transport
Définition de la table de transport

Nous pouvons maintenant créer et alimenter cette table :

mon_domaine.net           smtp:[11.22.33.44]
domaine_ami.net           smtp:[mail.domain_local.org]
Exemple de fichier /etc/postfix/transport

Comme toujours, pensez à recompiler la table avec la commande postmap après modification.

Comme vous le voyez, c'est aussi là que nous traitons le ré-acheminement du courrier du domaine ami que nous avons déclaré plus haut par relay_domains.

Une fois nos deux postfix paramétrés, le courriel arrive sur le premier (le serveur distant), est accepté (à cause de relay_domains), puis redirigé sur le serveur local grâce à la table transport. Là vous pouvez un routage final vers votre serveur IMAP, et c'est terminé.

A ce stade tout est presque prêt sauf un léger détail, postfix va rejeter tous ces courriels non-locaux parce qu'ils sont... non locaux... Pour éviter ce gag, il faut demander à notre ami de ne plus vérifier que le destinataire dispose d'un compte en local pour traiter son courriel :

local_recipient_maps =
Déclaration d'une table de destinataires vide

Quelques astuces

Remise en queue des messages

L'objectif de cette commande est de permettre aux messages d'être à nouveau interprétés par postfix pour être replacés dans les bonnes queues. Elle est notamment très utile lorsque l'on a des erreurs de configuration qui une fois corrigées laissent des messages en attente (ex. désinstallation d'amavis et message d'erreur warning: connect to transport smtp-amavis: No such file or directory) :

rootpostsuper -r ALL
postsuper: Requeued: 5 messages
remise en queue des messages

Liste des messages en queue

Lorsque Postfix n'arrive à rien faire d'un message, il le met en file d'attente. Les commande suivantes permette d'avoir l'état de ces files :

ces deux commandes sont équivalentes
rootpostqueue -f
-Queue ID- --Size-- ----Arrival Time---- -Sender/Recipient-------
1DEC5908D05     3716 Mon Jan 19 14:33:50  tcpv@mon_domaine.com
(mail forwarding loop for tartignole@mon_domaine.com)

rootmailq
-Queue ID- --Size-- ----Arrival Time---- -Sender/Recipient-------
1DEC5908D05     3716 Mon Jan 19 14:33:50  tcpv@mon_domaine.com
(mail forwarding loop for tartignole@mon_domaine.com)
Affichage des messages en non-traités

Lire le contenu d'un message en queue

Il arrive souvent qu'avant de détruire un message bloqué en queue, on ait envie de savoir ce qu'il contient.. Pour cela nous avons la commande postcat (depuis postfix 2.0)

rootpostcat -q ID_MESSAGE
Lecture d'un message unique

Suppression d'un message en queue

La commande précédente donne la liste des messages en attente dans la queue de postfix (généralement des spams :/). Chaque message dispose d'un ID qui permet de le détruire spécifiquement :

rootpostqueue -d ID_MESSAGE
destruction d'un message unique

S'il s'agit de détruire tous les messages en queue (attention !!) vous pouvez utilisez la commande suivante :

rootpostqueue -d ALL
postsuper: Deleted: 5 messages
destruction de tous les messages en queue

Profil de répartition des messages dans les queues

Pour voir de plus prés l'utilisation d'une queue :

rootqshape deferred
T  5 10 20 40 80 160 320 640 1280 1280+
TOTAL   7  0  0  0  0  0   0   0   1    0     6
chez.com   6  0  0  0  0  0   0   0   0    0     6
tiscali.fr  1  0  0  0  0  0   0   0   1    0     0
Profile des queues

Erreur de droit sur les fichiers

Si vous avez dans vos logs l'erreur suivante warning: mail_queue_enter: create file maildrop/163133.6208: Permission denied, une solution possible est de lancer les commandes suivantes :

rootpostfix set-permissions
rootpostfix reload
correction des droits postfix

Conclusion

La mise en place d'un serveur Postfix, sous réserve de prendre quelques précaution pour ne pas l'ouvrir aux spammeurs, est relativement simple. Et surtout c'est très fiable. Ceci étant dit il manque quelques trucs à notre arsenal :

  • une vraie gestion des spams avec SpamAssassin,
  • la gestion de SPF et DKIM pour signer nos mails et ne pas être pris pour des spammeurs.