Release 3 OVH & Sendmail

Début de l’histoire :

Ayant utilisé pendant 2 ans une Release 2 OVH et souhaitant migrer le serveur d’un client sur une nouvelle plus sécurisée et plus performante, j’ai fais le choix d’un nouveau serveur avec une Release 3 OVH (aussi appelée R3).

Les avantages de cette distribution :

  1. créer un nombre illimité de domaine et d’alias (rappel : seuls 10 domaines sont inclus dans la licence vendue avec le serveur)
  2. créer un nombre illimité de boitemail et d’alias
  3. dispose d’un outil intégré webmail : RoundCube
  4. dispose d’un outil d’administration : Webmin (un peu plus moderne que celui de la Release 2)
  5. gère PHP (attention seule la version 5.3 est disponible et il n’est pas possible d’installer PHP 4 et PHP 7)
  6. dispose des services de base pour un serveur hébergement avec email : Apache, Postfix, SSH, Fail2Ban, WebAnalyser

=> Attention, il s’agit d’une Distribution basée sur Centos (c’est yum qui est le gestionnaire de paquet et non apt)

Sendmail le binaire d’émission des emails :

Après voir migré l’ensemble des sites + les boitemails sur le nouveau serveur le point qu’il faut absolument noter que cette distribution utilise sendmail et non mail pour émettre les mails … et que c’est particulièrement ennuyant car il va falloir réaliser des adaptations de code PHP pour que les scripts d’émission de mail fonctionne « Correctement »

Le point noir : les Mails émis

Très vite, après la mise en place du serveur et la propagation DNS, des problèmes de mails sont apparus :

cat /var/log/maillog | grep 554 # voir les mails en erreur dans 
said: 554 5.7.1 <user@votredomaine>: Recipient address rejected: Missing Authentication (in reply to RCPT TO command))

Pour faire simple, ce message d’erreur signifie que :

les mails sont bien émis (postfix marche bien) mais les mails émis ne respectent pas la norme RFC 554.

Ce que dit la norme : les mails émis doivent avoir un champ reply-to dans l’entête de mail et la valeur associée à ce champ doit être un mail valide.

Hors les mails émis via script des scripts PHP ont bien un champ reply-to mais la valeur inscrite n’est pas un mail valide mais le user système utilisé par le script :

  • REPLY-TO : user (système gérant le domaine votredomain.fr)
  • REPLY-TO : postmaster@votredomain.fr

Autre manière de voir les mails en erreur

mailq # voir la queue des mails en attente de traitement
postcat -q IDMailPostFix | less # parcourir le contenu du mail est lire le message d'erreur

Erreurs blacklistent le serveur

Attention, yahoo, gmail, orange, laposte.net refusent de traiter les mails qui ne respectent pas cette norme. Tous les mails émis vers ces sites vont automatiquement revenir avec un status status=deferred (traitement remis à plus tard) ou status=bounced(traitement a bien été réalisés mais le message est revenu au serveur car problème)

Si une grande quantité de mail sont émis , par exemple via un script de newsletter, là c’est quasi automatiquement le blacklistage qui arrive : l’adresse IP de votre serveur rentre dans les RBL (Realtime Blackhole List) et est considéré comme un serveur émetteur de spam ….
Un super site internet permet de voir rapidement si l’IP de votre serveur est blacklistée :
http://multirbl.valli.org/lookup/
multirbl

Ce que j’ai fait :

Tout d’abord trouver tous les scripts qui utilisent la fonction php mail
Une méthode simple pour réaliser ce premier défi est d’utiliser la commande suivante :

mailq # récupérer la liste des mails en status d'erreur
postcat -q IDMailPosFix | grep PHP # récupérer le nom du fichier php qui a généré le mail 
find / -name Ficher.php # récupérer le nom du fichier PHP qui a généré le mail

Modifier les scripts php :

Il faut ajouter un paramètre supplémentaire à la fonction mail avec le préfixe -f.

<?php
  $from = "from@votredomain.com";
  $to = "to@example.com";

  $header = "FROM: " . $from . "\r\n";
  $param = "-f" . $from;

  mail($to, "The subject", "Body", $header, $param);
?>

Voici un excellent article sur le sujet

WordPress class-phpmailer.php :

J’ai modifié le fichier wp-includes/class-phpmailer.php qui gère l’émission des mails (notamment lors de la modification de profil utilisateur / réinitialisation des mots de passe par un user …

private function mailPassthru($to, $subject, $body, $header, $params)
    {
        $param = "-f" . $to;
        //Check overloading of mail function to avoid double-encoding
        if (ini_get('mbstring.func_overload') & 1) {
            $subject = $this->secureHeader($subject);
        } else {
            $subject = $this->encodeHeader($this->secureHeader($subject));
        }
        if (ini_get('safe_mode') || !($this->UseSendmailOptions)) {
            $result = @mail($to, $subject, $body, $header, $param);
        } else {
            $result = @mail($to, $subject, $body, $header, $param);
        }
        return $result;
    }

Version 5.2.7 de class-phpmailer.php

private function mailPassthru($to, $subject, $body, $header, $params)
{
    $param = "-f" . $to;
    if (ini_get('safe_mode') || !($this->UseSendmailOptions)) {
        $rt = @mail($to, $this->encodeHeader($this->secureHeader($subject)), $body, $header,$param);
    } else {
        $rt = @mail($to, $this->encodeHeader($this->secureHeader($subject)), $body, $header, $param);
    }
    return $rt;
}

WordPress add_filter( ‘wp_mail’,function(){},10 ) :

Ajouter le code suivant (à adapter) dans un plugin ou dans le fichier functions.php

/**
 * Plugin Name: My Email Setup
 */

add_filter( 'wp_mail', function( $args ) {
	if ( empty( $args['headers'] ) ) {
		$args['headers'] = array(
			'From: You Name ',
		);
	}
	return $args;
}, 10 );

Plugin WordPress MailPoet :

Ce plugin WordPress permet de réaliser très facilement des newsletters, gérer des listes d’abonnée (mais surtout de déléguer à des utilisateur sans connaissances techniques la possibilité de réaliser des Newsletter) à la MailChimp.
La commande de recherche ne renvoie pas de fichier PHP mais le nom d’une librairie PHPMailer
Après pas mal de recherche, pas besoin de modifier le Plugin, il y a dans le backoffice la possibilité de régler le binaire d’envoi ainsi que le mail du Reply-to.
Pour modifier le binaire d’envoi : MailPoet / Réglages / Envoyer Par …

mailpoet

Pour modifier le mail du reply-to : MailPoet / Réglages / Avancé

mailpoet-bounce

RoundCube :

La distribution dispose d’un webmail intégré RoundCube qui a exactement le même problème que les scripts …
Un peu par hasard, j’ai trouvé que RoundCube dispose d’un base de donnée : roundcubemail et d’une table intitulée identity avec une colonne reply-to .
Il suffit de compléter la colonne pour reply-to pour que les mails émis soient conformes.
roundcube-reply-to

Enlevé l’IP du Serveur des RBL

Un ancien article traite en détail de ce sujet : Enlever son IP d’un RBL

Externaliser le maximum de fonctionnalités sensibles sur des prestataires spécialisés dans le domaine du mail :

Pour les Newsletter, j’ai opté pour MailChimp qui dispose d’une offre gratuite assez intéressante : c’est gratuit à partir pour une liste d’abonné inférieur à 2000 et 12 000 mail émis / mois
Pour les mails (Thunderbird, Outlook) : Polarismail (hélas payant) et OVH (qui inclut une boitemail offerte avec le domain . Dans ce cas de figure, il faudra changer les paramètres DNS notamment le MX pour pouvoir utiliser ces services.
L’un des avantage certain d’externaliser le maximum de service mail est que même si l’IP du serveur est blacklistée, les mails continuent de fonctionner (et ainsi intervenir et analyser le problème sans être dans l’urgence et la panique) car les mails sont émis via un serveur avec une autre IP …

Ajouter de nouvelles règles IPTABLES

IPTABLES permet de déterminer quel user system peut générer des mails. Avec ces règles, il est possible bloquer tous les scripts qui n’utilisent pas des utilisateurs systèmes légitimes pour émettre des emails :

iptables -A OUTPUT -d 127.0.0.1 -p tcp -m tcp --dport 25 -j ACCEPT;
iptables -A OUTPUT -p tcp -m tcp --dport 25 -m owner --gid-owner mail -j ACCEPT;
iptables -A OUTPUT -p tcp -m tcp --dport 25 -m owner --gid-owner mailman -j ACCEPT;
iptables -A OUTPUT -p tcp -m tcp --dport 25 -m owner --gid-owner mailboxes -j ACCEPT;
iptables -A OUTPUT -p tcp -m tcp --dport 25 -m owner --gid-owner postfix -j ACCEPT;
iptables -A OUTPUT -p tcp -m tcp --dport 25 -m owner --uid-owner root -j ACCEPT;
iptables -A OUTPUT -p tcp -m tcp --dport 25 -j REJECT --reject-with icmp-port-unreachable;

Grâce à ces 7 règles IPTABLES, seuls les utilisateurs mail, mailman, mailboxes, postfix et root peuvent utiliser le port 25 (donc envoyer des mails). Tous les autres users systèmes sont bloqués.
En fonction de la distribution et du serveur mail, ces lignes doivent être adaptées. Pour qmail par exemple, il faudra utiliser d’autre user système.

Ce que je n’ai pas fait (mais aurait bien aimé tester) :

Conclusion :

Pour conclure cet article, je dirai que lors de la migration, la partie mail a été la partie la plus galère et la plus fastidieuse. Bon j’ai appris pas mal de nouveaux trucs mais ça a été au prix de dizaine d’heure de recherche sur le web…
Sur le web, il y a plein de tuto, wiki, explication qui parlent de sendmail, postfix, envoie de mail, SPF, DKIM etc etc. et en général chaque tuto présente une méthode qui est différente …
Générer des mails est un métier, et il faut obligatoirement disposer d’une infra avec plusieurs adresses IP pour pouvoir switcher rapidement d’un IP à un autre pour ne pas être bloqué.