Dans cette seconde partie de l'article, je vais m'attarder sur l'intégration des images dans l'email.
Intégrez les images dans le mail en pièce jointe
Lorsque l'on envoie une newsletter en HTML, on insère les images avec une url absolue. Selon les paramètres du lecteur de mail, ces images ne sont pas chargées à l'affichage, mais après une confirmation de l'utilisateur. Rien de dramatique il doit simplement cliquer sur un bouton "Charger les images", mais pour certains clients c'est déjà trop compliqué.
Pour répondre à cela il faut intégrer les images. Nous allons donc les encoder en base64, les intégrer en pièces jointes dans le corps du message et remplacer les url par des identifiants uniques (cid).
La structure du corps du message change légèrement, il y a :
- d'une part la version texte
- d'autre part la version HTML + les images séparés
Ces deux parties principales sont délimitées par un type MIME Content-type: multipart/alternative;
. Les éléments de la partie HTML + image seront eux délimités par un type MIME Content-Type: multipart/related;
.
Il faut donc générer deux séparateurs différents. Pour bien comprendre voici à quoi ressemble visuellement la structure de l'email.
// on crée le séparateur entre la version texte et HTML
$sepAlternative = '-----='.md5(uniqid(mt_rand()));
// on crée le séparateur entre le code HTML et les images
$sepRelated = '-----='.md5(uniqid(mt_rand()));
// cherche les images
preg_match_all('~ ~si', $html, $matches);
$i = 0;
// on utilise la variable $paths pour enregistré le chemin de chaque image et son identifiant attribué
$paths = array();
// boucle à travers les images trouvées
foreach($matches[1] as $img){
$img_old = $img;
// vérifie si l'image est un lien relatif
if(strpos($img, "http://") == false){
$uri = parse_url($img);
$paths[$i]['path'] = $_SERVER['DOCUMENT_ROOT'].$uri['path'];
// génère un identifiant pour l'image
$content_id = md5($img);
// remplace la source de l'image par l'identifiant
// <img src="image.png"> deviendra <img src="cid:9c08925d9cd90b3eca357d3c4c928f89">
$html = str_replace($img_old, 'cid:'.$content_id, $html, $count);
$paths[$i++]['cid'] = $content_id;
}
}
// corps du message
// 1- on commence par un séparateur pour signifier le début des versions alternatives
$msg = "--$sepAlternative\n";
// 2- on affiche des entêtes pour la version texte
$msg .= "Content-Type: text/plain; charset=\"$charset\"\n";
$msg .= "Content-Transfer-Encoding: 8bits\n\n";
// 3- on place la version texte
$msg .= $txt."\n\n";
// 4- on ajoute un séparateur pour signifier la fin d'une version alterntive et le début d'une autre
$msg .= "--$sepAlternative\n";
// 5- on débute la version HTML on signifiant un multipart
$msg .= "Content-Type: multipart/related; boundary=\"$sepRelated\"\n\n";
$msg .= "--$sepRelated\n";
// 6- on affiche des entêtes pour la version HTML
$msg .= "Content-Type: text/html; charset=\"$charset\"\n";
$msg .= "Content-Transfer-Encoding: 8bits\n\n";
// 7- on affiche la version HTML
$msg .= "$html\n\n";
// 8- on affiche un séparateur
$msg .= "--$sepRelated\n";
foreach($paths as $path){
if(file_exists($path['path'])){
$imgType = substr(strrchr($path['path'], '.' ),1);
$file = file_get_contents($path['path']);
$msg_part = "";
// affiche le type MIME de l'image
switch($imgType){
case 'png':
case 'PNG':
$msg_part .= "Content-Type: image/png";
break;
case 'jpg':
case 'jpeg':
case 'JPG':
case 'JPEG':
$msg_part .= "Content-Type: image/jpeg";
break;
case 'gif':
case 'GIF':
$msg_part .= "Content-Type: image/gif";
break;
}
// nom du fichier d'origine
$msg_part .= "; file_name=\"".basename($path['path'])."\"\n";
// Content-ID
$msg_part .= 'Content-ID: <'.$path['cid'].">\n";
// encodage des données. Ici base64
$msg_part .= "Content-Transfer-Encoding: base64\n";
// affich
$msg_part .= "Content-Disposition: inline; filename=\"".basename($path['path'])."\"\n\n";
// encode et affiche l'image. chunk_split permet de générer des lignes de 76 caractères
$msg_part .= chunk_split(base64_encode($file))."\n\n";
// ajoute une séparateur
$msg_part .= "--$sepRelated\n";
$msg .= $msg_part;
}
}
// ajoute les séparateurs finaux
$msg .= "--$sepRelated--\n\n--$sepAlternative--\n";
Conseil pour la version HTML
Les lecteurs de mail ont des moteurs de rendu HTML très différents et généralement obsolètes. Entre les versions d'Outlook, les webmails (gmail, yahoo, zimbra, etc), mail d'Apple, Thunderbird, etc. Chacun gère le code HTML selon ses propres désirs et ses propres bugs. Néanmoins, quelques bonnes pratiques vous permettrons de vous en sortir et d'envoyer un email qui passe à peu près convenablement partout :
- Gérez votre mise en page avec des
table
- Évitez les CSS, tous les logiciels ne les gèrent pas et ceux qui les gère guère mieux que des CSS niveau 1. Donc alors prévoyez une alternative sans
- Pour chaque lien vous devrez redéfinir la couleur avec une balise
<font face="" color="#">
- Utilisez des typos présentes sur l'ordinateur, oubliez GoogleFont. Au mieux le logiciel ignore la balise
link
, au pire il bloque là-dessus et n'affiche rien. - Évitez le javascript (il est bloqué la plupart du temps par sécurité)
- Évitez d'intégrer vos images dans le mail, sauf si vous les optimiser (très) correctement.
- Prenez le temps de tester votre mail sur différents logiciels et webmail.