Serveur mail d’envoi + signature DKIM + liberté de choix d’adresse de l’expéditeur

Posted by

On entend souvent les clients OVH se plaindre à propos du mail:

  • envoi compliqué, soumis à des quotas par heure et par IP
  • réputation médiocre des serveurs d’envoi partagés avec les autres clients
  • selon l’offre d’hébergement, impossible d’envoyer un mail à partir d’un alias ou adresse de redirection
  • absence de signature DKIM
  • mails envoyés qui disparaissent parfois, et aucun moyen de les retracer
  • webmail roundcube remplacé par Outlook Web (les choix ça ne se discute pas)

Dans ce tuto pas à pas, je vous propose de réaliser un serveur mail ayant les fonctionnalités suivantes:

  • envoi uniquement
  • pas de réception de mail (donc pas de problématique de filtrage du spam, etc)
  • pas d’hébergement de boîtes mail (le serveur ne contient aucune donnée à conserver)
  • c’est “votre serveur”, donc une adresse IP dédiée dont la réputation ne tient qu’à vous
  • soumission de mail uniquement via TLS sur le port 587 pour les utilisateurs autorisés.
  • Le port 25 est fermé.
  • le login d’authentification n’est pas relié à l’adresse mail de l’expéditeur
  • ajout de la signature DKIM pour un ou plusieurs domaines
  • accès aux fichiers log permettant un diagnostic (livraison ? refus ? etc)
  • En option, installation d’un serveur webmail roundcube, les messages restant sur le serveur IMAP. C’est publié ici !

Le tuto est réalisé sur la base d’un serveur VPS à 3€ TVAC par mois, loué au mois sans engagement, chez le fournisseur Hetzner. Il a un processeur 1 coeur, 20 GB de disque, 2 GB de RAM. C’est largement suffisant pour ce qu’on veut en faire. Vous avez le choix du fournisseur de cloud VPS. Il faut un VPS où vous avez le droit ‘root’.

Au niveau logiciel, debian 10.3, postfix, sasl, opendkim.

Il faut baptiser ce serveur (lui donner un nom complet dans un de vos domaines). Je déconseille formellement les nouveaux noms de domaines .site, .xyz, .pro, .bid, .best et autres, aussi bien dans le nom du serveur que dans les adresses mail d’expéditeur. Ces suffixes sont trop abusés par les spammeurs.

Appelons notre serveur bazooka.example.com dans la suite.

Supposons que vous avez 2 clients Tom et Jerry qui doivent recevoir chacun un login pour pouvoir envoyer des mails via ce serveur. Vous devez avoir confiance dans vos clients. Si l’un d’eux se met à spammer, il va pourrir la réputation de l’adresse IP de votre serveur.

Tom possède 2 domaines asteryx.be et obelyx.be dont les mails sortants devront être signés DKIM en sortie par notre serveur. (à la date de rédaction, ces 2 domaines sont libres)

Au niveau DNS, on devra

  • ajouter une entrée A pour bazooka.example.com. La mise à jour se fait dans la zone DNS là où le domaine example.com est hébergé.
  • mettre à jour le reverse (une entrée PTR) liée au serveur VPS. Cette mise à jour se fait chez le fournisseur du VPS et doit intervenir après l’étape précédente. N’oubliez pas de faire de même pour votre adresse IPv6 le cas échéant. C’est nécessaire pour le mail sortant.
  • ajouter une entrée TXT pour chacune des clés publiques DKIM. Cette mise à jour se fait par Tom ou son prestataire, auprès de l’hébergeur des domaines asteryx.be et obelyx.be.
  • Si vos domaines ont un enregistrement SPF, n’oubliez pas d’y ajouter l’adresse IP de votre nouveau serveur sous la forme IP4:123.45.67.89 . Idem pour l’adresse IPv6.

Hop à vos claviers ! Vous êtes supposé être capable d’utiliser ssh, putty, vi ou nano, et les commandes basiques.

Le serveur VPS est livré avec Debian 10 “tout nu”.

Commencez par changer le mot de passe de ‘root’, minimum 10 caractères, lisez mon article : Votre mot de passe est-il sûr ? .
Ou mieux, abandonner les bons vieux mots de passe au profit des clés ssh.

Mise à jour du système

apt-get update && apt-get dist-upgrade

Une petite parenthèse ici: si vous ne souhaitez pas que l’éditeur vi fasse de l’analyse syntaxique en couleurs, tapez la commande suivante:

echo syntax off >> ~/.vimrc

On va indiquer le nom du serveur, en éditant /etc/hostname : mettre le nom complet bazooka.example.com ; et /etc/hosts  : à côté de l’adresse IP remplacer l’ancien nom par le nom complet, un espace, puis le nom court:

123.45.67.89 bazooka.example.com bazooka

Définition de notre fuseau horaire:

dpkg-reconfigure tzdata

Un reboot à ce stade ne fait pas de tort: “reboot” ou “shutdown -r now”.
Ensuite on va installer les packages qui nous intéressent, d’abord nos boîtes à outils:

apt-get install whois at telnet ntp mailutils dnsutils

et ensuite

apt-get install postfix

Cette installation pose une question. Il faut dire qu’il s’agit d’un “internet site” et renseigner le nom de ce serveur: bazooka.example.com

On continue:

apt-get install sasl2-bin libsasl2-modules

Comment cela fonctionne-t-il ?

Postfix transporte du mail mais ne gère pas l’authentification des utilisateurs. Pour cela on fait appel à un “sous-traitant” nommé SASL, une librairie qui sert exclusivement à cela.

Installation de SASL

Dans notre serveur, SASL validera sur base d’un compte Unix.
Configuration de SASL, on édite le fichier /etc/default/saslauthd

On change la ligne:
START=yes
Remarquez MECHANISMS=”pam” qui indique l’utilisation du compte Unix

et la dernière ligne doit être remplacée par:

OPTIONS="-c -m /var/spool/postfix/var/run/saslauthd"

Sauvez le fichier.

On doit mettre Postfix dans le groupe SASL pour pouvoir avoir accès au socket de communication inter-processus.

adduser postfix sasl

et on redémarre le démon:
service saslauthd restart

On crée un compte pour tom

adduser tom
(-> répondre aux questions )

chsh tom
(-> répondre: /usr/sbin/nologin )

On vérifie que SASL est capable de valider le login/pass de Tom:

testsaslauthd -u tom -p goodpassword -f /var/spool/postfix/var/run/saslauthd/mux
0: OK "Success."
testsaslauthd -u tom -p badpassword -f /var/spool/postfix/var/run/saslauthd/mux
0: NO "authentication failed"

On fait de même pour jerry.

Configuration de Postfix

Postfix s’appuie essentiellement sur deux fichiers /etc/postfix/master.cf et /etc/postfix/main.cf.

Editez /etc/postfix/master.cf pour apporter les modifications suivantes:

  • Mettez en commentaire la ligne qui commence par “smtp”. Ceci empêchera la réception de mail sur notre serveur.
  • Décommentez la ligne qui commence par #submission ainsi que la dizaine de lignes de continuation qui suivent.

Editez /etc/postfix/main.cf  et ajoutez ce bloc de lignes, mettez-le par exemple en-dessous des paramètres TLS

# suggéré via blog.demees.net
smtpd_restriction_classes = mua_sender_restrictions, mua_client_restrictions, mua_helo_restrictions
mua_client_restrictions = permit_sasl_authenticated, reject
mua_sender_restrictions = permit_sasl_authenticated, reject
mua_helo_restrictions = permit_mynetworks, reject_non_fqdn_hostname, reject_invalid_hostname, permit
smtpd_sasl_auth_enable = yes
smtpd_sasl_path = smtpd
smtp_tls_security_level = may
message_size_limit = 40960000

Plus bas, vérifiez que la ligne “myhostname=” contient bien le nom complet du serveur, par exemple bazooka.example.com.

Il faut relier Postfix avec le démon saslauthd, via le fichier /etc/postfix/sasl/smtpd.conf :

pwcheck_method: saslauthd
mech_list: PLAIN LOGIN

Sauvez, et puis tapez la commande: postfix reload

A ce stade le serveur mail est opérationnel, mais sans DKIM.

Installation de OpenDKIM

Comme pour SASL, l’ajout de DKIM se fait par un module complémentaire.

Postfix et DKIM vont communiquer par un “socket” TCP n° 12301 choisi arbitrairement et que vous pouvez altérer à votre guise, des deux côtés de la configuration.

apt-get install opendkim opendkim-tools

A nouveau, on va éditer les fichiers de configuration, puis créer des clés pour les domaines dont il faut authentifier les mails.

Edition de /etc/opendkim.conf

On va ajouter tout un bloc de paramètres, et s’assurer de bien désactiver (mettre en commentaire) toute instruction contradictoire déjà présente.

# suggéré via blog.demees.net, inspiré d'un tuto sur Digitalocean
AutoRestart Yes
AutoRestartRate 10/1h
UMask 002
Syslog yes
SyslogSuccess Yes
LogWhy Yes
Canonicalization relaxed/simple
ExternalIgnoreList refile:/etc/opendkim/TrustedHosts
InternalHosts refile:/etc/opendkim/TrustedHosts
KeyTable refile:/etc/opendkim/KeyTable
SigningTable refile:/etc/opendkim/SigningTable
Mode s
PidFile /var/run/opendkim/opendkim.pid
SignatureAlgorithm rsa-sha256
UserID opendkim:opendkim
Socket inet:12301@localhost

Edition de /etc/default/opendkim : une seule ligne “SOCKET” doit subsister comme ceci. Les autres lignes “SOCKET=”doivent être mises en commentaire.

SOCKET=inet:12301@localhost

On doit encore ajouter quelques lignes à la configuration de Postfix pour lui indiquer comment communiquer avec OpenDKIM.

Ajoutez ces lignes dans /etc/postfix/main.cf, par exemple juste en-dessous de celles qu’on a ajoutées précédemment:

#OpenDKIM
milter_protocol = 2
milter_default_action = accept
smtpd_milters = inet:localhost:12301
non_smtpd_milters = inet:localhost:12301

On a encore du travail avec OpenDKIM

mkdir /etc/opendkim
mkdir /etc/opendkim/keys

On va créer une paire de clés par domaine. J’explique pour asteryx.be, il en est de même pour obelyx.be.

cd /etc/opendkim/keys
mkdir asteryx.be && cd asteryx.be
opendkim-genkey -s selector1 -d asteryx.be
chown opendkim:opendkim selector1.private

Il en résulte deux fichiers: selector1.private (clé privée à garder précieusement) et selector1.txt (clé publique à publier via DNS)

On va encore créer les fichiers suivants dans /etc/opendkim :

/etc/opendkim/TrustedHosts

127.0.0.1
localhost
192.168.0.1/24
#*.example.com

/etc/opendkim/SigningTable

*@asteryx.be selector1._domainkey.asteryx.be
*@obelyx.be selector2._domainkey.obelyx.be

/etc/opendkim/KeyTable

selector1._domainkey.asteryx.be asteryx.be:selector1:/etc/opendkim/keys/asteryx.be/selector1.private
selector2._domainkey.obelyx.be obelyx.be:selector2:/etc/opendkim/keys/obelyx.be/selector2.private

selector1 et selector2 sont des exemples, vous pouvez mettre ce que vous voulez en format alphanumérique, ce peut être bazooka, mail, mars2020. Il faut juste que ça corresponde avec l’entrée DNS que vous allez créer.

Vous transmettez le fichier asteryx.be/selector1.txt à l’administrateur du domaine asteryx.be. Celui-ci doit s’arranger pour ajouter cette clé publique dans un enregistrement TXT de sa zone DNS. Ca peut se trouver un peu compliqué car le contenu du champ est assez long. Parfois on doit passer par une édition en mode texte pour ajouter un tel enregistrement. La clé publique à publier dans DNS se trouve dans le fichier selector1.txt .

Voici un exemple avec k3 comme nom de selecteur et le nom de domaine fdm.ovh.

root@k3:/etc/opendkim/keys/fdm.ovh# cat k3.txt
k3._domainkey   IN      TXT     ( "v=DKIM1; h=sha256; k=rsa; "
          "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuWfTdOfeAXRt7nZkRSy46JWpk6mTC1vPtvUVdEQmYv+fzHesqWxtV8Ww7uq8L63p2L6OU8p61Deslodj3YjFL8vw9nVgt3/I1igPaPMuRcbHaM4WQnjOw6exP+U8qMTZEIpTgByowmmIruWXx/60QamRWGxdBxEWR9wZAgMZNYlVuafR+HjcdS1m2sVZqNSPFqx/q1E8ZnAyHI"
          "L0rQ7/qtIMHAB4MlK/eVvPPmGvx4djlaQJpCZfgMDdg0dzJMMvUMu37csCQcW/2XkoSOm6N2GlCEvKeYA2fZ66sKPKR3RhIuPZR/XHwLM/2fcsuUu6A/NiMSW1okmt/prI1xNaIQIDAQAB" )  ; ----- DKIM key k3 for fdm.ovh

après importation réussie dans DNS vous pouvez vérifier avec la commende dig, tout est sur une ligne. La commande nslookup peut vous présenter la réponse en plusieurs lignes où chaque morceau est encadré avec des apostrophes (“).

# dig +short k3._domainkey.fdm.ovh txt
"v=DKIM1; h=sha256; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuWfTdOfeAXRt7nZkRSy46JWpk6mTC1vPtvUVdEQmYv+fzHesqWxtV8Ww7uq8L63p2L6OU8p61Deslodj3YjFL8vw9nVgt3/I1igPaPMuRcbHaM4WQnjOw6exP+U8qMTZEIpTgByowmmIruWXx/60QamRWGxdBxEWR9wZAgMZNYlVuafR+H" "jcdS1m2sVZqNSPFqx/q1E8ZnAyHIL0rQ7/qtIMHAB4MlK/eVvPPmGvx4djlaQJpCZfgMDdg0dzJMMvUMu37csCQcW/2XkoSOm6N2GlCEvKeYA2fZ66sKPKR3RhIuPZR/XHwLM/2fcsuUu6A/NiMSW1okmt/prI1xNaIQIDAQAB"

C:\> nslookup -q=txt selector3._domainkey.fdm.ovh
Server:  s.home.local
Address:  192.168.99.2

Non-authoritative answer:
selector3._domainkey.fdm.ovh    text =

        "v=DKIM1; h=sha256; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA16O6zg653ZlnH6gSj+XcW1+bM07qXMuQ3dOOkcCgUQ6xAOMe+EtlMSGs7SdvcCG5PM7d0G3VxZx2CpXU56M3pa3/j7yV3CE2Iq+YEKeNoo/rdiTD5wbGnGmcIOxrLKfzUQoGGdfLjXt8L0OBaFa5xjamZQk/bjz+zIWRKEoXpG95N2VbAU"
        "U1oR3wbLzwuz6W2KOViP1ihK5/iIUbNBKPOF/Ue6lz8bZuSVJc54+PWdHxv/t+E51wvErFHpoFEVNnCdFbLZWL6fZ0pGdFKIv1sllKNhHw1orwGi/4UGuitLtnRsPIw2qjFXWC8XKDUrVKUDxf0i3I9wK9LEXBp63e9QIDAQAB"

Pour être certain que tout est bien réalisé et que tout redémarre de manière ordonnée, faites un reboot (toujours avec la commande “reboot” ou la commande “shutdown -r” ; jamais via le panneau d’administration de votre cloud ! jamais en tirant la prise !)

Enfin il nous reste une petite intervention à faire: si le serveur doit envoyer des mails à postmaster ou root, vous souhaitez les recevoir sur votre adresse habituelle.

Editez le fichier /etc/aliases, ajoutez une ligne

root: moi@example.net

sauvez et tapez la commande : newaliases.
Faites un test avec la commande: “echo test|mail root”

Ceci termine l’installation du serveur mail.
La maintenance est minimale. Par défaut Debian fait le ménage régulier des fichiers log pour que le disque ne se remplisse pas. Le serveur est peu vulnérable aux attaques si les mots de passe sont bien choisis.

Configuration de votre logiciel client

Dans votre client mail, par exemple Thunderbird, vous configurez un nouveau serveur d’envoi avec les paramètres suivants:

Thuderbird SMTP settings

Le mot de passe sera demandé lors de la première utilisation.

Et le webmail Roundcube ?

Je vous l’avais annoncé en titre. Avec le confinement du Coronavirus, j’ai trouvé le temps de rédiger cet article ! C’est par ici …

 

12 comments

  1. Bonjour,

    Merci pour ce tuto, celà m’a permis de mettre en place mon relay smtp pour mon domaine hébergé sur mon NAS Synology, car Orange bloque le port 25.

    Par contre j’ai testé un serveur vps chez OVH et j’ai tenté un envoi de mail sur Gmail, qui est bien arrivé, sur Outlook, IP bloquée et sur Yahoo, mail en spam.

    Mon DKIM, SPF et DMARC sont nickel.

    J’ai envoyé un message au support Outlook qui me dis d’inscrire l’IP aux deux programmes JMRP et SNDS.

    J’ai tenté un autre serveur, mais sur Scaleway, Gmail OK, Outlook et Yahoo, mail en spam.

    Mon domaine est un domaine en .xyz.

    Avez vous réussi chez Hetzner, tout est OK ?

    En vous remerciant par avance.

    1. Bonjour Michel,

      Je viens de renoncer à ce VPS chez Hetzner car c’est tout leur réseau qui est globalement banni à plusieurs endroits. Et pour trouver un morceau d’être humain chez qui aller se plaindre chez Orange, SFR, Skynet, c’est juste impossible. Et même pire, sans compte client impossible de remplir un formulaire.

      En fait plus facile de se faire accepter chez Gmail et Outlook.com que chez tous ces petits ayatollahs qui administrent le service mail des FAI nationaux.

      P.S L’adresse IP en question n’était blacklistée nulle part.

      1. Frédéric,

        Effectivement pas terrible.

        Et oui malheureusement, même avec une IP non blacklistée, si pas de réputation que ce soit serveur ou IP, il y a peu de chance d’arriver dans les courrier légitimes.

        J’ai quand même trouvé une solution qui revient à 30€ par mois, c’est d’utiliser Amazon SES avec IP dédiée.

        Ca me permet de garder le controle sur mes mail sur le Syno.

        Avec cette solution mes mail ne vont plus en spam.

        Après J’ai quand même essayé Microsoft 365 et même avec eux j’arrive chez Outlook ou Hotmail en spam, le comble pour des solutions d’une même entreprise. J’ai appelé leur support qui me dis que malheureusement, il n’y a pas de solution car ils n’ont pas de relation avec les équipe Outlook et une partie de leur pool d’IP est blacklist chez Outlook.

  2. bonjour,
    J’ain essayé de suivre a la letre les indications, mais apparement le dkim n’est toujours pas signé. Y a t’il une possibilité de verifier si la clé privée créé par opendkim est bien prise en compte par Postfix? ou verifier si il y a des erreurs?

    Merci,

    1. Bonjour Calin,

      Il faudrait analyser les en-têtes SMTP du message reçu pour voir s’il contient une signature DKIM. Il faudrait aussi analyser les logs de Postfix, toutes les actions de OpenDKIM y sont consignées.

  3. Bonjour Frédéric,

    Merci pour ce superbe tutoriel.
    Pourquoi être passé par socket INET plutôt que le défaut (dans ma distrib Ubuntu) ?

    /etc/default/opendkim : SOCKET=local:$RUNDIR/opendkim.sock
    /etc/opendkim.conf : local:/run/opendkim/opendkim.sock

    Merci.

    1. Et pourquoi pas ? Les deux se valent, du moment que le socket INET n’écoute que sur localhost…
      Du moment que c’est efficace et en toute sécurité.

  4. Bonjour,

    Ma configuration de postfix avait « inet_interfaces = loopback-only » (dans /etc/postfix/main.cf) et décommenter la ligne « submission inet n – y – – smtpd » et ses options ne suffisait pas à ouvrir le port 587.
    Je suis passé à « inet_interfaces = all ».

    Les commandes « netstat -na | grep LISTEN | grep 587 » et « netstat -na | grep LISTEN | grep 25 » permettent de vérifier quels ports sont ouverts en écoute, et j’ai vérifié par nmap depuis une machine extérieure pour m’assurer que le port 25 n’est pas ouvert.

    J’avoue que je suis tout de même inquiet par l’ouverture du port 587, même si la documentation de Postfix semble indiquer que « submission » est bien pour la primo-réception de mails depuis des clients mails qui s’autentifient. J’ai lu les règles de smtpd_*_restrictions suggérées ci-dessus et laissé les autres valeurs par défaut. Une valeur vide « smtpd_recipient_restrictions= » m’inquiète cependant.

    Comment s’assurer qu’on ne laisse pas une porte béante sur le port 587 ? Avec Telnet (ou nc) on peut faire le EHLO puis j’obtiens « 530 5.7.0 Must issue a STARTTLS command first ».

    J’ai suivi l’exemple de https://wiki.zimbra.com/wiki/Simple_Troubleshooting_For_SMTP_Via_Telnet_And_Openssl#For_TLS.2FSSL_-_Example pour me connecter en SSL sur le 587. Je peux faire le EHLO et annoncer un « mail from: » mais le « rcpt to: » me renvoit « Client host rejected: Access denied ». Ça semble bon. J’ai essayé en mettant une adresse locale à mon domaine pour le from, et une adresse existante pour le to. Ça semble rejeté. Ai-je couvert tous les cas ? Je n’ai pas essayé « pouet@localhost » ni 127.0.0.1 etc… Ma méthode me semble fastidieuse.

    Comment m’assurer qu’une authentification est indispensable préalablement à toute action ?

    Merci !

    1. En fait, après avoir renoncé à mon VPS chez Hetzner, j’ai installé Yunohost sur un kimsufi que j’ai chez OVH.
      Yunohost vaut la peine d’être testé. Ca nécessite un debian de base, et honnêtement je le trouve super !

  5. Merci pour ce tuto
    En complément je pense qu’il faut ajouter l’installation de certificat letsencrypt
    sudo apt install certbot
    sudo certbot certonly –standalone -d mail.example.com

    sudo postconf -e ‘smtpd_tls_cert_file = /etc/letsencrypt/live/mail.example.com/fullchain.pem’
    sudo postconf -e ‘smtpd_tls_key_file = /etc/letsencrypt/live/mail.example.com/privkey.pem’

    1. Merci pour ce commentaire.
      Grâce à Let’s Encrypt les certificats auto-signés ont tendance à disparaître, dans les échanges mail aussi.

      1. Oui et j’ai testé avec la dernière version de thunderbird, sans un serveur avec un certificat valide, il refuse de se connecter. Après installation d’un certificat letsencrypt ça passe.

Comments are closed.