TUTORIEL PHP 
Conception d'un client de messagerie IMAP (4e partie)
Présentation du standard MIME, permettant le transport de pièces attachées, et décomposition d'un message s'y conformant. (17/10/2005)
Écrire une application de lecture et d'envoi de mails est loin d'être simple, notamment pour placer des éléments au sein du mail, voire simplement de gérer les différents encodages de texte possibles. La tâche serait largement simplifiée si un mail ne contenait que du texte simple, mais ce n'est pas le cas.

Avant de se plonger dans la lecture simple d'un mail et de ses pièces jointes, il nous faut nous pencher sur les différentes possibilités offertes en matière de format.

Description d'un mail
Dans sa forme la plus basique, un mail est composé de différents en-têtes, suivis du corps du message, puis d'un indicateur de fin du message. Un retour à la ligne sépare ces trois composantes. Voici un exemple au plus simple :

To: Youpla Boom (youpla@boom.fr.st)
From: Chapo Pointu (chapo@pointu.kr)
Subject: Ceci n'est pas une pipe.

Si vous lisez ce message, c'est bien.

.


L'affaire se complique singulièrement dès que l'on souhaite sortir des sentiers battus : jeu de caractères exotique, fichiers... Pour cela, on utilise le standard MIME, pour Multipurpose Internet Mail Extensions. Celui-ci rajoute son lot d'en-têtes, précisant la façon d'utiliser le contenu du mail. MIME a été spécialement conçu pour formater les messages utilisant un jeu de caractères autre qu'ASCII. Par extension, il devient possible d'envoyer des documents binaires au sein même des fichiers.

Un message répondant au standard MIME prendra, en version brute, la forme suivante (ou proche) :

Content-Type: multipart/mixed; boundary="----=_Part_14407_10941867.1129284691468"
MIME-Version: 1.0
Date: Mon, 17 Oct 2005 15:40:34 +0200
From: Chapo Pointu (chapo@pointu.kr)
To: Youpla Boom (youpla@boom.fr.st)
Subject: =?ISO-8859-1?Q?=E9bauche?=

This is a multi-part message in MIME format.
Le texte ici est normalement ignoré par les lecteurs qui comprennent les messages à plusieurs parties.

----=_Part_14407_10941867.1129284691468
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

Oh ! Un lapin !

----=_Part_14407_10941867.1129284691468
Content-Type: image/jpeg; name=lapin.jpg
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="lapin.jpg"

/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDABoSExcTEBoXFRcdGxof J0AqJyMjJ084PC9AXVJiYVxS
WllndJR+Z22Mb1laga+CjJmepqemZHy2w7ShwZSjpp// 2wBDARsdHSciJ0wqKkyfalpqn5+fn5+f
n5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+fn5+f n5+fn5+fn5+fn5+fn5+fn5//wAARCAE2AYoDASIA

----=_Part_14407_10941867.1129284691468


.

Les possibilités sont nombreuses, et c'est pourquoi il est délicat de construire un lecteur de mail solide : il faut prendre en compte un grand nombre de possibilités, et savoir tirer les bonnes données du mail brut. Les nombreuses fonctions dédiées de PHP sont pour cela très utiles, mais n'offrent pas de solution clef en main pour traduire un mail en son message et ses différents fichiers liés.

C'est d'ailleurs pour cela qu'ont été créées des bibliothèques assez exhaustives, permettant au développeur perdu d'intégrer rapidement la lecture et l'envoi de mails dans son application : les classiques PEAR::Mail et PEAR::Mail_MIME, mais également PHPMailer, HTML Mime Mail... Certaines sont cependant limitées à l'envoi de mail, plus simple à gérer que la réception.

Les en-têtes d'un mail, et leurs usages
Avant de se plonger dans le code PHP pour extirper la substantifique moelle de tout mail reçu, il convient donc de mieux comprendre la structure d'un message MIME, afin de mieux l'exploiter.
MIME décrit l'ensemble de son contenu par des en-têtes. Dans le cas de documents multiples, chacun est décrit avec l'en-tête idoine. C'est Content-Type qui permet de véritablement définir les contenus, aidé en cela par Content-Transfer-Encoding. Le premier identifie clairement le type du contenu (texte, image, vidéo...), tandis que le second décrit l'encodage de ce contenu. Combinés, ils autorisent la découverte et la bonne gestion des contenus.

Content-Type se retrouve systématiquement dans l'en-tête principal. Il peut prendre toutes les valeurs décrites dans le standard MIME, groupées par type. Ces types sont text, message, image, audio, video, model, application et multipart. Chacune dispose de plusieurs sous-types, comme text/plain, text/css, text/xml, image/gif, audio/mpeg, application/msword, application/xhtml+xml...

Content-Transfer-Encoding, pour sa part, peut prendre les valeurs suivantes : 7bit, 8bit, quoted-printable et base64. L'encodage de texte, de son côté, se fait via l'en-tête Content-Type, avec l'attribut charset, comme présenté dans notre exemple ci-dessus.

Ces en-têtes peuvent se trouver au début du message, auquel cas elles s'appliquent à l'ensemble du message, ou au début d'une partie du message. Elles s'appliquent alors uniquement à cette partie.

Décomposer un message en parties
C'est d'ailleurs là un des avantages de MIME : pouvoir décomposer un message en plusieurs parties indépendantes. C'est ce mécanisme qui permet de mettre dans un message plusieurs types de contenus, textes comme fichiers. Dans le cas d'un message à plusieurs parties, l'en-tête Content-Type placé en début de message, sera du type multipart, et requiert le paramètre boundary. Par exemple :
Content-Type: multipart/alternative;
boundary="----=_Part_14407_10941867.1129284691468"


Ce paramètre boundary représente le délimiteur, qui marche le passage d'une partie à l'autre. Celui-ci se retrouve donc au début de chaque partie, et à la fin du mail :

------=_Part_14407_10941867.1129284691468
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: quoted-printable
Content-Disposition: inline

Texte.

------=_Part_14406_1338276.1129284691468
Content-Type: image/jpeg; name=gonzo.jpg
Content-Transfer-Encoding: base64
Content-Disposition: attachment; filename="gonzo.jpg"

/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDABoSExcTEBoXFRcdGxof J0AqJyMjJ084PC9AXVJiYVxS
WllndJR+Z22Mb1laga+CjJmepqemZHy2w7ShwZSjpp//

------=_Part_14406_1338276.1129284691468


Le séparateur se voit ajouter deux tirets à son début pour chaque usage. Pour son dernier usage, il reçoit également deux tirets à sa fin.
On peut donc facilement décomposer un message en ses différents éléments :

En-têtes
un espace
--séparateur
une partie
--séparateur
une autre partie
--séparateur
encore une partie
--séparateur--


Reste ensuite à les traiter de la manière adéquate.

  Forum

Réagissez dans les forums de JDN Développeurs

Usage des fonctions PHP
Reste donc à faire la correspondance entre ce dont nous disposons (un mail avec des images attachées, par exemple), et ce à quoi nous voulons arriver (un affichage propre de ce mail). Pour cela, PHP offre une pléthore de fonctions, nous permettant de viser et transformer chaque partie du message.

Nombre de fonctions sont ainsi dédiées aux en-têtes (imap_fetchheader(), imap_header(), imap_headerinfo(), imap_headers(), imap_mime_header_decode()), aux encodages ou au corps lui-même. Il convient donc de les discerner et de pouvoir les utiliser correctement.

Nous verrons un usage précis de ces fonctions lors de notre prochain article.
 
Xavier Borderie, JDN Développeurs
 
Accueil | Haut de page
 
 





Quand achetez-vous le plus en ligne ?
Du lundi au vendredi
Le samedi
Le dimanche

Tous les sondages