Je suis Charlie

Autres trucs

Accueil

Seulement les RFC

Seulement les fiches de lecture

Ève

RFC 5321: Simple Mail Transfer Protocol

Date de publication du RFC : Octobre 2008
Auteur(s) du RFC : J. Klensin
Chemin des normes
Première rédaction de cet article le 1 octobre 2008


Ce RFC normalise la version actuelle de SMTP, le protocole de transfert de courrier électronique qui est un des grands succès de l'Internet et toujours une de ses applications les plus populaires, malgré les attaques des spammeurs et la concurrence des blogs et de la messagerie instantanée.

Ce protocole a été successivement normalisé par les RFC 788 (qui avait lui-même été précédé par des RFC décrivant des protocoles qui étaient très proches de SMTP), RFC 821, RFC 2821 et désormais notre RFC 5321. Le RFC 788 datant de novembre 1981, SMTP a donc vingt-sept ans.

Parmi ses caractéristiques principales, on trouve la simplicité, qui lui vaut son nom (écrire un client SMTP est simple), le fait qu'il permette le relayage du courrier par des serveurs intermédiaires et le fait qu'il ne spécifie que le transport du message, pas son contenu, qui fait l'objet du RFC 5322.

Il est intéressant de noter que, s'il a gagné en fonctions, SMTP en a aussi perdu dans certains cas. C'est ensuite que les fonctions de messagerie instantanée (voir annexe F.6) ont disparu avec le RFC 2821, le routage par la source également (annexe F.2) ou que la simple soumission du courrier par le logiciel client est désormais traitée par le RFC 6409, le SMTP complet étant réservé aux communications entre serveurs de messagerie.

La section 2 du RFC traite en détail du modèle de fonctionnement de SMTP. Le principe est que l'émetteur trouve le serveur distant (en général grâce aux enregistrements MX du DNS) puis ouvre une connexion TCP avec ce serveur distant, connexion sur laquelle on transmet l'adresse de l'expéditeur, celle du destinataire et le message (ces deux adresses forment donc ce qu'on appelle l'enveloppe, qui ne fait pas partie du message ; elles ne sont pas forcément identiques aux adresses qu'on trouve dans les champs From: et To: du message). (L'annexe B revient également sur certains aspects de la séparation entre l'enveloppe et le message. Ainsi, faire suivre un message en se fiant aux en-têtes To: du message, au lieu d'utiliser l'enveloppe, va très probablement produire des boucles sans fin.)

Le serveur distant n'est pas forcément la destination finale, il peut être un simple relais (un relais utilise SMTP des deux côtés) ou une passerelle (la passerelle parle SMTP d'un côté mais utilise un autre protocole, par exemple un protocole privé, de l'autre côté, cf. section 2.3.10).

En théorie (et la section 2.1 insiste sur ce point), le serveur qui a accepté un message doit le délivrer ou bien prévenir l'expéditeur. Aujourd'hui, avec la prolifération du spam et des joe jobs, ce principe n'est plus tenable et cette partie du RFC est donc celle qui est la plus ignorée. Une discussion sur ce point figure dans le RFC, aux sections 6.1, 6.2 et 7.8, qui admettent que « In today's world, [...] those principles may not be practical. » en rappelant toutefois qu'il faut être prudent, contrairement à beaucoup d'opérateurs de serveurs de messagerie qui jettent de nombreux messages sans garder de trace, ce qui jette un sérieux doute sur la fiabilité du service de courrier.

SMTP est simple, mais extensible. La section 2.2 résume le modèle d'extensibilité de SMTP, qui avait été intégré à partir du RFC 2821. Il repose sur une nouvelle commande pour s'annoncer au serveur distant, EHLO, qui remplace l'ancien HELO, et qui permet d'annoncer les extensions que l'ou ou l'autre MTA accepte. La section 2.2.1 insiste toutefois sur le fait que l'une des forces de SMTP est sa simplicité et qu'il ne faut donc peut-être pas trop le charger d'extensions, si elles ne sont pas clairement utiles.

La (longue) section 2.3 est consacrée à la terminologie. Elle rappelle notamment la distinction entre enveloppe et message, signalée plus haut. C'est ainsi que la définition des en-têtes du message comme Subject: ou bien Date: est laissée au RFC 5322, alors que celle du corps du message est du domaine de MIME (RFC 2045).

C'est également dans cette section de terminologie que sont définis des termes comme MTA ou MUA même si le RFC note (section 2.3.3) que, dans ce monde peu organisé, il ne faut pas toujours prendre les mots trop sérieusement.

La section suivante, 2.4, couvre les principes de base de la syntaxe SMTP, comme le fait que les commandes sont du texte, pas du binaire, qu'elles sont insensibles à la casse, et que les réponses à ces commandes sont des nombres de trois chiffres, conçus pour être interprétés par un programme (par exemple, 500 signifie « Erreur de syntaxe »).

Place ensuite, en section 3, aux procédures SMTP. Le cœur du protocole est là, notamment dans la section 3.3 qui explique l'enchaînement des commandes. Quatre sont particulièrement importantes, EHLO pour se connecter (section 4.1.1.1), MAIL FROM pour indiquer l'expéditeur (section 4.1.1.2), RCPT TO pour le destinataire (section 4.1.1.3) et DATA pour envoyer le message (section 4.1.1.4).

Voici un exemple d'une session SMTP, telle que l'affiche, pour nous aider au déboguage, le client SMTP msmtp, lorsqu'il est lancé par echo TEST | msmtp --from=foobar@example.org --debug stephane@bortzmeyer.org (les lignes préfixées par <-- sont envoyées par le serveur SMTP de réception, celles commençant par --> par celui d'émission) :


<-- 220 relay1.nic.fr ESMTP Postfix
--> EHLO bortzmeyer.nic.fr
<-- 250-relay1.nic.fr
<-- 250-PIPELINING
<-- 250-SIZE 10240000
<-- 250-VRFY
<-- 250-ETRN
<-- 250-ENHANCEDSTATUSCODES
<-- 250-8BITMIME
<-- 250 DSN
--> MAIL FROM:<foobar@example.org>
--> RCPT TO:<stephane@bortzmeyer.org>
--> DATA
<-- 250 2.1.0 Ok
<-- 250 2.1.5 Ok
<-- 354 End data with <CR><LF>.<CR><LF>
--> TEST
--> .
<-- 250 2.0.0 Ok: queued as 92859A1D95D
--> QUIT
<-- 221 2.0.0 Bye

On voit, et c'est une des caractéristiques importantes de SMTP, que l'émetteur peut indiquer ce qu'il veut comme expéditeur. Cela permet les usurpations d'identité mais il n'est pas évident de résoudre ce problème de sécurité sans supprimer en même temps bien des usages utiles du courrier. Si le serveur SMTP initial peut à la rigueur authentifier ses clients, les serveurs suivants n'ont guère le choix, sinon de tout accepter.

Et voici ce qu'affiche un programme Python qui utilise la bibliothèque smtplib. Notons que les commandes de la bibliotèque portent le nom des commandes SMTP. Ici, on n'utilise que la commande de bienvenue initiale, EHLO :


% python
...
>>> import smtplib
>>> s = smtplib.SMTP("mail.example.org")
>>> s.set_debuglevel(True)
>>> s.ehlo("mail.foobar.example")
send: 'ehlo mail.foobar.example\r\n'
reply: '250-horcrux\r\n'
reply: '250-VRFY\r\n'
reply: '250-ETRN\r\n'
reply: '250-STARTTLS\r\n'
reply: '250-ENHANCEDSTATUSCODES\r\n'
reply: '250-8BITMIME\r\n'
reply: retcode (250); Msg: mail.example.org
VRFY
ETRN
STARTTLS
ENHANCEDSTATUSCODES
8BITMIME
(250, 'mail.example.org\nVRFY\nETRN\nSTARTTLS\nENHANCEDSTATUSCODES\n8BITMIME')

On trouve d'ailleurs des mises en œuvre de SMTP pour tous les langages de programmation, pour Emacs Lisp, pour Haskell...

En théorie, le serveur SMTP ne devrait pas du tout toucher au message qu'il convoie. Mais il existe quelques exceptions. Par exemple, la section 3.7.2 couvre le cas des en-têtes Received: dans le message (également discutés en section 4.4). Très utiles au déboguage, ceux-ci doivent être ajoutés par chaque serveur SMTP qui a relayé le message. Pour le premier exemple ci-dessus, l'en-tête Received: ressemblera à :


Received: from bortzmeyer.nic.fr (batilda.nic.fr [192.134.4.69])
        by relay1.nic.fr (Postfix) with ESMTP id 92859A1D95D
        for <stephane@bortzmeyer.org>; Sun, 28 Sep 2008 03:56:11 +0200 (CEST)

Enfin, la section 4.1 décrit une par une toutes les commandes SMTP et leur syntaxe. La section 4.2 décrit, elle, les réponses. Composées de trois chiffres, le premier indique si la réponse est positive, négative ou incomplète (ainsi, 2xy indique que le serveur qui répond est satisfait, 5xy qu'il ne l'est pas et 4xy qu'il y a eu un problème temporaire). Le second chiffre, lui, indique le genre de la réponse : x0z pour ce qui concerne la syntaxe, x2z pour le réseau, etc. On peut donc en déduire que 421 signifie un problème temporaire avec le réseau, forçant à fermer la connexion (section 3.8).

Tout cela est bien beau, mais cela ne fait que spécifier le dialogue avec un serveur distant qu'on a déjà trouvé. Et comment le trouver ? Si je suis un MTA et que je veux transmettre un message envoyé à postmaster@gmail.com, comment est-ce que je trouve l'adresse du ou des serveurs responsables de gmail.com ? Si on refaisait SMTP en partant de zéro aujourd'hui, j'utiliserai sans doute les enregistrements SRV du RFC 2782. Mais le courrier électronique a été normalisé longtemps avant ce RFC et il utilise donc une sorte d'enregistrements SRV spécifique, les enregistrements MX. Le MTA regarde donc dans le DNS les MX de gmail.com :

% dig MX gmail.com.
gmail.com.		3600	IN	MX	5 gmail-smtp-in.l.google.com.
gmail.com.		3600	IN	MX	10 alt1.gmail-smtp-in.l.google.com.
...

et sait donc qu'il doit contacter gmail-smtp-in.l.google.com. La section 5 du RFC est consacrée à ce mécanisme.

Que faire s'il n'y a pas d'enregistrement MX ? La question a toujours été chaudement discutée chez les passionnés de SMTP, mais particulièrement lors de la rédaction de ce RFC 5321. En effet, l'ancienne règle (section 5 du RFC 2821) était qu'on utilisait, s'il était présent, un enregistrement A (une adresse IPv4), qualifié de « MX implicite ». Ce mécanisme est très critiqué : les domaines ont souvent un enregistrement A pour le Web (afin de pouvoir taper http://example.net/ et pas seulement http://www.example.net/) et la machine qu'il indique n'a pas forcément de serveur de courrier. En outre, que faut-il faire s'il n'y a pas d'enregistrement A mais un AAAA (une adresse IPv6) ? Notre RFC s'éloigne donc du RFC 2821 ici et décide de garder l'ancienne convention du MX implicite (au nom de la continuité), en l'étendant à IPv6 (voir la discussion en section 5.2). Les termes de « A RR » (A resource record, enregistrement de type A) ont ainsi disparus au profit de address RR qui regroupe A et AAAA.

On note qu'il n'existe pas de moyen normalisé de dire « Je ne veux pas recevoir de courrier » ; ne pas avoir de MX ne suffit pas, en raison de la règle maintenue d'un MX implicite ; la méthode la plus courante, mais non standard, est de publier un MX délibérement invalide, pointant par exemple vers . (la racine) ou vers localhost.

Notons que la section 5 précise qu'un émetteur SMTP doit essayer d'envoyer à toutes les adresses IP, pas uniquement à tous les MX (un serveur peut avoir plusieurs adresses).

La section 6 est consacrée aux problèmes et à tout ce qui peut aller mal. Par exemple, la sous-section 6.4 parle des rapports avec les implémentations qui violent la norme. Elles sont très nombreuses (historiquement, Lotus Notes semble avoir la médaille des problèmes). Depuis que le courrier existe, il y a des polémiques entre les « éradicateurs » qui demandent que les serveurs SMTP refusent de compenser ces violations et stoppent tout dialogue avec les logiciels trop bogués et les « conciliateurs » qui, après avoir fait trois génuflexions vers la statue de Jon Postel et cité son « principe de robustesse » (« Be conservative in what you send and liberal in what you accept »), demandent qu'on essaie malgré tout de parler avec les programmes ratés. Le problème est d'autant plus difficile que tous les développeurs ne sont pas égaux : on peut difficilement refuser de parler aux serveurs de messagerie d'AOL, quelles que soient les curieuses pratiques qu'ils utilisent. Même chose avec des logiciels très répandus comme Microsoft Exchange.

Une autre partie du problème est que certains MUA ont des capacités limitées et qu'on ne peut pas trop exiger d'eux. Ainsi, les serveurs SMTP ont pris l'habitude de réparer les messages, en rectifiant par exemple les champs Date: invalides (une bogue très fréquente). Ces réparations devraient, dit le RFC, être limitées aux clients locaux, que l'on connait, et ne pas s'étendre aux machines d'autres domaines. Cette approche est cohérente avec le RFC 6409 (qui sépare la soumission d'un message depuis un MUA vers le premier MTA, de l'envoi d'un message entre MTA) mais avec certains logiciels, comme Postfix, elle ne peut pas être configurée.

Toute aussi brûlante est la question de la sécurité du courrier électronique, qui fait l'objet de la section 7. D'abord (section 7.1), il y a le problème de l'authentification : un serveur SMTP peut toujours prétendre que le courrier vient de pape@nic.va, il n'y a aucun moyen de vérifier. (De très nombreux projets ont visé à traiter ce problème, voir par exemple les RFC 7208 et RFC 6376 mais il est bien plus compliqué qu'il n'en a l'air, notamment parce qu'il n'existe pas de système d'identité international et reconnu.) Le RFC recommande donc d'authentifier ses messages, par exemple avec le RFC 4880.

La section 7.9, elle, couvre les questions opérationnelles liées à la sécurité. Par exemple, certains fournisseurs de courrier (notamment AOL, qui s'en vante bruyamment), refusent le courrier de certains sites, sur des critères décidés unilatéralement et sans prévenir leurs propres utilisateurs. D'une certaine façon, c'est compréhensible, puisque l'ampleur du spam nécessite des mesures souvent radicales. Mais cela peut, si on poursuit cette logique, mener à un système de courrier qui serait réservé à un oligopole de quelques fournisseurs qui s'acceptent entre eux (le projet du MAAWG).

C'est la même section qui mentionne les relais ouverts, en des termes étonnamment prudents (la pratique générale est de les supprimer). Comme autre exemple de code Python pour faire du SMTP, voici un programme pour tester si un serveur est un relais ouvert.

Ce RFC ne marque guère de changements par rapport à son prédécesseur, le RFC 2821. Le but principal était de le faire avancer sur le chemin des normes, vers son nouveau statut de « Projet de norme ». Les changements ? Eh bien, le principal étant l'extension du « MX implicite » à IPv6.

Ce RFC a été longtemps retardé par une amusante et exaspérante « querelle des exemples » et a même fait l'objet d'un appel contre l'obstruction de l'IESG. Celle-ci estimait en effet que le RFC aurait dû utiliser, pour ses exemples, uniquement les noms de domaines du RFC 2606, malgré le fait que le RFC 2821 aie déjà utilisé des noms comme isi.edu (l'université de Jon Postel) ou generic.com depuis des années.

Des propositions d'architectures radicalement nouvelles, en général fondées sur un modèle où le récepteur « tire », comme avec Atom, plutôt que sur le modèle traditionnel du courrier où l'expéditeur « pousse » ont déjà été faites, par exemple par Dan Bernstein ou par Wietse Venema mais n'ont jamais débouché sur des protocoles finalisés, et encore moins sur des implémentations. Ces propositions visent en général à traiter le problème du spam en forçant l'expéditeur à garder le message chez lui, jusqu'au moment de la récupération par le destinataire. Cela résoudrait la question du stockage du spam, mais pas du tout celle de son traitement puisqu'il faut bien notifier le destinataire qu'il a un message, et qu'il doit bien le récupérer pour décider si c'est du spam ou pas.


Téléchargez le RFC 5321

Version PDF de cette page (mais vous pouvez aussi imprimer depuis votre navigateur, il y a une feuille de style prévue pour cela)

Source XML de cette page (cette page est distribuée sous les termes de la licence GFDL)