Il arrive parfois de vouloir envoyer un mail en HTML et d’y incorporer des images. Généralement, il suffit de placer l’adresse absolue de l’image dans le tag correspondant. Cependant, il peut être nécessaire de lier l’image dans le mail, pour par exemple pouvoir relire le mail hors connexion.
Les différentes composantes d’un mail
Dans un mail il y a 3 grosses parties :
- Les entêtes qui indiquent ce que contient le mail, qui est le destinataire, qui est l’envoyeur, à qui faut il répondre, ....
- Le corps du message ( qu’il soit en HTML ou en texte simple )
- Les fichiers joins ( images, documents, ...)
Ces trois parties sont séparées par un délimiteur qu’il convient de renseigner dans les entêtes du mail.
Le délimiteur
Il convient d’utiliser une séquence difficile à retrouver dans le reste du mail ( de façon à ne pas confondre une occurrence d’un texte avec le délimiteur ). On va le définir de la façon suivante et récupérer un délimiteur de 32 caractères.
<?php
$delimiteur = '--'.'---='.md5( uniqid( rand() ) );
?>
J’ai du couper les 4 tirets du délimiteur pour contrer les raccourci typographiques de spip :)
Les entêtes
Les entêtes sont importantes, une erreur bien placée pourrait vous donner l’envie de vous arracher les cheveux pendant 2 semaines sans jamais trouver la source de l’erreur.
On va définir le type MIME du message, , le sous type ou la nature du contenu du mail ( présentement « related » [1] ), l’adresse à laquelle répondre et l’envoyeur. On définit également quel sera la séquence du délimiteur servant à départager les différentes informations du mail.
<?php
$headers = "MIME-Version: 1.0\r\n";
$headers .= "Content-Type: multipart/related; boundary=\"$delimiteur\"\r\n";
$headers .= "Reply-to: $from\r\n";
$headers .= "From: $from\r\n";
$headers .= "\r\n";
?>
( ceci est une liste non exhaustive d’entêtes )
Référencer les images dans le mail
Afin d’insérer les images dans le mail, il convient d’assigner à chaque image une référence et indiquer dans le texte la référence. On appellera cette référence le « CID » [2].
On pars du principe que vous avez possédez déjà une liste des images de votre message HTML dans une variable nommée $imgListe( sinon il faudra trouver d’autre moyen comme preg_match_all, ou alors un listing de répertoire si jamais toutes les images de votre mail se retrouve « par chance » dans un même dossier. )
On va donc assigner à chaque image un identifiant nommé "image-*" où * sera remplacé par l’indice du tableau correspondant à cette image, et on remplacera l’occurence de cette image dans le contenu du mail ( symbolisé ici par $content ) par cet identifiant.
<?php
foreach($imgListe as $k => $v){
$content = str_replace($v, 'cid:image'.$k, $content);
}
?>
++++
Renseigner le corps du message
Avant dernière étape : spécifier le corps du message transformé dans la partie précédente. Il est important de spécifier le type mime [3] du contenu ( text/html ) et son encodage.
<?php
$msg = "Content-Type: text/html; charset=\"iso-8859-1\"\r\n";
$msg .= "Content-Transfer-Encoding:8bit\r\n";
$msg .= "\r\n";
$msg .= $content."\r\n";
$msg .= "\r\n";
?>
Attacher les images
Voici la dernière étape avant l’envoi du mail : attacher les images. On considère toujours que vous avez un tableau contenant les noms des images de votre mail. On va donc créer pour chaque item de ce tableau une entrée dans le mail grâce à cete fonction préalablement créée :
<?php
# fonction qui va générer le texte des images du mail
function buildImageContent($file, $key){
$fp = fopen($file, 'r');
$attached = fread($fp, filesize($file));
fclose($fp);
$attached = chunk_split(base64_encode($attached));
$msg = "Content-Type: application/octet-stream; name=\"$file\"\r\n";
$msg .= "Content-Transfer-Encoding: base64\r\n";
$msg .= "Content-ID: <image$key>\r\n";
$msg .= "\r\n";
$msg .= $attached . "\r\n";
$msg .= "\r\n\r\n";
return $msg;
}
?>
Cette fonction récupère le contenu de l’image dans une variable, segmente ce contenu en ligne de 76 octets après l’avoir encoder en MIME base64 ( pour les systèmes qui ne gèrent pas correctement les 8bits ), spécifie quelle est la référence de cette image et indique le contenu de l’image. Il est important de toujours mettre une ligne vide entre des entêtes et le contenu de la partie.
/!\ Ne pas oublier de séparer chaque partie du mail par le délimiteur
++++
Exemple
Une fois cette fonction déclarée, vous pouvez facilement créer le message. Voici le code dans son intégralité :
<?php
# fonction qui va générer le texte des images du mail
function buildImageContent($file, $key){
$fp = fopen($file, 'r');
$attached = fread($fp, filesize($file));
fclose($fp);
$attached = chunk_split(base64_encode($attached));
$msg = "Content-Type: application/octet-stream; name=\"$file\"\r\n";
$msg .= "Content-Transfer-Encoding: base64\r\n";
$msg .= "Content-ID: <image$key>\r\n";
$msg .= "\r\n";
$msg .= $attached . "\r\n";
$msg .= "\r\n\r\n";
return $msg;
}
# On définit le délimiteur
$delimiteur = '--'.'---='.md5( uniqid( rand() ) );
# Le contenu HTML du message, le destinataire, l'envoyeur, et le sujet
$content = 'mon message en html';
$to = 'you@spam.com';
$from = 'me@spam.com';
$subject = 'Happy to be spamed';
# la liste des images du message
$imgListe = array('monImage.gif');
# Les entêtes du mail
$headers = "MIME-Version: 1.0\r\n";
$headers .= "Content-Type: multipart/related; boundary=\"$delimiteur\"\r\n";
$headers .= "Reply-to: $from\r\n";
$headers .= "From: $from\r\n";
$headers .= "\r\n";
# On va transformer le HTML du mail
foreach($imgListe as $k => $v){
$content = str_replace($v, 'cid:image'.$k, $content);
}
# Le contenu du mail avec le HTML transformé
$msg = "Content-Type: text/html; charset=\"iso-8859-1\"\r\n";
$msg .= "Content-Transfer-Encoding:8bit\r\n";
$msg .= "\r\n";
$msg .= $content."\r\n";
$msg .= "\r\n";
# on attache toutes les images du mail
foreach($imgListe as $k => $v){
$msg .= '--'.$delimiteur."\r\n";
$msg . = buildImageContent($v,$k);
}
# Une dernière petite ligne
$msg .= '--'.$delimiteur."\r\n";
# Et on envois le mail
mail($to, $subject, $msg, $headers);
?>