Posez votre question »

Langages - Envoyer un mail avec pièce jointe

Avril 2015

Les mails, tout comme les pages web, sont livrés avec des en-têtes (headers en anglais).
Ces en-têtes servent à donner quelques détails nécessaires comme l'adresse du destinataire, celle de l'envoyeur, la date de l'envoi, le sujet du mail etc.
Elles sont organisées de cette manière :
Nom_en_tete: valeur\n\r
Nom_en_tete: valeur\n\r
[...]
Nom_en_tete: valeur\n\n\r

Corps du message...

Sachant que "\n" signifie retour à la ligne, et "\r" placement en début de ligne.

C'est en partie en trifouillant dans ces en-têtes que l'on peut envoyer un mail avec pièce jointe par le biais d'un programme.
Les en-têtes spécifient également le type du message : mail en html, mail texte etc.
Pour envoyer un mail avec pièce jointe, il faut lui donner le type multipart/mixed pour signifier qu'on trouvera plusieurs parties dans ce mail (ici, le message principal et la pièce jointe).

Pour séparer ces parties, on utilise ce qu'on appelle une "frontière" (boundary en anglais).
Cette frontière doit être une chaîne de caractères assez unique pour ne pas être retrouvée dans votre message principal.

Prenons par exemple "didondinaditondelosdudosdodudundodudindon" (prenez des caractères acsii de préférence, je ne sais pas comment un client mail réagira avec des caractères évolués).
Pour nos en-têtes, on se contentera de déclarer l'adresse de l'envoyeur, la version de MIME et le type du message et, comme c'est un message avec pièce jointe, il nous faut préciser la frontière :
From: expediteur@domaine.fr\r\n
MIME-Version: 1.0\r\n
Content-Type: multipart/mixed; boundary="didondinaditondelosdudosdodudundodudindon"\r\n\n

(Notez que la fin des en-têtes se caractérise par deux sauts de ligne).
Pour entamer une partie du corps du mail, on va commencer par afficher notre frontière. Lorsqu'une frontière ouvre une partie, elle est précédée de deux tirets :"--". On le terminera avec un saut de ligne :
--didondinaditondelosdudosdodudundodudindon\n

On va dire que le message lisible du mail sera un simple texte. On met donc le type de cette partie (avec le jeu de caractères qui convient, ici le jeu de caractères utilisé par l'alphabet français) :
Content-Type: text/plain; charset=ISO-8859-1\r\n\n

Message principal du mail.\n\n</pre>

La suite va concerner le fichier joint. Pour mettre des données binaires dans un mail, on utilise souvent un standard appelé base 64 qui permet de transformer ces données en caractères.
On va donc rebalancer notre frontière pour délimiter cette partie et préciser dans nos en-têtes :
_ Le type du fichier (on va prendre un fichier doc pour Word)
_ Le type d'encodage du fichier (ici base 64)
_ La disposition du fichier dans le mail (pièce jointe) et son nom.
--didondinaditondelosdudosdodudundodudindon\n
Content-Type: application/msword; name="nom_fichier"\r\n
Content-Transfer-Encoding: base64\r\n
Content-Disposition: attachment; filename="nom_fichier"\r\n\n

À la suite, nous afficherons le contenu de notre fichier encodé en base64.

Et enfin, nous allons fermer notre frontière pour de bon.
Pour fermer une frontière, il faut la faire suivre et précéder de deux tirets "--", soit :
--didondinaditondelosdudosdodudundodudindon--\n


Et vouaala. Le mail n'a plus qu'à être envoyé.
Histoire de concrétiser tout ça, on va implémenter l'envoi de ce mail en Php (pratique avec ses fonctions mail() et base64_encode() toutes prêtes) :
<?php
$boundary='didondinaditondelosdudosdodudundodudindon';
//En-têtes du mail
$headers="From: expediteur@domaine.fr\r\n
MIME-Version: 1.0\r\n
Content-Type: multipart/mixed; boundary=\"$boundary\"\r\n\n";

//Corps du mail en commençant par le message principal
$body="--". $boundary ."\n
Content-Type: text/plain; charset=ISO-8859-1\r\n\n
Message principal du mail.\n\n";

/* Pièce jointe, on va dire que notre fichier s'appelle bidule.doc et qu'il se situe dans le répertoire courant */

$fichier=file_get_contents('./bidule.doc');
/* On utilise aussi chunk_split() qui organisera comme il faut l'encodage fait en base 64 pour se conformer aux standards */
$fichier=chunk_split( base64_encode($fichier) );

//Écriture de la pièce jointe
$body = $body . "--" .$boundary. "\n
Content-Type: application/msword; name=\"nom_fichier\"\r\n
Content-Transfer-Encoding: base64\r\n
Content-Disposition: attachment; filename=\"nom_fichier\"\r\n\n
$fichier";

//Fermeture de la frontière
$body = $body . "--" . $boundary ."--";

//Envoi du mail
mail("destinataire@bidule.fr", "sujet", $body, $headers);
?>

Et vouala :-)

Sources et doc :
_ hochfeiler
_ fr2 (voir exemples dans la discussion)
Pour une lecture illimitée hors ligne, vous avez la possibilité de télécharger gratuitement cet article au format PDF :
Langages-envoyer-un-mail-avec-piece-jointe.pdf

Réalisé sous la direction de , fondateur de CommentCaMarche.net.

A voir également

Dans la même catégorie

Lenguajes - Enviar un email con un archivo adjunto
Par Carlos-vialfa le 15 août 2008
Linguagem: enviar um e-mail com anexo
Par ninha25 le 3 décembre 2009
Publié par kilian. - Dernière mise à jour par christelle.b
Ce document intitulé «  Langages - Envoyer un mail avec pièce jointe  » issu de CommentCaMarche (www.commentcamarche.net) est mis à disposition sous les termes de la licence Creative Commons. Vous pouvez copier, modifier des copies de cette page, dans les conditions fixées par la licence, tant que cette note apparaît clairement.