Académique Documents
Professionnel Documents
Culture Documents
com/informatique/tutoriels/e-mail-envoyer-un-e-mail-
en-php)
Vous me direz : rien de plus simple ! J'utilise la fonction mail() et je lui donne le destinataire, le
sujet, le contenu du courriel.
Alors oui, ça peut fonctionner, mais le gros problème est que, lorsque l'on utilise cette
méthode, l'e-mail a 95 % de chances de partir dans les courriers indésirables... Ce qui n'est pas
vraiment très bon pour l'expéditeur.
C'est pourquoi ce tutoriel va non seulement vous apprendre à envoyer un courriel qui arrivera
(presque toujours) à son destinataire, mais aussi à envoyer un e-mail en HTML et même y
ajouter une pièce jointe. ;) Eh oui, comme les annonces de publicité que vous recevez, ou
encore les courriels du Site du Zéro (e-mails d'avertissement de messages privés ou la
Newsletter).
Avant-propos
Pour commencer ce tutoriel, il faut tout d'abord fixer une chose : tous les serveurs qui reçoivent les e-
mails ne suivent pas obligatoirement la norme, comme je viens d'en avoir la confirmation à la suite
de la dernière édition de ce tuto. En e!et, selon la norme que je cite quelques paragraphes plus loin,
un passage à la ligne dans le code source d'un e-mail est « » ; or, certains hébergeurs remplacent le « »
automatiquement par « », ce qui fait que l'on se retrouve avec « », qui occasionne certains bogues au
niveau de l'a!ichage des e-mails.
:
Il existe donc deux possibilités soit on tente de filtrer les serveurs à problèmes et donc de respecter le
plus souvent la norme, soit on décide de mêttre un peut la norme de coté et l'on utilise « » qui
marche de toutes façons, au cas ou vous voudriez gérer au cas par cas, voici un petit bout de code.
<?php
if (!preg_match("#^[a-z0-9._-]+@(hotmail|live|msn).[a-z]{2,4}$#", $mail))
{
$passage_ligne = "\r\n";
}
else
{
$passage_ligne = "\n";
}
?>
L'en-tête
Définition
L'en-tête d'un e-mail, aussi appelé header, est la partie qui se trouve au début d'un courriel. Elle est
invisible pour l'utilisateur lambda qui ne fait que lire ses messages.
Dans ce tutoriel, j'utiliserai le mot anglais header lorsque je parlerai de l'en-tête car, comme
vous le savez certainement, le langage informatique utilise pour ainsi dire toujours la langue
anglaise ; il sera donc plus facile de se servir de ce terme dans le cours, car il sera réutilisé dans
le code.
Le header, donc, contient toutes les informations de l'e-mail. En voici quelques exemples :
l'heure d'envoi,
l'adresse de réponse,
etc.
Eh, mais tu viens de nous dire que le header, nous, on ne le voyait pas ! Mais moi, je sais très
bien à quelle heure mon e-mail a été envoyé et qui me l'a envoyé !
:
Alors certes, l'utilisateur lambda voit certaines de ces informations, mais c'est uniquement parce que
votre logiciel de messagerie va lire le header pour ensuite vous l'a!icher de manière propre.
Schéma
Lorsque vous créez le header pour envoyer un e-mail avec la fonction mail() de PHP, vous avez besoin
de spécifier quatre arguments :
l'adresse de l'expéditeur,
l'adresse de retour,
la version de MIME,
le content-type du message.
Bon, maintenant, éclaircissons un peu cette liste. Les deux premiers arguments n'ont pas besoin
d'explication (ou bien alors vous êtes en-dessous de zéro :p ).
Pour ce qui est de la version du MIME, il s'agit de donner la version de l'e-mail au serveur qui va le
recevoir. En gros, ça permet de lui dire comment le lire. :)
Si vous voulez plus de renseignements sur le standard MIME, voici un lien : CCM
(http://www.commentcamarche.net/courrier-electronique/mime.php3).
Pour le content-type, vous l'avez peut-être déjà rencontré. Il va servir dans le cas présent à définir ce
que va contenir votre e-mail. Sachez qu'il peut aussi être utilisé en HTML pour définir le contenu
d'une page, ou encore en PHP lors de la génération d'une image avec une bibliothèque graphique
(pour signaler à votre navigateur de quelle façon il va devoir interpréter ce qui se trouve dans la
page). On verra que le content-type va devoir aussi être réutilisé plus tard dans le corps du message.
Ainsi, pour récapituler, nous avons maintenant le schéma d'un header qui ressemble à cela :
expéditeur,
adresse de retour,
MIME,
content-type.
expéditeur,
adresse de retour,
MIME,
content-type.
:
Je vais commencer à écrire du code, à partir de maintenant. Comme je suis en train de traiter
le header, je vais mettre tout ce qui le concerne dans une variable $header.
Déclaration de l'expéditeur
<?php
$header = "From: \"EXPEDITEUR\"<ADRESSE_EXPEDITEUR>".$passage_ligne;
?>
Certains anti-spam se basent sur la concordance entre l'expéditeur qui est présent dans la
balise FROM et le serveur depuis lequel le message est envoyer pour détecter un risque de
fishing (exemple depuis sav@toto.com vous envoyez un mail en tant que sav@titi.com) donc il
vaut mieux coller à 100%
Pour cela si vous etes sur un serveur mutualisée pour avoir l'adresse exacte envoyez vous un
email avec la fonction mail de php avec juste un destinataire, un corps et un sujet peut
importe le contenu vous n'aurez qu'à regarder l'adresse de l'expéditeur pour la mettre à la
place de ADRESSE_EXPEDITEUR
Déclaration du content-type
<?php
$header.= "Content-Type: multipart/alternative;".$passage_ligne." boundary=\"$
boundary\"".$passage_ligne;
?>
Quelques explications
:
Tout d'abord, la valeur de content-type : multipart/alternative.
J'ai choisi d'utiliser celle-ci car mon tutoriel a pour but d'envoyer un e-mail en mode texte et en
mode HTML (je détaillerai ces modes un peu plus tard).
Nous avons aussi la valeur boundary à laquelle j'ai a!ecté $boundary : je suis obligé de déclarer cette
valeur ici, mais je vous expliquerai plus tard le contenu de la variable et son utilité.
Un exemple concret :
<?php
//=====Création du header de l'e-mail
$header = "From: \"WeaponsB\"<weaponsb@mail.fr>".$passage_ligne;
$header .= "Reply-to: \"WeaponsB\" <weaponsb@mail.fr>".$passage_ligne;
$header .= "MIME-Version: 1.0".$passage_ligne;
$header .= "Content-Type: multipart/alternative;".$passage_ligne." boundary=\"
$boundary\"".$passage_ligne;
//==========
?>
1er bilan
Dans cette première partie, nous avons donc appris de quoi était constitué le header d'un e-mail et
comment en créer un à notre convenance. Dans la prochaine partie, nous verrons les di!érents types
de courriels et aussi le code à utiliser pour les déclarer.
Définition
J'imagine que vous avez tous reçu des e-mails au moins une fois dans votre vie. ^^ Vous avez donc eu
la possibilité de constater que certains possèdent de belles images et une belle mise en forme. Par
exemple :
Format Html
Au format HTML
:
Format texte
Au format texte
Tous simplement car selon le client mail qui va lire votre message, il ne sauras pas forcément a!icher
la partie HTML. Par défaut les clients mail tente de convertir l'HTML en texte mais vous voudrez peut-
être a!icher un texte di!érent selon les cas
Comme nous allons envoyer un e-mail en mode texte et en mode HTML, il va nous falloir deux
variables : la première contenant le contenu de l'e-mail en mode texte que l'on appellera
$message_txt, et la seconde, qui contiendra l'e-mail au format HTML, au nom de
$message_html. Mais attention : ces messages devront OBLIGATOIREMENT se terminer par un
.
Content-Transfer-Encoding : XXXXXXXXXX
Si l'on veut traduire cette partie en code PHP, on obtiendra quelque chose comme cela :
<?php
$message = "...";
$message .= "Content-Type: XXX/XXX; charset=\"XXXXXX\"".$passage_ligne;
$message .= "Content-Transfer-Encoding: XXXXXXXXXX".$passage_ligne;
$message .= "...";
?>
Pour information, j'utilise ici une nouvelle variable $message. Cette variable sera envoyée à la
fonction mail() et contiendra l'intégralité du contenu de l'e-mail (texte et code HTML).
Vous aurez aussi remarqué que j'ai ajouté « ... » avant et après ma déclaration de type. C'est
parce qu'en temps normal, il y a autre chose avant et après la déclaration. Je l'aborderai plus
tard dans ce tutoriel.
Quelques explications
Tout d'abord, le content-type (eh oui encore lui, mais je vous avais dit qu'il reviendrait :) ).
Ici, il va servir à dire si l'on veut placer à la suite du texte ou du code HTML.
:
Mode Texte => text/plain
Passons au charset. Il va servir à définir le type d'encodage des caractères qui vont suivre.
J'ai utilisé ici le charsetiso-8859-1 car il est supporté par tous les webmails, contrairement à l'UTF-8.
L'UTF-8 peut être utilisé pour l'envoi d'un e-mail multilingue (chinois, arabe...).
Maintenant, cela va donc dépendre de ce que vous écrivez dans votre courriel. Si vous souhaitez
utiliser des accents, vous devrez obligatoirement régler le Content-Transfer-Encoding sur 8 bits. :)
Ainsi, si nous appliquons ce qui se trouve ci-dessus, on devrait se retrouver, pour une déclaration de
mode HTML, avec ceci :
<?php
$message = "...";
$message .= "Content-Type: text/html; charset=\"ISO-8859-1\"".$passage_ligne;
$message .= "Content-Transfer-Encoding: 8bit".$passage_ligne;
$message .= "...";
?>
2e bilan
Eh bien nous y voilà ! :)
Maintenant, nous savons comment définir ce que nous allons placer dans notre courriel. On avance
sur le chemin de la quête de l'e-mail qui ne part pas à la corbeille. :p Il ne nous reste plus qu'à voir
comment faire la jonction entre les di!érentes parties.
Boundary
Je vais enfin vous expliquer ce que contient la fameuse variable $boundary. :)
Tout d'abord, pour vous donner une idée, boundary se traduit en français par frontière.
Boundary va donc nous permettre de séparer les di!érentes parties de notre e-mail, et c'est
OBLIGATOIRE. On pourrait les considérer comme des super-balises.
----=Chaîne_aléatoire
Pour générer cette chaîne, nous allons utiliser deux fonctions PHP. Tout d'abord, la fonction rand(),
qui permet d'obtenir un nombre aléatoire, puis la fonction md5(), qui permet de hacher une chaîne
(ici, nous hacherons ce que la fonction rand() nous sortira).
Ainsi, si vous avez bien compris ce que je vous ai expliqué, vous devriez avoir écrit un code comme
celui-ci :
<?php
$boundary = "-----=".md5(rand());
?>
Si nous utilisons ces deux méthodes c'est qu'il faut que le texte de la boundary ne soit pas
présent dans notre corps de message sinon ça part droit à la catastrophe
Une boundary étant une frontière, il lui faut donc aussi une fin. Malheureusement, la création de la
boundary comme cela ne pourra pas su!ire pour le corps du message.
Il va falloir ajouter ces caractères devant à chaque fois que vous les utilisez en dehors de la
déclaration qui se situe dans le header.
Citation : caractères
--
--
:
Et voilà qui termine cette partie sur les boundary.
Ouverture boundary.
Déclaration de type (exemple texte).
Texte.
Ouverture boundary.
Déclaration de type (exemple HTML).
HTML.
Fermeture boundary.
Fermeture boundary.
Et voilà ! Je pense que je n'ai plus grand-chose à vous apprendre sur ce sujet. Je vous o!re juste un
dernier exemple de code complet pour que vous puissiez l'analyser.
<?php
$mail = 'weaponsb@mail.fr'; // Déclaration de l'adresse de destination.
if (!preg_match("#^[a-z0-9._-]+@(hotmail|live|msn).[a-z]{2,4}$#", $mail)) // O
n filtre les serveurs qui rencontrent des bogues.
{
$passage_ligne = "\r\n";
}
else
{
$passage_ligne = "\n";
}
//=====Déclaration des messages au format texte et au format HTML.
$message_txt = "Salut à tous, voici un e-mail envoyé par un script PHP.";
$message_html = "<html><head></head><body><b>Salut à tous</b>, voici un e-mail
envoyé par un <i>script PHP</i>.</body></html>";
//==========
//=====Création de la boundary
$boundary = "-----=".md5(rand());
//==========
//=====Définition du sujet.
$sujet = "Hey mon ami !";
//=========
:
//=====Création du header de l'e-mail.
$header = "From: \"WeaponsB\"<weaponsb@mail.fr>".$passage_ligne;
$header.= "Reply-to: \"WeaponsB\" <weaponsb@mail.fr>".$passage_ligne;
$header.= "MIME-Version: 1.0".$passage_ligne;
$header.= "Content-Type: multipart/alternative;".$passage_ligne." boundary=\"$
boundary\"".$passage_ligne;
//==========
//=====Création du message.
$message = $passage_ligne."--".$boundary.$passage_ligne;
//=====Ajout du message au format texte.
$message.= "Content-Type: text/plain; charset=\"ISO-8859-1\"".$passage_ligne;
$message.= "Content-Transfer-Encoding: 8bit".$passage_ligne;
$message.= $passage_ligne.$message_txt.$passage_ligne;
//==========
$message.= $passage_ligne."--".$boundary.$passage_ligne;
//=====Ajout du message au format HTML
$message.= "Content-Type: text/html; charset=\"ISO-8859-1\"".$passage_ligne;
$message.= "Content-Transfer-Encoding: 8bit".$passage_ligne;
$message.= $passage_ligne.$message_html.$passage_ligne;
//==========
$message.= $passage_ligne."--".$boundary."--".$passage_ligne;
$message.= $passage_ligne."--".$boundary."--".$passage_ligne;
//==========
//=====Envoi de l'e-mail.
mail($mail,$sujet,$message,$header);
//==========
?>
Changement de l'en-tête
Bon, comme je vous l'ai déjà expliqué dans les précédentes parties, lorsque l'on souhaite envoyer un
e-mail en texte et en HTML, on doit déclarer dans le header le Content-Type : multipart/alternative.
Ça, c'était pour du texte et du HTML. Pour pouvoir joindre un fichier, cela va changer un petit peu. ;)
En e!et, le Content-Type : multipart/alternative prévient le client qu'il va recevoir du texte et du
HTML, mais pas un ou plusieurs fichiers. Pour cela, on va utiliser le Content-Type : multipart/mixed
qui, lui, prévient juste le client qu'il va recevoir plusieurs parties di!érentes.
:
Maintenant, après les modifications, votre header devrait ressembler à cela :
<?php
//=====Création du header de l'e-mail.
$header = "From: \"WeaponsB\"<weaponsb@mail.fr>".$passage_ligne;
$header .= "Reply-to: \"WeaponsB\" <weaponsb@mail.fr>".$passage_ligne;
$header .= "MIME-Version: 1.0".$passage_ligne;
$header .= "Content-Type: multipart/mixed;".$passage_ligne." boundary=\"$bound
ary\"".$passage_ligne;
//==========
?>
Maintenant, avant d'aller plus loin, il va nous falloir comprendre ce qu'est réellement un fichier.
Citation : Définition d'un fichier
Un fichier est en fait une suite de caractères. Ces caractères sont par la suite
interprétés par le logiciel que vous utilisez pour l'ouvrir.
Je pense que, maintenant, vous avez compris comment nous allons procéder pour joindre un fichier
à un e-mail.
Il va donc nous falloir lire le contenu du fichier pour, par la suite, l'ajouter dans le courriel.
Comme mon tutoriel ne porte pas sur la gestion de fichier en PHP, je vais juste vous donner le code
que j'utilise pour lire les fichiers joints à mes e-mails.
<?php
$fichier = fopen("image.jpg", "r"); //on ouvre le fichier en lecture seul
e.
$attachement = fread($fichier, filesize("image.jpg")); //on lit l'ensemble du
fichier avec la fonction fread.
fclose($fichier); //on ferme le fichier.
?>
Maintenant que nous avons le contenu de notre fichier, nous allons devoir l'encoder en 64 bits.
Pas de problème. Encoder, c'est remplacer un caractère ou une suite de caractères par un ou une
autre. :)
Comment encoder un fichier en 64 bits ? Grâce au PHP, rien de plus simple ! En e!et, il existe une
fonction qui fait ça tout seul. C'est pas beau, ça ?
Il s'agit de la fonction base64_encode(), que l'on va utiliser comme ceci :
:
<?php
$attachement = chunk_split(base64_encode($attachement));
?>
Au passage, vous remarquerez que j'ai également utilisé la fonction chunk_split(), qui sert, lorsqu'elle
n'a pas de second argument, à e!ectuer un retour à la ligne tous les 76 caractères, ce qui permet de
respecter la norme RFC 2045.
Voilà. Maintenant que nous avons notre fichier dans une variable et qu'il est au bon format, on va
pouvoir l'ajouter à notre e-mail.
Pour l'ajouter, on va faire comme lorsque l'on voulait déclarer soit du texte, soit du HTML.
La déclaration se voit quand même quelque peu enrichie. On va devoir maintenant déclarer :
le nom du fichier ;
Le Content-Disposition permet de dire que ce qui suit devra être en fichier joint. Pour cela, on lui
donnera la valeur attachment.
Ce qui, en code, nous donnera :
<?php
$message.= "Content-Disposition: attachment; filename=\"nom_fichier\"".$passag
e_ligne;
?>
Le Content-Type va lui aussi changer. En e!et, rappelez-vous, c'est lui qui détermine à quoi
correspondent les caractères entre les deux boundary. Le problème dans le cas présent, c'est que le
Content-Type dépendra du fichier que vous voulez joindre. :'( Il faudra donc le faire varier en fonction
de l'extension du fichier que vous envoyez. Ces types sont définis par l'IANA. Vous trouverez ici
(http://www.commentcamarche.net/courrier-electronique/mime.php3) une liste non exhaustive des
di!érents types disponibles, avec descriptions.
Comme dans cet exemple, nous allons joindre le fichier image.jpg et nous allons utiliser le Content-
Type:image/jpeg. Lors de la déclaration d'un Content-Type qui sert à joindre un fichier, on doit aussi
déclarer le nom du fichier joint. Au final, nous obtiendrons une déclaration du Content-Type similaire
à celle-ci :
<?php
$message.= "Content-Type: image/jpeg; name=\"nom_fichier\"".$passage_ligne;
?>
Maintenant que nous avons vu les di!érentes étapes, je vous donne la déclaration que vous devriez
avoir obtenue si vous m'avez bien suivi.
:
<?php
$message.= "Content-Type: image/jpeg; name=\"image.jpg\"".$passage_ligne;
$message.= "Content-Transfer-Encoding: base64".$passage_ligne;
$message.= "Content-Disposition: attachment; filename=\"image.jpg\"".$passage_
ligne;
?>
Bon, maintenant, vous pensez que l'on va pouvoir directement envoyer le fichier joint ? Eh bien non.
:p
Évidemment, cela aurait été trop simple. Car si jamais vous essayez d'insérer directement votre
fichier joint dans le courriel, la personne qui va le recevoir aura un e-mail avec ce schéma :
e-mail en texte,
e-mail en HTML,
pièce jointe.
Ouverture boundary.
Déclaration de type (exemple texte).
Texte.
Ouverture boundary.
Déclaration de type (exemple HTML).
HTML.
Fermeture boundary.
Fermeture boundary.
<?php
$mail = 'weaponsb@mail.fr'; // Déclaration de l'adresse de destination.
if (!preg_match("#^[a-z0-9._-]+@(hotmail|live|msn).[a-z]{2,4}$#", $mail)) // O
n filtre les serveurs qui présentent des bogues.
{
$passage_ligne = "\r\n";
}
else
{
$passage_ligne = "\n";
}
//=====Déclaration des messages au format texte et au format HTML.
$message_txt = "Salut à tous, voici un e-mail envoyé par un script PHP.";
$message_html = "<html><head></head><body><b>Salut à tous</b>, voici un e-mail
envoyé par un <i>script PHP</i>.</body></html>";
//==========
//=====Création de la boundary.
$boundary = "-----=".md5(rand());
$boundary_alt = "-----=".md5(rand());
:
//==========
//=====Définition du sujet.
$sujet = "Hey mon ami !";
//=========
//=====Création du message.
$message = $passage_ligne."--".$boundary.$passage_ligne;
$message.= "Content-Type: multipart/alternative;".$passage_ligne." boundary=\"
$boundary_alt\"".$passage_ligne;
$message.= $passage_ligne."--".$boundary_alt.$passage_ligne;
//=====Ajout du message au format texte.
$message.= "Content-Type: text/plain; charset=\"ISO-8859-1\"".$passage_ligne;
$message.= "Content-Transfer-Encoding: 8bit".$passage_ligne;
$message.= $passage_ligne.$message_txt.$passage_ligne;
//==========
$message.= $passage_ligne."--".$boundary_alt.$passage_ligne;
$message.= $passage_ligne."--".$boundary.$passage_ligne;
//==========
?>
Annexe : FAQ
J'ai décidé de créer cette partie pour y ranger les informations qui ont été distribuées dans les
commentaires, cela permet de tout regrouper clairement.
R : Il vous faut configurer un serveur smtp pour envoyer votre e-mail depuis votre PC en local ; pour
ce faire, il faut éditer le fichier php.ini.
Q : J'ai suivi le tuto, mais mes e-mails tombent toujours dans la corbeille.
R : Malheureusement, il n'y a pas de solution miracle... Certains serveurs électroniques filtrent plus
ou moins...
Maximum 1
Haute 2
Normale 3
:
Basse 4
Minimale 5
Maintenant pour définir la priorité dans l'email il faut ajouter une ligne dans le header :
<?php
//=====Création du header de l'e-mail
$header = "From: \"WeaponsB\"<weaponsb@mail.fr>".$passage_ligne;
$header .= "Reply-to: \"WeaponsB\" <weaponsb@mail.fr>".$passage_ligne;
$header .= "MIME-Version: 1.0".$passage_ligne;
$header .= "X-Priority: 3".$passage_ligne;
$header .= "Content-Type: multipart/alternative;".$passage_ligne." boundary=\"
$boundary\"".$passage_ligne;
//==========
?>
Je pense avoir réussi à vous apprendre comment envoyer correctement un e-mail en PHP. Certaines
personnes me feront peut-être remarquer que je n'ai pas tout traité ! En e!et, mais s'il y a des choses
que je n'ai pas abordées, c'est tout simplement parce que je ne les maîtrise pas encore totalement
(l'inclusion d'une image à l'intérieur d'un e-mail, par exemple). Je préfère donc ne pas en parler du
tout, plutôt que de me risquer à écrire n'importe quoi. :)
: