13.Zend Framework 2 et 3

13.9.Envoyer un e-mail avec Zend Framework 3 et Zend Framework 2

13.9.1.Introduction

Dans le tutoriel sur l'envoi de mail[où?] nous avons pu constater que le principe est très simple (il suffit d'utiliser la fonction mail()) mais la mise en oeuvre peut être rendue complexe, notamment lorsqu'il s'agit de joindre des fichiers, car elle implique de connaître la norme décrivant la structure d'un mail. Afin de s'affranchir de cette difficulté, il vaut mieux faire appel à une bibliothèque telle que Zend Framework 3 ou 2.
Pour commencer vous devrez installer Zend Framework[comment?].
warning Que ce soit avec Zend Framework ou simplement la fonction mail(), le "problème" est le même: pour pouvoir envoyer un mail, vous devez au préalable configurer votre environnement PHP comme précisé dans le chapitre précédent.

13.9.2.Les classes Message() et SendMail()

13.9.2.1.Introduction

Envoyer un e-mail avec ZF3 et ZF2, se fait en deux étapes. Il faut dans un premier temps créer le mail et dans un second temps l'envoyer.
La rédaction du mail se fait via la classe Zend\Mail\Message.
L'envoi du mail se fait via une classe de transport telle que Zend\Mail\Transport\SendMail.

13.9.2.2.Message()

La classe Message s'instancie sans paramètre et il suffit ensuite de faire appel aux fonctions permettant de préciser l'adresse du destinataire, le titre du mail, etc.
Cette classe offre notamment les méthodes suivantes:
  • addFrom($email [,$nom]) permettant de préciser l'adresse email de l'expéditeur éventuellement complété par le nom de l'expéditeur en toutes lettres.
  • addTo($email [,$nom]) permettant d'ajouter un destinataire (son adresse email) éventuellement complété par le nom du destinataire en toutes lettres.
  • addCc($email [,$nom]) permettant d'ajouter un destinataire (son adresse email) en copie éventuellement complété par le nom du destinataire en toutes lettres.
  • addBcc($email [,$nom]) permettant d'ajouter un destinataire (son adresse email) en copie cachée éventuellement complété par le nom du destinataire en toutes lettres.
  • addReplyTo($email [,$nom]) permettant de préciser l'adresse email de retour éventuellement complété par le nom du destinataire en toutes lettres.
  • setSubject($titre) permettant de préciser l'objet du mail.
  • setEncoding($titre) permettant de préciser l'encodage utilisé pour les entêtes (nom d'expéditeur, de destinataire, titre du mail, etc. mais attention par pour le corps du message).
Et enfin la méthode setBody() qui permet de définir le corps du message. Dans son utilisation la plus simple, il suffit de lui passer en paramètre une chaîne de caractères ASCII.
<?php
use Zend\Mail\Message;

$destinataire = 'lui@monsite.fr';
$expediteur = 'moi@monsite.fr';
$expediteurNom = 'Nom de l\'expéditeur en utf-8';
$encodageEntetes = 'utf-8';
$titre = 'Titre du mail créé avec ZF2 et ZF3 (en utf-8)';
$texte = 'Contenu du mail en ASCII';

$msg = new Message();
$msg->addFrom($expediteur, $expediteurNom)
    ->addTo($destinataire)
    ->setEncoding($encodageEntetes)
    ->setSubject($titre);
$msg->setBody($texte);

// Reste à faire l'appel à la classe de transport

13.9.2.3.SendMail()

La classe Sendmail est une des options proposées pour envoyer le message (les variantes étant Smtp, File, InMemory).
Dans le cadre d'un simple envoi mail via sendmail il suffit de faire appel à la méthode send() avec en paramètre le message (instance de Message).
<?php
use Zend\Mail\Transport\Sendmail;

$transport = new Sendmail();
$transport->send($message);
?>

13.9.3.Mail en utf-8

Si l'on souhaite un mail avec un message encodé différemment de l'ASCII (disons en utf-8) il faut manipuler l'entête du message comme dans l'exemple suivant:
<?php
// Au besoin on intègrera ici les instructions nécessaires au chargement de l'autoloader
// Cf. tuto installation de Zend Framework
use Zend\Mail\Message;
use Zend\Mail\Transport\Sendmail;

$destinataire = 'lui@monsite.fr';
$expediteur = 'moi@monsite.fr';
$expediteurNom = 'Nom de l\'expéditeur en utf-8';
$encodageEntetes = 'utf-8';
$titre = 'Titre du mail créé avec ZF2 et ZF3 (en utf-8)';
$texte = 'Contenu du mail en utf-8. Bonne réception!';

$msg = new Message();
$msg->addFrom($expediteur, $expediteurNom)
    ->addTo($destinataire)
    ->setEncoding($encodageEntetes)
    ->setSubject($titre);
$msg->getHeaders()->addHeaderLine('Content-Type','text/plain; charset=utf-8')
    ->setBody($texte);

$transport = new Sendmail();
$transport->send($msg);
?>
rem
  • Pour envoyer un mail html basique (sans image jointe) on appliquera le même principe en remplaçant text/plain par text/html

13.9.4.Mail avec fichier joint

Pour joindre un (ou plusieurs) fichier(s) au mail il faut utiliser la méthode setBody() un peu différemment. On ne passe plus un simple texte mais un object Message de type Mime qui sera composé de plusieurs objets Part de type Mime.
En effet, comme nous l'avons vu dans les chapitres précédents, dès que le contenu d'un mail n'est plus un simple texte (formatté ou pas), on passe à un mail dit "multi-part". Il faut alors définir chaque partie du mail: ici, le texte d'une part et un fichier de l'autre.
Chaque partie se déclare avec la classe Part que l'on pourra instancier par exemple avec une chaîne de caractères ou un pointeur de fichier. Cette classe possède des attributs accessibles en écriture tel que:
  • type, permettant de préciser le type mime de la partie soit à partir des constantes prédéfinies suivantes soit en saisissant directement la chaîne de caractères comme 'image/gif', 'application/pdf', etc.
    • Mime::TYPE_TEXT pour 'text/plain'
    • Mime::TYPE_HTML pour 'text/html'
    • Mime::TYPE_OCTETSTREAM pour 'application/octet-stream' (données binaires)
  • encoding, permettant de préciser le type d'encodage de la partie à partir des constantes prédéfinies suivantes:
    • Mime::ENCODING_8BIT pour '8bit' encodage classique pour simple texte
    • Mime::ENCODING_BASE64 pour 'base64' encodage classique pour les données binaires (fichiers, images)
    • Mime::ENCODING_7BIT pour '7bit' encodage texte pur ASCII
    • Mime::ENCODING_QUOTEDPRINTABLE pour 'quoted-printable'
  • dispositon, permettant de préciser si le fichier attaché doit être proposé dans le corps du message (inline: Mime::DISPOSITION_INLINE) ou en fichier attaché (atttachment: Mime::DISPOSITION_ATTACHMENT)
  • filename, permettant de préciser le nom que l'on doit donner à la pièce jointe
<?php
use Zend\Mail\Message;
use Zend\Mime\Mime;
use Zend\Mime\Message as MimeMessage;
use Zend\Mime\Part as MimePart;
use Zend\Mail\Transport\Sendmail as SendmailTransport;

// Au besoin faire appel à l'autoloader Cf. chapitre installation ZF
// require_once '/chemin/vers/composer/vendor/autoload.php';

$destinataire = 'testemail@toutestfacile.com';
$expediteur   = 'moi@monsite.com';
$reponse      = $expediteur;

$msg = new Message();
$msg->addFrom($destinataire, 'Nom de l\'expéditeur')
        ->addReplyTo($reponse)
        ->addTo($destinataire)
        ->setEncoding('utf-8')
        ->setSubject('test avec fichier attaché (façon ZF2/ZF3)');

$text = new MimePart('Ceci est un mail avec un fichier joint.');
$text->type = Mime::TYPE_TEXT; // text/plain
$text->charset = 'utf-8';

$fichierChemin = 'image.jpg';
$fichierMimePart = new MimePart(fopen($fichierChemin, 'r'));
$fichierMimePart->type = 'image/jpeg';
$fichierMimePart->filename = basename($fichierChemin);
$fichierMimePart->disposition = Mime::DISPOSITION_ATTACHMENT;
$fichierMimePart->encoding    = Mime::ENCODING_BASE64;

$body = new MimeMessage();
$body->setParts(array($text, $fichierMimePart));

$msg->setBody($body);

$transport = new SendmailTransport();
$transport->send($msg);
rem
  • Dans ce cas, l'encodage de la partie texte est précisé via l'attribut charset. Plus besoin d'aller patcher l'entête
  • Pour éviter la confusion entre Zend\Mail\Message et Zend\Mime\Message, ce dernier est rebaptisé MimeMessage
  • Dans cet exemple, le nom de la pièce jointe qui apparaît dans le mail est identique au nom du fichier sur le disque mais vous pouvez préciser un nom différent via l'attribut filename

13.9.5.Mail avec version texte et version HTML

Si vous souhaitez envoyer un mail qui s'affiche soit en simple texte soit en html selon ce que le client mail est capable d'afficher vous devez là aussi créer un mail multipart. Mais ce ne doit plus être un multipart/mixed (comme c'est le cas par défaut) mais multipart/alternative. Il faut donc là aussi patcher l'entête créé par ZF.
<?php
use Zend\Mail\Message;
use Zend\Mime\Mime;
use Zend\Mime\Message as MimeMessage;
use Zend\Mime\Part as MimePart;
use Zend\Mail\Transport\Sendmail as SendmailTransport;

// Au besoin faire appel à l'autoloader Cf. chapitre installation ZF
// require_once '/chemin/vers/composer/vendor/autoload.php';

$destinataire = 'testemail@toutestfacile.com';
$expediteur   = 'moi@monsite.com';
$reponse      = $expediteur;

$msg = new Message();
$msg->addFrom($destinataire, 'Nom de l\'expéditeur')
        ->addReplyTo($reponse)
        ->addTo($destinataire)
        ->setEncoding('utf-8')
        ->setSubject('test avec fichier attaché (façon ZF2/ZF3)');

$texteBody = 'Partie texte du mail';
$texte = new MimePart($texteBody);
$texte->type = Mime::TYPE_TEXT;
$texte->charset = 'utf-8';

$htmlBody = '<html><head></head><body><h1>Mail</h1>En vous souhaitant <b>bonne</b> réception.</body></html>';
$html = new MimePart($htmlBody);
$html->type = Mime::TYPE_HTML;
$html->charset = 'utf-8';

$body = new MimeMessage();
$body->setParts(array($texte, $html));

$msg->setBody($body);
$msg->getHeaders()->get('contenttype')->setType(Mime::MULTIPART_ALTERNATIVE);

$transport = new SendmailTransport();
$transport->send($msg);
?>