HomeDevEnvoyer des emails en PHP : le kit de démarrage

Envoyer des emails en PHP : le kit de démarrage

L’envoi d’emails est certainement l’une des utilisations les plus courantes en PHP. Nous allons tout d’abord voir un exemple simple d’envoi, puis, progressivement, nous détaillerons d’autres possibilités.

Envoyer un email

Pour envoyer un email, nous disposons en PHP de la fonction mail(). En voici la syntaxe :

boolean mail( string to, string subject, string message [, string headers [, string parameters]])

Seuls les trois premiers arguments sont obligatoires. La fonction retourne TRUE en cas de succés, FALSE dans le cas contraire.
L’email est envoyé au destinataire to. L’email a pour sujet subject et le corps de l’email est message. Des entêtes supplémentaires peuvent être ajoutés avec headers.

Enfin, des paramètres de commande supplémentaires peuvent être passés avec parametersPHP les utilisera dans son appel du programme d’envoi de courriel.

Voici un exemple basique d’envoi d’un email :

<?php
  mail('adresse@domain.tld', 'Le sujet', 'Exemple d\'envoi d\'email');
?>

Ca y est, vous avez envoyé un email 🙂 c’est bien beau tout ça, mais dans l’email que reçoit le destinataire, l’expéditeur n’a pas été défini…
C’est là que les headers entrent en jeu.

Construction des messages

Nous allons maintenant construire un message un peu plus compliqué et inclure des entêtes à l’email pour améliorer tout ça. Un entête se présente comme suit :

nom de l'entête: contenu de l'entête

Notez bien qu’il n’y a pas d’espace entre le nom de l’entête et les deux points, mais qu’il y a ensuite un espace entre les deux points et le contenu de l’entête. Si vous indiquez plusieurs entêtes, vous devez effectuer un retour à la ligne entre chaque entête à l’aide du caractère spécial \n.

Exemple de construction des headers et du message, puis envoi :

<?php
  $headers  = "From: toto@titi.fr\n";
  $headers .= "Reply-To: toto@free.fr";

  $message  = "Salut Alphonse, \n\n";
  $message .= "J'espère que tu vas bien !\n";
  $message .= "Voila, j'ai découvert un super site :\n";
  $message .= "https://www.phpcodeur.net\n\n";
  $message .= "Va y jeter un oeil, il est terrible !\n\n";
  $message .= "Ciao.\n\n";
  $message .= "toto";

  mail('alphonse@lycos.fr', 'Super site', $message, $headers);
?>

Ici, nous avons utilisé l’entête From qui sert (comme vous l’avez deviné) à définir l’adresse email de l’expéditeur, ainsi que l’entête Reply-To qui, lui, sert à définir l’adresse de réponse à l’email.

Note : Les noms de certains entêtes sont case-sensitive

Note : L’adresse définie comme expéditeur n’a pas besoin d’être réelle. On comprend maintenant comment les spammeurs s’y prennent. Vous ne vous étonnerez plus si vous recevez un email de Bill Gates 😉

Note : L’adresse définie comme expéditeur n’est pas nécessairement la même que celle indiquée pour l’adresse de réponse

Comme on l’a vu, l’opérateur de concaténation (le point devant le caractère =) nous a permis de construire un message un peu plus compliqué. L’ajout des entêtes appropriés nous a permis de définir l’expéditeur, ce qui est la moindre des choses lorsqu’on envoie un email.
Il existe différents entêtes qui ont chacun leur utilité (utilité plus ou moins importante).

Pour voir une liste non-exhaustive des entêtes possibles, rendez vous au chapitre suivant.

Détails des différents entêtes

On l’a vu dans le chapitre précédent, les entêtes nous permettent de fournir de précieuses informations sur l’email. Voici quelques uns des entêtes, et leur utilité :

From
Définit l’adresse de l’expéditeur. Vous pouvez personnaliser cet entête de cette façon : “Petit toto”<toto@titi.fr>
To
Listes des adresses, séparées par une virgule, où doit être envoyée l’email
Reply-To
Définit l’adresse de réponse à l’email, si différente de l’adresse donnée dans l’entête From
X-Priority
Définit le niveau de priorité de l’email. (de 1 à 5)
Return-Path
L’adresse de retour en cas d’erreur (adresse inconnue, etc…). Typiquement, cet entête est ajouté directement par le programme d’envoi de courriel
Cc
Listes des adresses, séparées par une virgule, où doit être envoyée une copie de l’email (Cc signifie Carbon Copy)
Bcc
Listes des adresses, séparées par une virgule, où doit être envoyée une copie cachée de l’email (Bcc signifie Blind Carbon Copy)
Disposition-Notification-To
Adresse définie pour la réception de la confirmation de lecture (active de ce fait la confirmation de lecture)
Content-Type
Utilisé pour définir le type MIME du contenu de l’email ou d’une partie de l’email, et le jeu de caractère utilisé
Content-Transfer-Encoding
Utilisé pour définir l’encodage utilisé pour le contenu de l’email ou une partie de l’email

Voici un autre exemple d’envoi d’email en utilisant quelques uns des entêtes sus-nommés :

<?php
  $headers  = "From: \"toto\"<toto@titi.fr>\n";
  $headers .= "Reply-To: toto@titi.fr\n";
  $headers .= "Cc: alphonse@lycos.fr, georges@usa.com\n";
  $headers .= "Bcc: fred@free.fr\n";
  $headers .= "X-Priority: 1\n";
  $headers .= "Content-Type: text/plain; charset=\"iso-8859-1\"\n";
  $headers .= "Content-Transfer-Encoding: 8bit";

  $subject  = 'Un site à voir absolument !';

  $message  = "Salut à tous, \n\n";
  $message .= "Un site super à voir absolument : \n";
  $message .= "https://www.phpcodeur.net\n\n";
  $message .= "A demain\n\n";
  $message .= "toto";

  $result = mail('francois@wanadoo.fr', $subject, $message, $headers);

  if( $result == true )
  {
      echo 'l\'email a bien été envoyé';
  }
  else
  {
      echo 'l\'email n\'a pas pu être envoyé !';
  }
?>

Dans l’exemple ci-dessus, nous avons envoyé l’email à francois@wanadoo.fr. Nous avons également envoyé une copie de l’email à alphonse@lycos.fr et georges@usa.com (je manque d’inspiration moi…). Une copie cachée a été envoyée à fred@free.fr, et enfin, l’email a une haute priorité.

Nous avons également défini le type MIME du contenu de l’email (text/plain) bien que ce ne fut pas nécessaire, les emails étant par défaut dans ce type.

Emails au format HTML

Dans l’exemple précédent, j’ai utilité l’entête Content-Type pour définir le type MIME de l’email. Réutilisons cet entête en spécifiant cette fois text/html :

<?php
  $headers  = "From: \"toto\"<toto@titi.fr>\n";
  // on indique qu'on a affaire à un email au format html avec l'entête ci-dessous
  $headers .= "Content-Type: text/html; charset=\"iso-8859-1\"";

  $message_html  = "<html><body><b>Salut Alphonse</b><br><br>";
  $message_html .= "Ca va ?<br>";
  $message_html .= "<font color=\"red\">C'était juste pour savoir..</font><br><br>";
  $message_html .= "A plus<br>";
  $message_html .= "<u>toto</u>";

  mail('alphonse@lycos.fr', 'Comment tu vas', $message_html, $headers);
?>

Note : Rappellez vous que certains logiciels de courrier électronique ne gèrent pas les emails au format HTML.

Prévoyons une alternative pour les personnes ne disposant pas d’un logiciel gérant les emails au format HTML, ou qui désactivent pour des raisons de sécurité l’affichage de ces emails.

Nous allons ici aborder le terme de frontières dans le corps de l’email, un moyen de séparer les différentes parties de l’email, en conformité avec le format MIME 1.0.

En d’autres termes, nous allons définir une chaîne de caractères, et l’utiliser pour séparer la partie texte de la partie HTML.
Mais je laisse le code parler pour moi :

<?php
  // on génère une chaîne de caractères aléatoire qui sera utilisée comme frontière
  $boundary = "-----=" . md5( uniqid ( rand() ) );

  $headers  = "From: \"toto\"<toto@titi.fr>\n";
  // on indique qu'on a affaire à un email au format html et texte et
  // on spécifie la frontière (boundary) qui servira à séparer les deux parties
  // ainsi que la version mime
  $headers .= "MIME-Version: 1.0\n";
  $headers .= "Content-Type: multipart/alternative; boundary=\"$boundary\"";

  $message_txt  = "Salut Alphonse\n\n";
  $message_txt .= "Ca va ?\n";
  $message_txt .= "C'était juste pour savoir.\n\n";
  $message_txt .= "A plus\n";
  $message_txt .= "toto";

  $message_html  = "<html><body><b>Salut Alphonse</b><br><br>";
  $message_html .= "Ca va ?<br>";
  $message_html .= "<font color=\"red\">C'était juste pour savoir..</font><br><br>";
  $message_html .= "A plus<br>";
  $message_html .= "<u>toto</u>";

  $message  = "This is a multi-part message in MIME format.\n\n";
  $message .= "--" . $boundary . "\n";
  $message .= "Content-Type: text/plain; charset=\"iso-8859-1\"\n";
  $message .= "Content-Transfer-Encoding: quoted-printable\n\n";
  $message .= $message_txt;
  $message .= "\n\n";
  $message .= "--" . $boundary . "\n";
  $message .= "Content-Type: text/html; charset=\"iso-8859-1\"\n";
  $message .= "Content-Transfer-Encoding: quoted-printable\n\n";
  $message .= $message_html;
  $message .= "\n\n";
  $message .= "--" . $boundary . "--\n";

  mail('alphonse@lycos.fr', 'Comment vas-tu ?', $message, $headers);
?>

Respectez bien la construction du message, en particulier les sauts de ligne entre les différents entêtes et les parties proprement dites.

Voila, le destinataire recevra un email qui s’affichera au format HTML dans son logiciel, si celui ci gère ce format, au format texte dans le cas contraire.

Emails avec pièces jointes

Pour joindre un fichier à votre email, c’est exactement le même principe des frontières que précédemment que nous devons utiliser. Nous allons également utiliser les fonctions de lecture de fichiers pour lire le fichier à joindre.

Les fichiers (image, archive zip, etc…) étant de type binaire, nous allons l’encoder en base64, car seules les données de type ascii peuvent être envoyées par email.

Là encore, je vous laisse étudier le code :

<?php
  // on génère une frontière
  $boundary = '-----=' . md5( uniqid ( rand() ) );

  // on va maintenant lire le fichier et l'encoder
  $path = 'chemin/fichier.gif'; // chemin vers le fichier
  $fp = fopen($path, 'rb');
  $content = fread($fp, filesize($path));
  fclose($fp);
  $content_encode = chunk_split(base64_encode($content));

  $headers  = "From: \"toto\"<toto@titi.fr>\n";
  $headers .= "MIME-Version: 1.0\n";
  $headers .= "Content-Type: multipart/mixed; boundary=\"$boundary\"";

  $message  = "Ceci est un message au format MIME 1.0 multipart/mixed.\n\n";
  $message .= "--" . $boundary . "\n";
  $message .= "Content-Type: text/plain; charset=\"iso-8859-1\"\n";
  $message .= "Content-Transfer-Encoding: 8bit\n\n";
  $message .= "Salut Alphonse, \n\n";
  $message .= "Voila le fichier que tu m'as demandé\n";
  $message .= "\n";
  $message .= "--" . $boundary . "\n";
  $message .= "Content-Type: image/gif; name=\"fichier.gif\"\n";
  $message .= "Content-Transfer-Encoding: base64\n";
  // mettez inline au lieu de attachment
  // pour que l'image s'affiche dans l'email
  $message .= "Content-Disposition: attachment; filename=\"fichier.gif\"\n\n";
  $message .= $content_encode . "\n";
  $message .= "\n\n";
  $message .= "--" . $boundary . "--\n";

  mail('alphonse@lycos.fr', 'le fichier demandé', $message, $headers);
?>

Note : Si vous ne connaissez pas le type MIME du fichier que vous envoyez, vous pouvez indiquer application/octet-stream.

Utiliser des fichiers embarqués dans les emails HTML

Vous avez également la possibilité de joindre un fichier et de l’utiliser directement dans l’email HTML (fichier image, son…). Cela peut permettre de consulter l’email hors ligne, sans que les images ou autres media ne restent invisibles, faute de connexion au réseau.

Cette méthode doit toutefois être utilisée avec parcimonie, le fichier étant joint à l’email, son poids augmente d’autant le poids de l’email et rend plus long le téléchargement de ce dernier.

Pour réaliser cela, nous allons faire appel à un nouvel entête : Content-ID. Celui ci va nous servir à spécifier l’identifiant du fichier, lequel sera utilisé dans la partie html pour indiquer le fichier joint à utiliser.

Voici le code PHP, très proche de l’exemple précédent :

<?php
  // on génère une frontière
  $boundary = '-----=' . md5( uniqid ( rand() ) );
  // on génère un identifiant aléatoire pour le fichier
  $file_id  = md5( uniqid ( rand() ) ) . $_SERVER['SERVER_NAME'];

  // on va maintenant lire le fichier et l'encoder
  $path = 'chemin/fichier.gif'; // chemin vers le fichier
  $fp = fopen($path, 'rb');
  $content = fread($fp, filesize($path));
  fclose($fp);
  $content_encode = chunk_split(base64_encode($content));

  $headers  = "From: \"toto\"<toto@titi.fr>\n";
  $headers .= "MIME-Version: 1.0\n";
  $headers .= "Content-Type: multipart/related; boundary=\"$boundary\"";

  $message  = "Ceci est un message au format MIME 1.0 multipart/mixed.\n\n";
  $message .= "--" . $boundary . "\n";
  $message .= "Content-Type: text/html; charset=\"iso-8859-1\"\n";
  $message .= "Content-Transfer-Encoding: 8bit\n\n";
  $message .= "<html><body>Salut Alphonse, <br><br>";
  $message .= "Voila le fichier que tu m'as demandé :<br>";
  $message .= "<img src=\"cid:$file_id\" alt=\"le fichier demandé\"><br>";
  $message .= "<br>@+";
  $message .= "\n\n";
  $message .= "--" . $boundary . "\n";
  $message .= "Content-Type: image/gif; name=\"fichier.gif\"\n";
  $message .= "Content-Transfer-Encoding: base64\n";
  $message .= "Content-ID: <$file_id>\n\n";
  $message .= $content_encode . "\n";
  $message .= "\n\n";
  $message .= "--" . $boundary . "--\n";

  mail('alphonse@lycos.fr', 'le fichier demandé', $message, $headers);
?>

Nous avons ajouté dans les entêtes de la partie du fichier l’entête Content-ID avec pour valeur l’identifiant aléatoire que nous avons créé. Pour appeller ensuite le fichier, il nous a suffi d’indiquer comme valeur de l’attribut src de la balise img : cid:identifiant_du_fichier

Envoi d’emails à partir d’un serveur local

Cette question revenant assez souvent sur la plupart des forums, je vais la traiter brièvement ici.

Si vous avez essayé d’envoyer un email à partir d’un serveur local, vous avez dù tomber sur un message d’erreur de ce genre :

Failed to connect …

En effet, avant de tenter d’envoyer un email en local, vous devez d’abord configurer correctement le fichier php.ini qui se trouve dans le dossier windows/ (ou winnt, bref, on se comprend).

Vous devez éditer le fichier et vous rendre jusqu’à cette rubrique :

[mail function]
SMTP = localhost ; For Win32 only.
sendmail_from = me@localhost ; For Win32 only.
;sendmail_path =
; For Unix only. You may supply arguments as well (default: "sendmail -t -i")

Indiquez dans SMTP l’adresse du serveur SMTP qui doit être utilisé, par exemple celui de votre fournisseur d’accés, et dans sendmail_from l’adresse de retour par défaut (celle qui sera utilisé dans l’entête Return-Path)

Il est possible que vous ne désiriez pas utiliser le serveur SMTP de votre fournisseur d’accés, dans ce cas, vous pouvez installer un serveur smtp sur votre machine. Il en existe plusieurs gratuits (par exemple, limités à un compte).

Si vous désirez savoir comment installer un serveur SMTP, je vous renvoie sur cet excellent tutoriel de Korben :

Informations complémentaires

La plupart des hébergeurs gratuits suppriment la fonction mail() ou la bride fortement pour prévenir tout abus (spamming). Certains hébergeurs payants font de même (intolérable à mon avis).

Free

Free a supprimé cette fonction de ses serveurs, impossible donc d’envoyer un email avec PHP. Il existe apparamment une solution alternative qui consiste à utiliser un service gratuit de ovh en ouvrant une fenetre sur leur serveur durant trois secondes le temps d’envoyer l’email. (je ne trouve plus le lien, je le mettrai quand je l’aurai retrouvé).

Une dernière solution pour envoyer un email consiste à utiliser les sockets et de parser les reponses du serveur SMTP… Le dialogue avec un serveur via les sockets (voir fsockopen()) sera détaillé dans un prochain article.

Vous pouvez, si vous vous intéressez à la question, télécharger la classe WAmailer, qui propose cette fonctionnalité, et en étudier le code.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.