Spécifications

Fonction mail()

Voir aussi

Email avec Zend Framework

6.Le langage PHP

6.22.Envoyer un mail

6.22.4.Mail au format MIME (pour les fichiers joints)

6.22.4.1.Introduction

Nous avons vu comment envoyer un mail au contenu basique: simple texte ou html sans image ni fichier associé. Pour passer à l'étape suivante, il faut des mails composés de différentes parties on parle de mails au format MIME (Multipart Internet Mail Extension).

6.22.4.2.Présentation rapide du format "multi parties"

Ainsi dans un mail qui serait lisible soit en texte, soit en HTML selon le lecteur utilisé, il faut un mail composé d'une partie en simple texte et d'une partie en HTML.
Pour un mail avec plusieurs documents attachés, il faut un mail composé d'une partie en simple texte (ou éventuellement HTML) et plusieurs parties pour les documents (une partie par document).
C'est le principe du format "multipart" (multi parties). La différence par rapport aux cas simples vus précédemment c'est qu'il faut préciser que le mail est au format MIME dans sa version 1.0. Il faut choisir une chaîne de caractères qui servira de délimiteur entre chaque partie du mail. Et enfin, il faut pour chaque partie du mail en préciser le type (text, html, image, etc.).
Le mail ne transportant que du texte, les données binaires (comme les images) devront être codées en ASCII (texte) et le type de codage utilisé (généralement base64) devra être précisé dans l'entête de la partie du mail correspondante.

6.22.4.3.Le format MIME en pratique

Vous en avez assez entendu? Vous avez compris le principe mais ne voulez pas mettre cela en oeuvre à la main... Nous vous invitons à sauter directement au chapitre envoi de mail avec un framework PHP. Pour les plus aventureux, on poursuit ici.
C'est donc dans l'entête du mail (4ème paramètre de la fonction mail) que l'on précise que l'on a affaire à un mail au format MIME dans sa version 1.0 et que son contenu est de type "multipart/mixed" (ou "multipart/alternative" si l'on souhaite un mail qui s'adapte au client mail pour afficher soit une version texte, soit une version html). La chaîne de caractères utilisée comme délimiteur est quant a elle précisée par l'attribut "boundary" (frontière en anglais). Ce qui donne le schéma suivant, restera à compléter $msg:
<?php
//----------------------------------
// Construction de l'entête
//----------------------------------
// On choisi généralement de construire une frontière générée aléatoirement
// comme suit. (le document pourra ainsi etre attaché dans un autre mail
// dans le cas d'un transfert par exemple)
$boundary = "-----=".md5(uniqid(rand()));

// Ici, on construit un entête contenant les informations
// minimales requises.
// Version du format MIME utilisé
$header = "MIME-Version: 1.0\r\n";
// Type de contenu. Ici plusieurs parties de type different "multipart/mixed"
// Avec un frontière définie par $boundary
$header .= "Content-Type: multipart/mixed; boundary=\"$boundary\"\r\n";
$header .= "\r\n";

// Ensuite il faut construire le corps du message
// c'est là que ça se complique
$msg = 'A compléter';

$destinataire = 'testemail@toutestfacile.com';
$expediteur   = 'moi@monsite.com';
$reponse      = $expediteur;
echo "Ce script envoie un mail avec fichier attaché à $expediteur";
mail($destinataire,
      'Fragment de script pour envoi de mail multipart',
      $msg,
      "Reply-to: $reponse\r\nFrom: $expediteur\r\n".$header);
?>

6.22.4.4.Joindre un unique fichier

Exemple de mail avec un fichier attaché. Dans ce script, le fichier image s'appelle 'monfichier.gif' et est situé dans le même répertoire que le script appelé.
<?php

//----------------------------------
// Construction de l'entête
//----------------------------------
// On choisi généralement de construire une frontière générée aléatoirement
// comme suit. (le document pourra ainsi etre attache dans un autre mail
// dans le cas d'un transfert par exemple)
$boundary = "-----=".md5(uniqid(rand()));

// Ici, on construit un entête contenant les informations
// minimales requises.
// Version du format MIME utilisé
$header = "MIME-Version: 1.0\r\n";
// Type de contenu. Ici plusieurs parties de type different "multipart/mixed"
// Avec un frontière définie par $boundary
$header .= "Content-Type: multipart/mixed; boundary=\"$boundary\"\r\n";
$header .= "\r\n";

//--------------------------------------------------
// Construction du message proprement dit
//--------------------------------------------------

// Pour le cas, où le logiciel de mail du destinataire
// n'est pas capable de lire le format MIME de cette version
// Il est de bon ton de l'en informer
// REM: Ce message n'apparaît pas pour les logiciels sachant lire ce format
$msg = "Je vous informe que ceci est un message au format MIME 1.0 multipart/mixed.\r\n";

//---------------------------------
// 1ère partie du message
// Le texte
//---------------------------------
// Chaque partie du message est séparée par une frontière
$msg .= "--$boundary\r\n";

// Et pour chaque partie on en indique le type
$msg .= "Content-Type: text/plain; charset=\"utf-8\"\r\n";
// Et comment il sera codé
$msg .= "Content-Transfer-Encoding:8bit\r\n";
// Il est indispensable d'introduire une ligne vide entre l'entête et le texte
$msg .= "\r\n";
// Enfin, on peut écrire le texte de la 1ère partie
$msg .= "Ceci est un mail avec un fichier joint\r\n";
$msg .= "\r\n";

//---------------------------------
// 2nde partie du message
// Le fichier
//---------------------------------
// Tout d'abord lire le contenu du fichier
$file = 'monfichier.gif';
$fp = fopen($file, 'rb');   // b c'est pour les windowsiens
$attachment = fread($fp, filesize($file));
fclose($fp);

// puis convertir le contenu du fichier en une chaîne de caractères
// certe totalement illisible mais sans caractères exotiques
// et avec des retours à la ligne tout les 76 caractères
// pour être conforme au format RFC 2045
$attachment = chunk_split(base64_encode($attachment));

// Ne pas oublier que chaque partie du message est séparée par une frontière
$msg .= "--$boundary\r\n";
// Et pour chaque partie on en indique le type
$msg .= "Content-Type: image/gif; name=\"$file\"\r\n";
// Et comment il sera codé
$msg .= "Content-Transfer-Encoding: base64\r\n";
// Petit plus pour les fichiers joints
// Il est possible de demander à ce que le fichier
// soit si possible affiché dans le corps du mail
$msg .= "Content-Disposition: inline; filename=\"$file\"\r\n";
// Il est indispensable d'introduire une ligne vide entre l'entête et le texte
$msg .= "\r\n";
// C'est ici que l'on insère le code du fichier lu
$msg .= $attachment . "\r\n";
$msg .= "\r\n\r\n";

// voilà, on indique la fin par une nouvelle frontière
$msg .= "--$boundary--\r\n";

$destinataire = 'testemail@toutestfacile.com';
$expediteur   = 'moi@monsite.com';
$reponse      = $expediteur;
echo "Ce script envoie un mail avec fichier attaché à $expediteur";
mail($destinataire, 'test avec fichier attaché', $msg,
     "Reply-to: $reponse\r\nFrom: $expediteur\r\n".$header);
?>
Ne pas oublier de laisser une ligne entre chaque entête et le message ou fichier. Il suffit de très peu de chose pour que le mail reçu ne soit pas conforme au résultat attendu. Dans cet exemple, nous avons choisi d'afficher l'image dans le corps du mail en utilisant "Content-Disposition: inline". Il aurait également été possible de faire en sorte que l'image soit jointe au mail en tant que fichier à sauvegarder par l'utilisateur en remplacant inline par attachment

6.22.5.Joindre plusieurs fichiers

<?php
//----------------------------------
// Construction de l'entête
//----------------------------------
$boundary = "-----=".md5(uniqid(rand()));

$header  = "MIME-Version: 1.0\r\n";
$header .= "Content-Type: multipart/mixed; boundary=\"$boundary\"\r\n";
$header .= "\r\n";

//--------------------------------------------------
// Construction du message proprement dit
//--------------------------------------------------

$msg = "Je vous informe que ceci est un message au format MIME 1.0 multipart/mixed.\r\n";

//---------------------------------
// 1ère partie du message
// Le texte
//---------------------------------
$msg .= "--$boundary\r\n";
$msg .= "Content-Type: text/plain; charset=\"utf-8\"\r\n";
$msg .= "Content-Transfer-Encoding:8bit\r\n";
$msg .= "\r\n";
$msg .= "Ceci est un mail avec 2 fichiers joints\r\n";
$msg .= "\r\n";

//---------------------------------
// 2nde partie du message
// Le 1er fichier (inline)
//---------------------------------
$file = 'monfichier1.gif';
$fp   = fopen($file, 'rb');   // le b c'est pour les windowsiens
$attachment = fread($fp, filesize($file));
fclose($fp);
$attachment = chunk_split(base64_encode($attachment));

$msg .= "--$boundary\r\n";
$msg .= "Content-Type: image/gif; name=\"$file\"\r\n";
$msg .= "Content-Transfer-Encoding: base64\r\n";
$msg .= "Content-Disposition: inline; filename=\"$file\"\r\n";
$msg .= "\r\n";
$msg .= $attachment . "\r\n";
$msg .= "\r\n\r\n";

//---------------------------------
// 3ème partie du message
// Le 2ème fichier (attachment)
//---------------------------------
$file = 'monfichier2.gif';
$fp = fopen($file, 'rb');
$attachment = fread($fp, filesize($file));
fclose($fp);
$attachment = chunk_split(base64_encode($attachment));

$msg .= "--$boundary\r\n";
$msg .= "Content-Type: image/gif; name=\"$file\"\r\n";
$msg .= "Content-Transfer-Encoding: base64\r\n";
$msg .= "Content-Disposition: attachment; filename=\"$file\"\r\n";
$msg .= "\r\n";
$msg .= $attachment . "\r\n";
$msg .= "\r\n\r\n";

$msg .= "--$boundary--\r\n";

$destinataire = 'testemail@toutestfacile.com';
$expediteur   = 'moi@monsite.com';
$reponse      = $expediteur;
echo "Ce script envoie un mail avec 2 fichiers joints à $destinataire";
mail($destinataire,
     'Email avec 2 fichiers joints (dont 1 inline)',
     $msg,
     "Reply-to: $reponse\r\nFrom: $destinataire\r\n".$header);
?>
L'un de ces fichiers est présenté "inline" et l'autre en "attachment" ce qui vous permet de visualiser la différence. Les clients mails ne tiennent pas tous compte de ce paramètre.

6.22.6.Email HTML avec des images

Cela ressemble à l'envoi d'un mail avec un ou plusieurs fichiers joints. Il suffit simplement d'indiquer que le premier bloc est de type text/html, d'ajouter pour chaque fichier joint un entête Content-ID précisant l'identifiant du fichier dans le mail et de préciser cet identifiant dans les balises <img src="..."> en les faisant précéder de cid:.
<?php
//----------------------------------
// Construction de l'entête
//----------------------------------
$delimiteur = "-----=".md5(uniqid(rand()));

$entete = "MIME-Version: 1.0\r\n";
$entete .= "Content-Type: multipart/related; boundary=\"$delimiteur\"\r\n";
$entete .= "\r\n";

//--------------------------------------------------
// Construction du message proprement dit
//--------------------------------------------------

$msg = "Je vous informe que ceci est un message au format MIME 1.0 multipart/mixed.\r\n";

//---------------------------------
// 1ère partie du message
// Le code HTML
//---------------------------------
$msg .= "--$delimiteur\r\n";
$msg .= "Content-Type: text/html; charset=\"utf-8\"\r\n";
$msg .= "Content-Transfer-Encoding:8bit\r\n";
$msg .= "\r\n";
$msg .= "<html><body><h1>Email HTML avec 2 images</h1>";
$msg .= "Image 1:<img src=\"cid:image1\"><br />";
$msg .= "Image 2:<img src=\"cid:image2\"><br /></body></html>\r\n";
$msg .= "\r\n";

//---------------------------------
// 2nde partie du message
// Le 1er fichier (inline)
//---------------------------------
$fichier = 'monfichier.jpg';
$fp      = fopen($fichier, "rb");
$fichierattache = fread($fp, filesize($fichier));
fclose($fp);
$fichierattache = chunk_split(base64_encode($fichierattache));

$msg .= "--$delimiteur\r\n";
$msg .= "Content-Type: application/octet-stream; name=\"$fichier\"\r\n";
$msg .= "Content-Transfer-Encoding: base64\r\n";
$msg .= "Content-ID: <image1>\r\n";
$msg .= "\r\n";
$msg .= $fichierattache . "\r\n";
$msg .= "\r\n\r\n";

//---------------------------------
// 3ème partie du message
// Le 2ème fichier (attachment)
//---------------------------------
$fichier = 'monfichier2.jpg';
$fp      = fopen($fichier, "rb");
$fichierattache = fread($fp, filesize($fichier));
fclose($fp);
$fichierattache = chunk_split(base64_encode($fichierattache));

$msg .= "--$delimiteur\r\n";
$msg .= "Content-Type: application/octet-stream; name=\"$fichier\"\r\n";
$msg .= "Content-Transfer-Encoding: base64\r\n";
$msg .= "Content-ID: <image2>\r\n";
$msg .= "\r\n";
$msg .= $fichierattache . "\r\n";
$msg .= "\r\n\r\n";

$msg .= "--$delimiteur\r\n";

$destinataire = 'testemail@toutestfacile.com';
$expediteur   = 'moi@monsite.com';
$reponse      = $expediteur;
echo "Ce script envoie un mail au format HTML avec 2 images à $destinataire";
mail($destinataire,
     'Email HTML avec 2 images',
     $msg,
     "Reply-to: $reponse\r\nFrom: $expediteur\r\n".$entete);
?>
Ici vous pouvez apprendre :
Forum PHP
Version imprimable: imprimer