• 15 heures
  • Difficile

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 14/09/2023

Installez votre serveur SMTP

 

Dans ce chapitre, nous allons travailler sur la mise en place d’un serveur SMTP et prendrons pour cela Postfix qui est un des serveurs les plus utilisés.

Mettez en oeuvre votre serveur SMTP

Principes

Postfix est un serveur de messagerie modulaire.

Mais ça veut dire quoi modulaire ? 

Cela veut dire qu’il est composé de plusieurs petits programmes qui ont chacun un rôle particulier. Cela permet d’apporter beaucoup plus de flexibilité et de sécurité, car il suffit de toucher à la partie concernée du code pour modifier Postfix. De plus, chaque sous-programme peut être sécurisé individuellement.

Ainsi, nous verrons que certains sous-programmes seront chargés d’écouter sur le réseau, quand d’autres le seront pour la réception du mail ou l’envoi de celui-ci.

Installez votre serveur SMTP

Comme dans le chapitre précédent, nous allons continuer à travailler sous Debian. Cependant, maintenant que vous êtes à l’aise et un vrais pro, je vais vous laisser libre quant au choix de distribution Linux et de version à utiliser. Vous pouvez tout à fait conserver la machine Linux que vous avez utilisée jusqu’à maintenant, ou en mettre en place une nouvelle. Pour ma part, je serai sous Debian 11, notamment pour vous faire découvrir toutes les nouveautés réseau qu’elle apporte.

Maintenant que vous avez votre système fin prêt, vous allez voir que l’installation de Postfix est très simple.

Comme d’habitude sous Debian, nous utiliserons notre système de gestion des paquets préféré apt.

Nous allons mettre à jour notre liste de packages, puis chercher les packages disponibles susceptibles de nous intéresser :

root@Debian02:~# apt-get update
[...]
root@Debian02:~# apt-cache search postfix | grep postfix
bld-postfix - outils Postfix pour le serveur de listes noires BLD
postfix - agent de transport de courriers électroniques à hautes performances
postfixadmin - interface web d’administration pour Postfix
postfix-cdb - prise en charge des mappes CDB pour Postfix
postfix-policyd-spf-python - serveur Postfix de politique de gestion de courriel (SPF)
[...]

Nous voyons le package Postfix qui semble bien être le serveur que nous cherchons ; il est temps de l’installer !

root@Debian02:~# apt-get install postfix

Et nous allons cliquer sur o ou y pour valider l’installation.

Page de dialog nous invitant à choisir la configuration de postfix
Choix de la configuration du serveur

Une fenêtre de dialogue s’ouvre en nous demandant quel type d’installation de serveur nous souhaitons mettre en place. Nous allons choisir "Site Internet" pour avoir un fichier de configuration déjà prérempli.

Page de dialog nous permettant d'indiquer le nom du domaine de messagerie par défaut.
Choix du domaine du serveur

Nous devons ensuite indiquer quel est le domaine par défaut auquel va être lié notre serveur. Si vous n’avez pas de domaine, ce qui sera le cas la plupart du temps, je vous propose de choisir mondomaine.local.

Après avoir validé en appuyant sur Entrée, la suite de l’installation devrait se faire, magique !

Nous avons donc installé notre serveur SMTP Postfix et allons pouvoir commencer sa configuration.

Configurez Postfix

En avant pour la configuration !

Comme pour la majorité des services sous Linux, les fichiers de configuration vont se situer dans /etc, et Postfix ne déroge pas à la règle.

Allons voir ce que l’on y trouve :

root@Debian02 : ~# ls /etc/postfix
dynamicmaps.cf main.cf makedefs.out master.cf.proto postfix-files.d post-install
dynamicmaps.cf.d main.cf.proto master.cf postfix-files postfix-script sasl

Bien qu’il y ait une bonne dizaine de fichiers dans le répertoire, seul main.cf va nous intéresser pour l’instant.

Le fichier main.cf va contenir tous les paramètres de configuration que nous voulons indiquer au serveur. Il y en a plusieurs centaines, mais tous ont une valeur par défaut. Nous allons donc indiquer que ceux que nous devrons modifier.

Regardons donc le contenu de main.cf. J’ai ajouté quelques commentaires explicatifs en commençant les lignes par ## :

# See /usr/share/postfix/main.cf.dist for a commented, more complete version

# Debian specific: Specifying a file name will cause the first
# line of that file to be used as the name. The Debian default
# is /etc/mailname.
#myorigin = /etc/mailname

## le message envoyé quand quelqu’un se connecte au serveur, nous le verrons quand nous
## enverrons des mails avec telnet
smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU)
## Système pour prévenir l’utilisateur de la réception de nouveaux mails
biff = no

# appending .domain is the MUA's job.
append_dot_mydomain = no

# Uncomment the next line to generate "delayed mail" warnings
#delay_warning_time = 4h

readme_directory = no

# See http://www.postfix.org/COMPATIBILITY_README.html -- default to 2 on
# fresh installs.
compatibility_level = 2

# TLS parameters
## Paramètres utilisés pour utiliser du chiffrement pour sécuriser les mails
smtpd_tls_cert_file=/etc/ssl/certs/ssl-cert-snakeoil.pem
smtpd_tls_key_file=/etc/ssl/private/ssl-cert-snakeoil.key
smtpd_use_tls=yes
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache

# See /usr/share/doc/postfix/TLS_README.gz in the postfix-doc package for
# information on enabling SSL in the smtp client.

## Paramètre TRES important pour indiquer pour qui nous acceptons de relayer les mails
## Si ce paramètre est trop permissif, votre serveur pourra être utilisé par des spammeurs
smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
## Nom donné à notre serveur
myhostname = Debian02.itinet.fr
## Lieu et mode d’utilisation des alias, que nous verrons plus tard
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
## Fichier qui contient le nom de domaine utilisé pour les mails issus de notre serveur
myorigin = /etc/mailname
## Noms de domaines acceptés par notre serveur pour une livraison locale
mydestination = $myhostname, itinet.fr, localhost, localhost.localdomain, localhost
## Serveur à utiliser pour relayer nos mails
relayhost =
## Réseaux de confiance
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
## taille limite d’un fichier dans notre boîte aux lettres
mailbox_size_limit = 0
recipient_delimiter = +
## Interfaces réseau sur lesquelles le serveur est en écoute
inet_interfaces = all
## Si l’on veut spécifier que notre serveur fonctionne en IPv4 ou IPv6
inet_protocols = all

Pour l’instant, j’ai laissé les lignes par défaut, mais nous allons les modifier petit à petit pour mettre notre serveur dans la configuration qui nous intéresse.

Si jamais nous ne faisions rien de plus, est-ce que notre serveur serait capable de recevoir des mails avec cette configuration par défaut ?

Nous allons faire un test et allons essayer d’envoyer un mail à un utilisateur de notre serveur.

Mais comment envoyer un mail à notre serveur, et comment le mail va-t-il pouvoir être relayé jusqu’à lui ?

Nous allons directement nous connecter au serveur sans passer par un serveur SMTP intermédiaire, et nous essayerons d’envoyer un mail à un utilisateur valide. Notamment, on voit dans le paramètre mydestination que notre serveur acceptera les mails pour le domaine mondomaine.local. Vu que nous n’avons pas créé de compte de messagerie spécifique, nous allons essayer d’envoyer un mail à l’un des comptes des utilisateurs de notre système Debian. En l’occurrence, nous allons essayer d’envoyer un mail à root@mondomaine.local.

Envoyez votre premier mail

Pour envoyer un mail directement à notre serveur, nous avons plusieurs choix plus ou moins judicieux :

  • Soit configurer notre client de messagerie Outlook, Thunderbird ou Mail afin de lui indiquer d’utiliser notre serveur pour les envois, mais cela est lourd à faire et nous ne pourrons plus envoyer de mails avec cette configuration.

  • Ou bien se connecter au serveur en ligne de commande, et à lui parler directement dans le langage qu’il comprend, le SMTP.

Nous utiliserons donc la commande telnet pour nous connecter à notre serveur.

Voici ce que donne l'utilisation de la commande telnet pour se connecter à notre serveur.

root@Debian02:~# apt-cache search telnet | grep telnet
dcap-tunnel-telnet - tunnel Telnet pour dCache
libguac-client-telnet0 - application web HTML5 d’accès à des bureaux distants – prise en charge de Telnet
telnet - client telnet de base
telnetd - serveur telnet basique
ttysnoop - espionnage de connexion série telnet
inetutils-telnet - telnet client
inetutils-telnetd - telnet server
jta - Java telnet/ssh applet
jta-doc - Java telnet/ssh applet - documentation
libcli-dev - emulates a cisco style telnet command-line interface (dev files)
libcli1.9 - emulates a cisco style telnet command-line interface
libnet-telnet-perl - Perl module to script telnetable connections
libtelnet-dev - Small library for parsing the TELNET protocol - development files
libtelnet-utils - Small library for parsing the TELNET protocol - utilities
libtelnet2 - Small library for parsing the TELNET protocol - shared library
mactelnet-client - Console tools for telneting and pinging via MAC addresses
mactelnet-server - Telnet daemon for accepting connections via MAC addresses
libnet-telnet-cisco-perl - Additional functionality to automate Cisco management
telnet-ssl - telnet client with SSL encryption support
telnetd-ssl - telnet server with SSL encryption support
pcmanx-gtk2 - user-friendly telnet client mainly targets BBS users
procserv - Process server with telnet console and log access
ruby-net-telnet - telnet client library
socks4-clients - Socks4 enabled clients as rtelnet and rftp

Pour commencer, on installe Telnet s’il n’est pas présent :

root@Debian02:~# apt-get install telnet

Ensuite, l’utilisation de Telnet est très simple, on indique l’adresse du serveur sur lequel nous voulons nous connecter, puis le port.

Le port par défaut du protocole SMTP est le port 25.

Nous allons donc nous connecter dessus avec la commande telnet.

root@Debian02:~# telnet localhost 25
Trying ::1...
Connected to localhost.
Escape character is '^]'.
220 Debian02.itinet.fr ESMTP Postfix (Debian/GNU)

Le serveur nous répond ! Il nous faut maintenant parler son langage pour lui envoyer des instructions.

Nous commençons par nous présenter.

ehlo toto.com
250-Debian02.mondomaine.local
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-STARTTLS
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250 SMTPUTF8

Nous disons venir du serveur toto.com (on peut y mettre ce que l’on veut) et le serveur nous répond en nous indiquant les extensions qu’il accepte (et dont on ne se soucie pas).

Nous allons maintenant lui dire quelle est l’adresse de l’expéditeur :

mail from: toto@toto.com
250 2.1.0 OK

Nous indiquons que l’expéditeur est toto@toto.com, le serveur nous dit que c’est OK pour lui.

Il faut maintenant indiquer à qui nous voulons écrire :

rcpt to: root@mondomaine.local
250 2.1.5 OK

Nous choisissons d’écrire à l’adresse qui nous semble valide, et le serveur l’accepte aussi. Il y a donc des chances pour que l’adresse existe vraiment et que le mail soit bien reçu.

Nous allons maintenant indiquer le contenu du mail :

data
354 End data with <CR><LF>.<CR><LF>
Subject: Salut les amis
C’est vraiment sympa d’écrire des mails à la main.
250 2.0.0 OK: queued as 2FD64721
quit
221 2.0.0 Bye
Connection closed by foreign host.
Vous avez du courrier dans /var/mail/root

Nous avons utilisé la commande data pour spécifier le contenu de notre mail, puis le sujet, et enfin le contenu réel.

Nous finissons l’envoi de notre mail avec un simple point.

Le serveur nous répond que le mail a été mis dans la queue pour envoi. Nous pouvons alors quitter Telnet avec quit.

Étant connectés en root, nous recevons au passage un message nous indiquant que nous avons reçu un courrier !

Allons vite voir ce qu’il en est :

root@Debian02:~# cat /var/mail/root
From toto@toto.com Tue Jan 16 11:31:11 2018
Return-Path: <toto@toto.com>
X-Original-To: root@mondomaine.local
Delivered-To: root@mondomaine.local
Received: from toto.com (localhost [IPv6:::1])
 by Debian02.mondomaine.local (Postfix) with ESMTP id 2FD64721
 for <root@mondomaine.local>; Tue, 16 Jan 2018 11:28:05 +0100 (CET)
Subject: Salut les amis
Message-Id: <20180116102938.2FD64721@Debian02.mondomaine.local>
Date: Tue, 16 Jan 2018 11:28:05 +0100 (CET)
From: toto@toto.com

C’est vraiment sympa d’écrire des mails à la main

Nous voyons que le mail est arrivé dans le fichier root du répertoire /var/mail.

Au passage, vous pouvez voir l’en-tête du mail qui contient des informations sur le transport du mail et souvent quelques autres informations qui peuvent être utiles.

Enfin, il est souvent très utile, quand il y a une erreur, d’aller voir dans les logs ce qui s’est passé. Même si tout s’est bien passé ici, nous allons regarder les informations qui y sont indiquées :

root@Debian02 : ~# cat /var/log/mail.info
Jan 16 11:20:54 Debian02 postfix/smtpd[13682]: connect from localhost[::1]
Jan 16 11:29:38 Debian02 postfix/smtpd[13682]: 2FD64721: client=localhost[: : 1]
Jan 16 11:31:11 Debian02 postfix/cleanup[13686]: 2FD64721: message-id=<20180116102938.2FD64721@Debian02.mondomaine.local>
Jan 16 11:31:11 Debian02 postfix/qmgr[13232]: 2FD64721: from=<toto@toto.com>, size=370, nrcpt=1 (queue active)
Jan 16 11:31:11 Debian02 postfix/local[13687]: 2FD64721: to=<root@mondomaine.local>, relay=local, delay=186, delays=186/0.01/0/0, dsn=2.0.0, status=sent (delivered to mailbox)
Jan 16 11:31:11 Debian02 postfix/qmgr[13232]: 2FD64721: removed
Jan 16 11:31:25 Debian02 postfix/smtpd[13682]: disconnect from localhost[::1] ehlo=1 mail=1 rcpt=1 data=1 quit=1 commands=5

On voit à la ligne 6 que le mail à bien été délivré (status=sent), ce dont on pouvait déjà se douter.

Notre serveur de messagerie fonctionne donc correctement, cependant nous pouvons entrevoir quelques problèmes :

  • Si les mails arrivent tous dans un fichier, cela va être compliqué à terme quand nous aurons reçu beaucoup de mails.

  • S’il faut créer un compte Unix pour chaque adresse de messagerie, nous allons devoir créer beaucoup de comptes, et donc de failles de sécurité potentielles.

Mais heureusement pour nous, Postfix nous laisse différentes options de configuration qui vont nous permettre de répondre positivement à ces problématiques.

Mettez en place des boîtes aux lettres pour vos utilisateurs virtuels

Intéressons-nous d’abord à la façon de créer nos utilisateurs.

Par défaut, il y a les utilisateurs du système Linux, mais Postfix nous permet de créer des utilisateurs virtuels qui n’ont pas de relation avec les utilisateurs Linux. Cela peut se faire soit en ligne de commande, soit avec une base de données.

Pour être exhaustifs, nous allons voir les deux façons de faire afin que vous puissiez choisir celle qui vous convient le mieux.

Méthode n°1: créez vos utilisateurs virtuels en ligne de commande

Comme vous le savez maintenant, la configuration va se faire dans le fichier main.cf.

Pour cela, nous allons ajouter quelques lignes à notre fichier de configuration pour indiquer que nous voulons utiliser des boîtes aux lettres virtuelles :

virtual_mailbox_domains = mondomaine.local
virtual_mailbox_base = /var/mail/vhosts
virtual_mailbox_maps = hash:/etc/postfix/vmailbox
virtual_minimum_uid = 100
virtual_uid_maps = static:5000
virtual_gid_maps = static:5000

Lisons ensemble ces différentes lignes :

  • Dans la première, nous indiquons d’abord le nom de notre domaine virtuel ; il s’agit ici de mondomaine.local.

  • La seconde ligne indique où vont se situer nos boîtes aux lettres dans l’arborescence Linux.

  • La troisième précise quel fichier va recenser nos adresses mail virtuelles. Le mot hash: devant le fichier indique que celui-ci doit être lu par Postfix dans un format compilé ; nous le verrons dans quelques instants.

  • Les trois lignes suivantes indiquent quels sont les UID et GID de l’utilisateur Linux qui va recevoir les mails pour nos boîtes virtuelles (eh oui, il va nous falloir malgré tout un utilisateur Linux supplémentaire).

Avant de pouvoir tester notre solution, il va falloir créer un utilisateur Linux qui va recevoir les mails, et créer le fichier /etc/postfix/vmailbox qui contiendra nos adresses mail virtuelles.

On commence par créer le groupe et l’utilisateur, en pensant à utiliser le GID et l’UID 5000 comme spécifié dans main.cf :

root@Debian02:/etc/postfix# groupadd -g 5000 vhosts 
root@Debian02:/etc/postfix# useradd -g vhosts -u 5000 vhosts -d /var/mail/vhosts -s /bin/false -m

On peut vérifier que l'utilisateur a bien été créé :

root@Debian02:/etc/postfix# cat /etc/passwd |grep vhosts
vhosts:x:5000:5000::/var/mail/vhosts:/bin/false

Ainsi que la base des boîtes aux lettres :

root@Debian02:/etc/postfix# ls -la /var/mail
total 16
drwxrwsr-x 3 root mail 4096 janv. 16 15:11 .
drwxr-xr-x 12 root root 4096 janv. 12 16:52 ..
-rw------- 1 root mail 495 janv. 16 11:31 root
drwxr-xr-x 2 vhosts vhosts 4096 janv. 16 15:11 vhosts

Tout semble bien de ce côté-là. Il nous reste à créer nos adresses mail virtuelles dans le fichier /etc/postfix/vmailbox que vous allez créer maintenant et dont voici le contenu :

toto@mondomaine.local mondomaine.local/toto/

Pour l’instant, nous ne créons qu’une seule adresse, et nous indiquons où va se situer sa boîte aux lettres. Ainsi, l’adresse toto@mondomaine.local recevra ses mails dans /var/mail/vhosts/itinet.fr/toto/.

Nous devons ensuite compiler le fichier vmailbox, comme indiqué dans notre fichier de configuration avec cette manipulation :

root@Debian02:/etc/postfix# postmap /etc/postfix/vmailbox
root@Debian02:/etc/postfix# ls /etc/postfix
dynamicmaps.cf main.cf makedefs.out master.cf.proto postfix-files.d post-install vmailbox
dynamicmaps.cf.d main.cf.proto master.cf postfix-files postfix-script sasl vmailbox.db

Nous voyons bien qu’un fichier vmailbox.db est apparu dans /etc/postfix.

Nous allons ensuite retourner sur notre fichier de configuration main.cf afin de supprimer de la ligne mydestination le champ mondomaine.local.

En effet, Postfix ne va pas savoir si pour le domaine mondomaine.local, il faut livrer les mails aux utilisateurs Linux de la machine, ou à nos utilisateurs virtuels, vu que nous avons mis le domaine mondomaine.local à la fois dans mydestination et virtual_mailbox_domains, dans le fichier main.cf.

Donc après l’avoir enlevé, redémarrez Postfix et nous allons pouvoir refaire notre test.

root@Debian02:/etc/postfix# cat vmailbox.db
a
�� ���I6эh^�
 ���I6эh^itinet.fr/toto/toto@itinet.fr

On voit des caractères bizarres. Qu'est-ce que c'est ? 

En effet, c’est un fichier compilé dans un langage compréhensible par Postfix, mais pas par nous (même si ici certains mots apparaissent correctement).

Avant de faire notre test, nous pouvons aussi voir dans les logs qu’il y a un warning, do not list domain itinet.fr in BOTH mydestination and virtual_mailbox_domains.

En effet, Postfix ne va pas savoir si pour le domaine itinet.fr, il faut livrer les mails aux utilisateurs Linux de la machine, ou à nos utilisateurs virtuels, vu que nous avons mis le domaine itinet.fr à la fois dans mydestination et virtual_mailbox_domains, dans le fichier main.cf.

Nous allons corriger cela en l’enlevant de mydestination, vu que nous voulons que ce soit des adresses virtuelles.

Donc après l’avoir enlevé, redémarrez Postfix et nous allons pouvoir refaire notre test.

root@Debian02: systemctl reload Postfix
root@Debian02:/etc/postfix# telnet localhost 25
Trying ::1...
Connected to localhost.
Escape character is '^]'.
220 Debian02.mondomaine.local ESMTP Postfix (Debian/GNU)
ehlo toto.com
250-Debian02.mondomaine.local
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-STARTTLS
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250 SMTPUTF8
mail from: toto@toto.com
250 2.1.0 OK
rcpt to: toto@mondomaine.local
250 2.1.5 OK
data
354 End data with <CR><LF>.<CR><LF>
Subject: Mon premier mail virtuel !
Je n’existe pas, je suis virtuel
.
250 2.0.0 OK: queued as 421DC72B
quit
221 2.0.0 Bye
Connection closed by foreign host.

Tout semble s’être bien passé. Pour le vérifier, on commence par aller voir les logs :

root@Debian02:/etc/postfix# tail /var/log/mail.info
Jan 16 15:28:23 Debian02 postfix/trivial-rewrite[13844]: warning: do not list domain mondomaine.local in BOTH mydestination and virtual_mailbox_domains
Jan 16 15:28:23 Debian02 postfix/smtpd[13841]: NOQUEUE: reject: RCPT from localhost[::1]: 550 5.1.1 <toto@mondomaine.local>: Recipient address rejected: User unknown in local recipient table; from=<toto@toto.com> to=<toto@mondomaine.local> proto=ESMTP helo=<toto.com>
Jan 16 15:28:40 Debian02 postfix/smtpd[13841]: disconnect from localhost[::1] ehlo=1 mail=1 rcpt=0/1 quit=1 commands=3/4
Jan 16 15:42:10 Debian02 postfix/smtpd[13853]: connect from localhost[::1]
Jan 16 15:42:30 Debian02 postfix/smtpd[13853]: 421DC72B: client=localhost[::1]
Jan 16 15:42:56 Debian02 postfix/cleanup[13856]: 421DC72B: message-id=<20180116144230.421DC72B@Debian02.mondomaine.local>
Jan 16 15:42:56 Debian02 postfix/qmgr[13833]: 421DC72B: from=<toto@toto.com>, size=364, nrcpt=1 (queue active)
Jan 16 15:42:56 Debian02 postfix/virtual[13857]: 421DC72B: to=<toto@mondomaine.local>, relay=virtual, delay=35, delays=35/0.01/0/0, dsn=2.0.0, status=sent (delivered to maildir)
Jan 16 15:42:56 Debian02 postfix/qmgr[13833]: 421DC72B: removed
Jan 16 15:42:59 Debian02 postfix/smtpd[13853]: disconnect from localhost[::1] ehlo=1 mail=1 rcpt=1 data=1 quit=1 commands=5

On a bien notre mail en status sent !

Allons donc voir dans la boîte aux lettres de Toto si le mail est bien présent :

root@Debian02:/etc/postfix# cat /var/mail/vhosts/mondomaine.local/toto/new/1516113776.V805I730M886308.Debian02
Return-Path: <toto@toto.com>
X-Original-To: toto@mondomaine.local
Delivered-To: toto@mondomaine.local
Received: from toto.com (localhost [IPv6:::1])
 by Debian02.mondomaine.local (Postfix) with ESMTP id 421DC72B
 for <toto@mondomaine.local>; Tue, 16 Jan 2018 15:42:21 +0100 (CET)
Subject: Mon premier mail virtuel !
Message-Id: <20180116144230.421DC72B@Debian02.mondomaine.local>
Date: Tue, 16 Jan 2018 15:42:21 +0100 (CET)
From: toto@toto.com

Je n’existe pas, je suis virtuel

Le mail est là ! Nous avons donc réussi à créer notre boîte aux lettres virtuelle et à recevoir notre premier mail.

Mais avant de continuer, il y a un point à éclaircir concernant les différentes façons d’associer des adresses mail. Il y en a trois en fait, que Postfix appelle les classes d’adresses.

  • La première concerne des adresses mail qui correspondent à des boîtes aux lettres existantes, comme nous venons de le voir avec vmailbox.

  • La seconde concerne des adresses mail que nous voulons rediriger vers une autre adresse mail, locale ou non (par exemple, je peux dire que tout mail qui arrive pour admin@mondomaine.local devra être redirigé vers test@gmail.com), et qui sont situées dans le fichier virtual.

  • Enfin, la troisième correspond à des adresses d’utilisateurs locaux que nous voulons rediriger vers d’autres utilisateurs locaux, et cela se fait dans le fichier aliases.

Mais pour l’instant, nous ne nous intéresserons qu’aux boîtes aux lettres usuelles comme celles renseignées dans vmailbox.

Allez plus loin

Nous avons vu quelque chose qu’il peut être intéressant de comprendre pour vous. Quand nous avons fait notre connexion telnet et que nous avons indiqué l’adresse source, nous avons choisi arbitrairement toto@toto.com, et le mail que nous avons reçu portait bien ce nom d’expéditeur.

Que se passerait-il si nous avions choisi donald.trump@whitehouse.gov ? Ou mieux encore, maitredumonde@openclassrooms.com ?

Il est important de comprendre qu’il n’y a pas d’authentification par défaut avec le protocole SMTP. Ainsi, vous pouvez vous connecter à n’importe quel serveur SMTP et choisir une adresse source folklorique et s’il n’est pas parfaitement configuré, votre interlocuteur recevra votre mail.

C’est notamment ce que font souvent les spammeurs. Il vous est peut-être parfois arrivé qu’un ami vous écrive en vous disant que votre boîte mail avait été piratée, car il avait reçu un mail bizarre provenant de votre adresse. Cependant, il y a de grandes chances pour que ce ne soit pas le cas et que ce soit simplement un spammeur qui ait usurpé votre adresse. Ce qui est illégal, au passage...

A présent que vous connaissez la première méthode en ligne de commande, vous allez découvrir la création d'utilisateurs virtuels ainsi que la configuration de votre serveur Postfix avec une base de données SQL.

Méthode n°2: créez vos utilisateurs virtuels via une base de données SQL

Dans cette section, nous allons utiliser une base de données SQL MariaDB. C’est un fork de la base plus connue MySQL qui est de plus en plus adoptée de nos jours.

En tant que fork de MySQL, MariaDB sera très très proche de MySQL dans son fonctionnement, mais aussi dans les processus ou fichiers utilisés.

Nous allons donc créer une base de données qui permettra à Postfix d’y trouver notre domaine, ainsi que les adresses associées.

Installez et configurez les packages

Comme à notre habitude, nous allons trouver et installer les packages nécessaires.

root@Debian02:~# apt-cache search mariadb | grep server
mariadb-server-10.1 - exécutables du serveur de base de données MariaDB
mariadb-server-core-10.1 - fichiers centraux du serveur de base de données MariaDB
goiardi - Chef server written in Go
golang-github-ctdk-goiardi-dev - Golang library to interact with a chef server
mariadb-plugin-gssapi-server - GSSAPI authentication plugin for MariaDB server
mariadb-server - MariaDB database server (metapackage depending on the latest version)
tango-db - TANGO distributed control system - database server

A priori, le package mariadb-server semble faire l’affaire.

Installez le package, ou celui qui vous semble le plus pertinent, selon votre choix de distribution. Nous pouvons ensuite tester que le service est bien en écoute :

root@Debian02:~# ss -antp
State Recv-Q Send-Q Local Address:Port Peer Address:Port
LISTEN 0 128 * : 22 *:* users:(("sshd",pid=561,fd=3))
LISTEN 0 100 * : 25 *:* users:(("master",pid=13229,fd=13))
LISTEN 0 80 127.0.0.1 : 3306 *:* users:(("mysqld",pid=20244,fd=17))
ESTAB 0 244 10.0.0.2 : 22 10.0.0.254 : 56013 users : (("sshd",pid=18355,fd=3))
LISTEN 0 128 :: : 22 :::* users:(("sshd",pid=561,fd=4))
LISTEN 0 100 :: : 25 :::* users:(("master",pid=13229,fd=14))

Nous voyons ici que MySQL est bien en écoute sur le port 3306 de notre interface locale. C’est normal, vu que MariaDB est un fork de MySQL ; c’est le processus mysqld qui est utilisé par MariaDB.

Nous pouvons maintenant créer notre base et les tables nécessaires.

Nous allons créer une base que nous allons appeler messagerie qui contiendra une table pour indiquer nos domaines, et une autre pour nos utilisateurs.

Si vous n’avez jamais fait de SQL, je vais vous indiquer les actions à faire pas à pas, mais pour ceux qui sont plus à l’aise, vous pourrez simplement vous référer aux contenus SQL à exécuter.

Créez la base et les tables

Tout d’abord, nous allons devoir nous connecter à la base.

Par défaut, MariaDB vous permet de vous connecter en root sans avoir à fournir de mot de passe :

root@Debian02:~# mysql -u root
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 2
Server version: 10.1.26-MariaDB-0+deb9u1 Debian 9.1

Copyright (c) 2000, 2017, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]>

Nous sommes maintenant dans une l’interface de MariaDB qui nous permet d’envoyer des commandes SQL à notre service.

Nous pouvons par exemple voir la liste des bases de données présentes :

MariaDB [(none)]> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
+--------------------+
3 rows in set (0.00 sec)

Notre serveur SQL contient donc 3 bases de données par défaut, qui sont les bases nécessaires à son fonctionnement, notamment pour gérer les authentifications et les droits d’accès.

Pour la culture, nous allons découvrir quelques informations qui peuvent vous intéresser. On commence par se connecter à la base MariaBD et à regarder les tables qu’elle continent :

MariaDB [(none)]> use mysql;
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
MariaDB [mysql]> show tables;
+---------------------------+
| Tables_in_mysql |
+---------------------------+
| column_stats |
| columns_priv |
| db |
| event |
| func |
| general_log |
| gtid_slave_pos |
| help_category |
| help_keyword |
| help_relation |
| help_topic |
| host |
| index_stats |
| innodb_index_stats |
| innodb_table_stats |
| plugin |
| proc |
| procs_priv |
| proxies_priv |
| roles_mapping |
| servers |
| slow_log |
| table_stats |
| tables_priv |
| time_zone |
| time_zone_leap_second |
| time_zone_name |
| time_zone_transition |
| time_zone_transition_type |
| user |
+---------------------------+
30 rows in set (0.00 sec)

Il y a notamment la table user qui contient les utilisateurs et leurs droits associés. Nous allons regarder la liste :

MariaDB [mysql]> select Host, User, Password from user;
+-----------+------+----------+
| Host | User | Password |
+-----------+------+----------+
| localhost | root | |
+-----------+------+----------+

Nous voyons que par défaut, il y a un utilisateur root qui a le droit de se connecter depuis l’adresse locale, avec un mot de passe vide. C’est bien ce qui nous a permis de nous connecter !

Pour ajouter un peu de sécurité, nous allons modifier ce compte et lui ajouter un mot de passe :

MariaDB [mysql]> UPDATE mysql.user SET password=PASSWORD("openclassrooms") where User="root" AND Host="localhost";
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0

Et nous pouvons vérifier que cela a bien fonctionné :

MariaDB [mysql]> select Host, User, Password from user;
+-----------+------+-------------------------------------------+
| Host | User | Password |
+-----------+------+-------------------------------------------+
| localhost | root | *EBA3137E14824BDB009C3748D68E4D18A63D8E48 |
+-----------+------+-------------------------------------------+
1 row in set (0.00 sec)

Pour vraiment vérifier, nous allons nous déconnecter et nous reconnecter sans fournir de mot de passe. Normalement, vous ne devriez plus pouvoir vous connecter :

MariaDB [mysql]> quit
Bye
root@Debian02:~# mysql -u root
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 3
Server version: 10.1.26-MariaDB-0+deb9u1 Debian 9.1

Copyright (c) 2000, 2017, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]>

Heu... nous pouvons toujours nous connecter sans mot de passe ? 

Nous avons mis un mot de passe à notre utilisateur, mais nous pouvons continuer à nous authentifier sans avoir à fournir de mot de passe. Qu’est-ce qui a bien pu se passer ?

En fait, MariaDB n’utilise pas par défaut le système d’authentification par mot de passe pour l’utilisateur root en connexion locale, mais un plugin spécifique. On peut le voir en affichant la bonne colonne de la table :

MariaDB [mysql]> select Host, User, Password, plugin from user;
+-----------+------+-------------------------------------------+-------------+
| Host | User | Password | plugin |
+-----------+------+-------------------------------------------+-------------+
| localhost | root | *EBA3137E14824BDB009C3748D68E4D18A63D8E48 | unix_socket |
+-----------+------+-------------------------------------------+-------------+
1 row in set (0.00 sec)

Il nous faut donc enlever ce plugin et dire à MariaDB de prendre en compte nos changements :

MariaDB [mysql]> update user set plugin='' where User='root';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0

MariaDB [mysql]> flush privileges;
Query OK, 0 rows affected (0.00 sec)

Et maintenant, si nous tentons de nous reconnecter, cela ne fonctionne plus !

root@Debian02:~# mysql -u root
ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: NO)

Ouf, le système réagit bien comme nous nous y attendions. Nous pouvons maintenant nous connecter de manière sécurisée à notre base, cette fois en entrant notre mot de passe openclassrooms :

root@Debian02:~# mysql -u root -p
Enter password:
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 7
Server version: 10.1.26-MariaDB-0+deb9u1 Debian 9.1

Copyright (c) 2000, 2017, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]>

Alerte de sécurité !

Nous sommes maintenant prêts pour créer notre base, ce que nous allons faire de ce pas :

MariaDB [(none)]> create database messagerie;
Query OK, 1 row affected (0.00 sec)

Puis nous allons créer un utilisateur "messagerieUser" qui aura le droit d’accéder à notre base, pour éviter de le faire avec l’utilisateur root :

MariaDB [(none)]> GRANT ALL PRIVILEGES ON messagerie.* to 'messagerieUser'@'localhost' identified by 'openclassrooms';
Query OK, 0 rows affected (0.00 sec)

MariaDB [(none)]> flush privileges;
Query OK, 0 rows affected (0.01 sec)

Nous pouvons maintenant nous déconnecter et nous reconnecter avec le compte messagerieUser pour tester que tout s’est bien passé :

root@Debian02 : ~# mysql -u messagerieUser -p
Enter password:
Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 11
Server version: 10.1.26-MariaDB-0+deb9u1 Debian 9.1

Copyright (c) 2000, 2017, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]>

Cela fonctionne ; nous allons pouvoir créer les bases nécessaires au bon fonctionnement de Postfix.

Il y a plusieurs façons de le faire. Vous pouvez vous connecter à la base et entrer toutes les commandes, mais c’est fastidieux et la moindre erreur vous obligera à tout refaire. Je vous propose plutôt de placer toutes nos commandes SQL de création des tables dans un fichier, et d’exécuter ce fichier.

Voici donc le fichier SQL à créer, que nous nommerons creation_base_messagerie.sql :

use messagerie ;
CREATE TABLE `virtual_domains` (
`id` INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

CREATE TABLE `virtual_users` (
`id` INT NOT NULL AUTO_INCREMENT,
`domain_id` INT NOT NULL,
`password` VARCHAR(106) NOT NULL,
`email` VARCHAR(120) NOT NULL,
`maildir` VARCHAR(120) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `email` (`email`),
FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

Il indique de créer une table virtual_domains qui contiendra un id et le nom de notre domaine.

Puis une autre table virtual_users qui contiendra les adresses mail de nos utilisateurs, l’id de leur domaine, et un mot de passe.

Pourquoi un mot de passe ? Nous n’en avons pas utilisé pour les adresses mail jusqu’à maintenant ?

En fait, cela nous sera utile pour la suite, notamment pour la mise en place du protocole IMAP dans le prochain chapitre.

Exécutons maintenant notre script SQL :

root@Debian02:/etc/postfix# mysql -u messagerieUser -p < creation_base_messagerie.sql
Enter password:

Et vérifions que tout s'est bien passé :

root@Debian02:/etc/postfix# mysql -u messagerieUser -p messagerie -e 'show tables'
Enter password:
+----------------------+
| Tables_in_messagerie |
+----------------------+
| virtual_domains |
| virtual_users |
+----------------------+

Nous voyons que les deux tables ont bien été créées, nous allons donc pouvoir les remplir avec nos informations de domaine et les adresses mail associées. Pour cela, nous allons créer un autre fichier SQL que nous nommerons creation_utilisateurs_messagerie.sql :

use messagerie;
INSERT INTO `messagerie`.`virtual_domains`
(`id` ,`name`)
VALUES
('1', 'mondomaine.local'); 
INSERT INTO `messagerie`.`virtual_users`
(`id`, `domain_id`, `password` , `email`, `maildir`)
VALUES
('1', '1', ENCRYPT('motDePasseDeToto', CONCAT('$6$', SUBSTRING(SHA(RAND()), -16))), ’toto@mondomaine.local', 'mondomaine.local/toto/');

Nous créons notre domaine itinet.fr, ainsi qu’une adresse mail toto@mondomaine.local.

Il faut ensuite exécuter ce fichier de la même façon que précédemment.

root@Debian02:/etc/postfix# mysql -u messagerieUser -p < creation_utilisateurs_messagerie.sql

Nous pouvons tester par exemple que l'adresse mail est bien reconnue :

root@Debian02:/etc/postfix# mysql -u messagerieUser -p messagerie -e "SELECT email FROM virtual_users WHERE email='toto@mondomaine.local'"
Enter password:
+----------------+
| email |
+----------------+
| toto@mondomaine.local |
+----------------+

A priori, tout semble correct, il nous faut maintenant modifier le fichier de configuration main.cf pour lui indiquer que notre domaine et les adresses associées sont maintenant dans une base de données SQL.

Nous allons reprendre les critères que nous avions ajoutés :

virtual_mailbox_domains = mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
virtual_mailbox_base = /var/mail/vhosts
virtual_mailbox_maps = mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
virtual_minimum_uid = 100
virtual_uid_maps = static:5000
virtual_gid_maps = static:5000

Il nous reste maintenant à créer ces fichiers qui vont indiquer à Postfix comment se connecter à notre base de données et quelle requête effectuer pour récupérer les adresses mails.

Nous créons le premier fichier /etc/postfix/mysql-virtual-mailbox-domains.cf pour l’accès aux domaines, avec le contenu suivant :

user = messagerieUser
password = openclassrooms
hosts = 127.0.0.1
dbname = messagerie
query = SELECT 1 FROM virtual_domains WHERE name='%s’

Nous pouvons dès lors relancer notre service Postfix et regarder tout de suite s’il reconnaît notre domaine :

root@Debian02:/etc/postfix# systemctl restart postfix
root@Debian02:/etc/postfix# postmap -q mondomaine.local mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
postmap: fatal: unsupported dictionary type: mysql

C’est normal. Par défaut, Postfix ne sait pas parler le langage SQL. Il faut pour cela installer un package particulier, que nous allons chercher ensemble :

root@Debian02:/etc/postfix# apt-cache search postfix | grep mysql
postfix-mysql - MySQL map support for Postfix

C'est relativement simple, nous allons pouvoir l'installer et recommencer notre test :

root@Debian02:/etc/postfix# apt-get install postfix-mysql
Lecture des listes de paquets... Fait
[...]
root@Debian02:/etc/postfix# postmap -q mondomaine.local mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
1

Cette fois, cela fonctionne bien et notre domaine mondomaine.local est bien reconnu par la réponse 1 (vous pouvez essayer d’entrer un domaine farfelu et vous verrez que dans ce cas, Postfix ne vous répondra pas avec 1).

Nous allons maintenant créer notre second fichier /etc/postfix/mysql-virtual-mailbox-maps.cf indiquant nos adresses mail :

user = messagerieUser
password = openclassrooms
hosts = 127.0.0.1
dbname = messagerie
query = SELECT maildir FROM virtual_users WHERE email='%s’

Et nous pouvons tester si cela fonctionne correctement :

root@Debian02:/etc/postfix# postmap -q toto@mondomaine.local mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
mondomaine.local/toto/

Parfait, c’est bien l’endroit où se situe la boîte aux lettres qui est renvoyé. Les mails seront donc livrés au bon endroit !

Nous sommes maintenant prêts à faire notre premier test réel !

Lancez votre premier test

Mais cette fois, nous n’allons pas utiliser Telnet, qui est un peu lourd à utiliser si nous avons beaucoup de tests à faire. Nous allons simplement envoyer un mail en ligne de commande grâce à la commande mail :

root@Debian02 : ~# echo "Salut Toto" | mail -s "Test01" toto@mondomaine.local
-bash: mail : commande introuvable

Notre système ne connaît pas la commande mail. Il va falloir l’installer, mais pour cela, il va falloir trouver le package correspondant. Dans notre cas, cela risque d’être un peu problématique, vu que le mot mail est très générique. Dans un cas comme celui-ci, il est souvent préférable de passer par notre bon ami Google (ou autre moteur de recherche qui vous plaira).

Vous pouvez faire une recherche sur les mots clefs "mail command debian package", et en suivant le premier lien, vous comprendrez que cette commande est incluse dans le package mailutils.

Nous l’installons et testons notre envoi :

root@Debian02 : ~# apt-get install mailutils
Lecture des listes de paquets... Fait
[...]
root@Debian02:~# echo "Salut Toto" | mail -s "Test01" toto@itinet.fr

Et notre mail semble bien avoir été envoyé.

Comme vous en avez acquis le réflexe, nous allons jeter un coup d’œil aux logs pour vérifier que tout s’est bien passé :

Jan 22 15:14:23 Debian02 postfix/qmgr[24842]: 671DF75A: from=<root@Debian02>, size=333, nrcpt=1 (queue active)
Jan 22 15:14:23 Debian02 postfix/virtual[25493]: 671DF75A: to=<toto@mondomaine.local>, relay=virtual, delay=0.04, delays=0.03/0.01/0/0, dsn=2.0.0, status=sent (delivered to maildir)

Et vous pouvez même aller dans la boîte aux lettres de l’utilisateur pour voir si le mail y est bien présent (ce qui devrait être le cas, mais je vous laisse faire cette fois !).

Nous venons donc de voir comment recevoir des mails pour des utilisateurs locaux, et nous avons vu trois façons différentes de créer et d’utiliser des boîtes aux lettres.

En résumé

  • Nous avons installé et configuré un serveur SMTP grâce à Postfix

  • Nous avons réussi à créer une adresse de messagerie à travers une base de données SQL et nous avons pu lui envoyer des messages.

  • Cependant, cette adresse n’utilisant pas un nom de domaine qui nous appartient, nous ne serons pas en mesure de recevoir des mails pour l’instant autrement qu’en local sur le serveur.

L'installation et la configuration du serveur SMTP est terminée pour le moment. Cependant, nous ne nous sommes pas du tout intéressés pour l’instant à l’envoi de mails vers une adresse qui n’est pas gérée par notre serveur. Nous allons nous y pencher dans le chapitre suivant

Exemple de certificat de réussite
Exemple de certificat de réussite