Traiter les emails avec php

Publié le 05 avril 2011 par Jbjweb

Nous avons vu comment faire du email piping. Tous les emails pour support@votresite.com sont donc maintenant redirigés vers mailpiping.php. Ce fichier devra donc lire ces emails, éventuellement extraire les pièces jointes, et ensuite appliquer un traitement. Vous déciderez plus tard de ce traitement en fonction de vos besoins, mais cet article vous montrera comment récupérer, lire et décoder les emails.

Si vous n'avez pas encore lu comment rediriger les emails / email piping je vous invite à le faire.

Vous pouvez écrire vous-même votre script de lecture/décodage d’emails, mais pour des raisons pratiques, il est préférable de trouver une classe qui effectue ce travail pour vous, et de préférence une classe facile à utiliser, efficace et largement testée. J’ai cherché pour vous, et Pear ::Mail_mimeDecode(http://pear.php.net/package/Mail_mimeDecode) est la classe qu’il nous faut. Pour ceux qui l’ignorent, PEAR est un dépôt de packages PHP réutilisables recouvrant un grand nombre de besoins quotidiens (au point qu’avant d’écrire une application, vérifiez d’abord si elle n’existe pas déjà dans PEAR). La différence de PEAR avec tous les autres dépôts du genre est que les packages n’y sont admis qu’après avoir été soumis à un contrôle qualité et respectés un certain nombre de normes. PEAR est issu de la communauté PHP elle-même, et on peut donc y trouver une certaine fiabilité.

Installer un package PEAR est très facile lorsqu’on est sur un serveur dédié (ça peut être aussi simple que pear install Mail_mimeDecode en ligne de commande, et c’est tout). Sur un hébergement mutualisé ou un WAMP, ça prend un peu plus de temps, mais pas beaucoup. Vous pouvez consulter les pages suivantes pour savoir comment installer PEAR ::mail_mimeDecode.

http://pear.php.net/manual/en/guide.users.commandline.installing.php

http://php.developpez.com/cours/pear/installation/

http://www.zdnet.fr/builder/programmation/technologies_web/0,39021000,39149250-1,00.htm

http://www.6ma.fr/tuto/installer+pear+avec+wamp-455

http://pear.php.net/manual/en/installation.introduction.php

Une fois mime_Decode installé sur votre serveur, vous l’incluez dans le script avec

1 require_once 'Mail/mimeDecode.php';

Vous récupérez ensuite le contenu de l'email qui a été rerouté vers le script :

1 $fd fopen("php://stdin""r");

2 $email "";

3 while (!feof($fd)) {

4  $email .= fread($fd, 1024);

5 }

6 fclose($fd);

A la première ligne, fopen tente d’ouvrir le flux qu’il reçoit sur son entrée standard (stdin). Ici, c’est le contenu de l’email qui est envoyé vers le flux standard du fichier à travers la redirection. Le deuxième argument, « r », signifie que nous allons ouvrir le flux en lecture seulement.

Nous copions ensuite le contenu du flux, par tranche de 1024 octets dans la variable $email, jusqu’à ce que le flux soit copié intégralement. Nous fermons enfin le flux, puisque nous l’avons désormais copié entièrement dans $email.

1 $decoder new Mail_mimeDecode($email);

Nous allons ensuite passer au décodage de l'email proprement dit avec la classe Mime_mailDecode. On lui passe la variable $mail, contenant le contenu brut de l’email, dans son constructeur (si vous ne savez pas ce qu’est un email brut, ouvrez les propriétés d’un email dans votre client de messagerie préféré, ou faites Ctrl-F3 sur Outlook Express/Windows Mail. Notre objectif est de transformer ce texte assez compliqué (très compliqué lorsqu’il y a une ou plusieurs pièces jointes) en texte et fichier utilisable.

1 $structure $decoder->decode($params);

Nous appelons ensuite la méthode decode() de Mail_mimeDecode, qui effectue le décodage proprement dit et sépare le contenu brut en plusieurs éléments contenus dans une structure (texte normal, texte HTML, pièces jointes). decode() reçoit en paramètres un tableau qui lui indique ce qu’il doit faire avec le texte brut (voir le code au complet à la fin). Ici, include_bodies indique si le corps du mail doit être inclus dans la structure ;decode_bodies indique si le corps du mail doit être décodé, decode_headers indique si les en-têtes du mail doivent être décodés.

1 $subject $structure->headers['subject'];

2 $name $structure->headers['from'];

3 $message $structure->parts['0']->body;

Nous récupérons ensuite les éléments contenus dans $structure dans différentes variables afin de pouvoir les utiliser plus facilement. Tous les éléments du mail sont donc maintenant décodés et répartis dans le tableau$structure.

La première ligne récupère l’objet de l’email, la seconde ligne récupère le champ ‘from’ du message, qui comporte le nom de l’expéditeur et/ou son email ; enfin la troisième récupère le message lui-même, qui est le premier élément du tableau parts (d’où l’index zéro).

Nous avons donc déjà récupéré le sujet, l’expéditeur et le message. Reste à voir si l’email comporte des pièces jointes. C’est le rôle de la partie suivante.

01 foreach ($structure->parts as $part) {

02  // On va sauvegarder si c'est une pièce jointe

03  if (isset($part->disposition) & ($part->disposition=='attachment')) {

04   $file_realname $part->ctype_parameters['name'];

05   $pathinfo pathinfo($part->ctype_parameters['name']);

06   $file_name $file_realname;

07   $fileobject new SplFileObject($file_name'w');

08   $fileobject->fwrite($part->body);

09  }

10 }

Nous excluons d’abord toute autre partie qui ne soit pas une pièce jointe. Nous récupérons ensuite le nom de la pièce jointe, tel que précisé dans l’email brut à la ligne Content-Type et qui est contenu dans le variablectype_parameters[‘name’] de chaque élément du tableau $structure. Nous créons ensuite un objet SplFileObjet. La classe SplFileObjet permet de manipuler les fichiers en mode programmation par objet. Si vous n’avez qu’une vague idée de la POO, cela veut juste dire qu’avec une seule ligne, nous créons ici un nouveau fichier portant le nom $file_name et on annonce à PHP qu’on va tenter d’y écrire quelque chose. Avec la deuxième ligne, nous écrivons concrètement le contenu de la pièce jointe dans le fichier. La pièce jointe sera alors automatiquement enregistrée dans le même dossier le script. Cette opération sera répétée autant de fois qu’il y a de pièces jointes dans l’email.

A la fin, vous aurez donc d’une part le nom de l’expéditeur (ou son email) et l’objet du message dans les variables $from et $subject respectivement, le message dans la variable $message et les pièces jointes éventuelles seront enregistrées dans le dossier.

Le code complet du script : mailpiping.php

Si vous n’avez pas de serveur mail sous la main, vous pouvez quand même tester ce script en remplaçant le flux entrant (stdin) par le nom d’un fichier texte dans lequel vous aurez copié la source d’un email, de préférence avec une ou plusieurs pièces jointes (Ctrl+F3 sur Outlook Express/Windows Live Mail). Enregistrez le fichier dans le même dossier que le script et ensuite modifiez la ligne suivante :

1 $fd fopen("php://stdin""r");

en

1 $fd fopen("fichiercontenantlemail.txt""r");

Lancez ensuite le script, soit depuis le navigateur s’il est accessible sur le Web, ou par l’exécutable PHP s’il ne l’est pas (en ligne de commande, mettez-vous dans le dossier du script et tapez : php mailpiping.php ). Vous verrez ensuite les pièces jointes apparaître dans le même dossier.

Vous pourrez par la suite étendre ce script de plusieurs manières, comme filtrer les pièces jointes en fonction de leur nature, accepter uniquement les emails provenant d’une liste préétablie d’expéditeurs (white list), envoyer une réponse automatique, etc… Votre imagination et vos besoins sont vos limites !