Dans cet article nous allons creuser tout de qui concerne la gestion des emails dans les modules prestashop.

Dans un premier temps comment envoyer un email bien sûr, mais nous verrons ensuite qu’il est très facile d’interagir avec les emails systèmes via les hooks.

Ce tutoriel s’applique à la version 1.7 de Prestashop, certains hooks n’existent pas dans la version 1.6  dont le hook hookActionEmailSendBefore , il reste cependant assez facile de les implémenter manuellement en surchargeant la classe Mail

Pour illustrer et tester tout ça nous allons passer par la création d’un module de POC hh_demoemails

L’archive sera disponible en fin d’article, mais je précise bien que c’est un module de démo et d’apprentissage et pas du tout en module destiné à être mis en production 😉

Fonctionnement général

La gestion de l’envoi dans Prestashop est relativement basique car elle est centralisée dans une seule fonction qui est la fonction send de la classe Mail voici ses paramètres, la signature de la fonction est relativement explicite

/**
     * Send Email.
     *
     * @param int $idLang Language ID of the email (to translate the template)
     * @param string $template Template: the name of template not be a var but a string !
     * @param string $subject Subject of the email
     * @param string $templateVars Template variables for the email
     * @param string $to To email
     * @param string $toName To name
     * @param string $from From email
     * @param string $fromName To email
     * @param array $fileAttachment array with three parameters (content, mime and name).
     *                              You can use an array of array to attach multiple files
     * @param bool $mode_smtp SMTP mode (deprecated)
     * @param string $templatePath Template path
     * @param bool $die Die after error
     * @param int $idShop Shop ID
     * @param string $bcc Bcc recipient address. You can use an array of array to send to multiple recipients
     * @param string $replyTo Reply-To recipient address
     * @param string $replyToName Reply-To recipient name
     *
     * @return bool|int Whether sending was successful. If not at all, false, otherwise amount of recipients succeeded.
     */
    public static function send(
        $idLang,
        $template,
        $subject,
        $templateVars,
        $to,
        $toName = null,
        $from = null,
        $fromName = null,
        $fileAttachment = null,
        $mode_smtp = null,
        $templatePath = _PS_MAIL_DIR_,
        $die = false,
        $idShop = null,
        $bcc = null,
        $replyTo = null,
        $replyToName = null
    ) {
 //Code de la fonction
}

Les templates des emails systèmes par défaut sont situés dans le dossier /mails/ à la racine de prestashop et rangé ensuite par code langue ( fr/ en )

Dans le cas ou voulez changer le contenu d’un email pour juste changer un texte, il ne faut surtout pas modifier ces emails de la racine , mais il n’est pas nécessaire de passer par un module

Le plus simple est tout simplement de copier les fichiers .html et .txt du modèle souhaité dans le dossier mails du thème.

Par exemple si vous souhaitez changer le contenu de l’email de paiement par chèque en français et que votre thème utilisé est classic
Il faut copier les fichiers :

  • mails/fr/cheque.html vers /themes/classic/mails/fr/cheque.html
  • mails/fr/cheque.txt vers /themes/classic/mails/fr/cheque.txt

C’est également possible si vous souhaitez changer des éléments sur l’email d’un autre module 
Par exemple pour modifier l’email de notification de nouvelle commande du module ps_emailalerts
Il faut copier les fichiers :

  • modules/ps_emailalerts/mails/fr/new_order.html vers themes/classic/modules/ps_mailalerts/mails/fr/new_order.html
  • modules/ps_emailalerts/mails/fr/new_order.txt vers themes/classic/modules/ps_mailalerts/mails/fr/new_order.txt

Envoyer un email depuis un module

Créer un dossier mails ainsi qu’un dossier avec les codes langues de votre site.
Pour l’illustration on va uniquement créer un dossier fr , il suffira de procéder de la même manière pour les autres langues.

Pour chaque email il faut créer un fichier .html et un fichier.txt. Pour notre premier email nous allons lui donner le code demo

Voici le code nécessaire pour envoyer cet email de démo dans notre module
Vous trouverez également ces informations dans la documentation officielle : https://devdocs.prestashop.com/1.7/development/mail/

        //Variable de l'email, par convention la clé est sous la forme {variable}
        $emailsVars = [
            '{variable1}' => 'Contenu variable 1',
            '{variable2}' => 'Contenu variable 2'
        ];
 
        Mail::send(
            $this->context->language->id, //Identifiant de langue
            'demo', //Code du template ( nom du fichier sans extension) Attention il faut créer un fichier html et txt de chaque template
            $this->l(' Module Installation',false,$this->context->language->locale), // Sujet de l'email ( on peut forcer la traduction dans une locale souhaitée)
            $emailsVars,//Variables de l'email
            '[email protected]', // Email de l'adresse
            NULL, //receiver name
            NULL, //from email address
            NULL,  //from name
            NULL, //file attachment
            NULL, //mode smtp
            _PS_MODULE_DIR_.'hh_demoemails/mails' //La ligne importante est ici ( chemin du dossier mail de votre module )
        );

Interagir avec les emails système

La partie la plus intéressante commence maintenant, car via un module il est possible également de changer tout et n’importe quoi dans les emails systèmes, et cela sans réaliser aucune surcharge.

En utilisant tout simplement les hooks suivants :

  • actionEmailSendBefore
  • sendMailAlterTemplateVars
  • actionEmailAddBeforeContent
  • actionEmailAddAfterContent
  • actionGetExtraMailTemplateVars
  • actionMailAlterMessageBeforeSend

Nous allons voir ensemble à quoi ils peuvent servir et les illustrer avec un ou plusieurs cas d’usages

Pour récupérer les codes des templates emails, faut vous rendre dans le dossier mails/fr/ ( ou /en/ ) , le nom des templates correspond aux nom des fichiers sans extension.
Ex : account.html => account

sendMailAlterTemplateVars

Ce hook permets de modifier les valeurs données initialement aux variables de l’email.

Un exemple d’utilisation peut être par exemple de remplacer le prénom de l’ utilisateur qui s’inscrit par « Jean Michel » et son nom de famille par « A peu près » dans l’email de confirmation d’inscription.

Tous vos utilisateurs s’appelleront donc Jean Michel A peu près ( dans les emails uniquement ) 😀

/**
     * Cette fonction permets de modifier spécifiques des variables de l'email
     * @param array $params
     *  [
     *    'template' => 'nom_du_template',
     *    'template_vars' => &[//tableau des variables de l'email]
     *  ]
     */
    public function hookSendMailAlterTemplateVars($params)
    {
        //Conditionnement du template
        if ( $params['template'] == 'account') {
            //Pour connaitre les variables définies regarder l'email source Ou faire un dump( de $params['template_vars'] )
         //Les variables étant passées par références il est inutile de faire un return spécifique dans la fonction pour modifier leur valeur
            $params['template_vars']['{firstname}'] = 'Jean Michel';
            $params['template_vars']['{lastname}'] = ' A peu près';
        }
    }

actionEmailAddBeforeContent

Ce hook permet de definir du contenu avant l’affichage du template html appellé.
Nativement son intérêt est assez restreint car les templates contiennent déjà les entêtes html, ajouter du contenu avant sera donc problématique.

En revanche cela peut être utile dans le cas ou vous souhaitez mutualiser le fichier d’entête entre tous les fichiers , pour les exemples vous pouvez voir l’article suivant : https://www.h-hennes.fr/blog/2019/05/23/prestashop-simplification-de-la-mise-en-page-des-emails/

actionEmailAddAfterContent

Ce hook permet de definir du contenu après l’affichage du template html appellé.
Nativement son intérêt est assez restreint pour ajouter du contenu car les templates contiennent déjà la fin des balises html, ajouter du contenu après ne sera donc pas pris en compte.

Cela reste être utile dans le cas ou vous souhaitez mutualiser le fichier de pied de page entre tous les fichiers , pour les exemples vous pouvez voir l’article suivant : https://www.h-hennes.fr/blog/2019/05/23/prestashop-simplification-de-la-mise-en-page-des-emails/

Sinon ce hook comme vous avez accès au contenu généré il est possible de modifier ou de supprimer du contenu du template initial.

Pour l’exemple on va supprimer la variable {shop_name} de l’email de contact.
Un autre cas d’utilisation plus concret serait supprimer la mention « Powered by prestashop » situé dans le pied de page de tous les emails ( sans avoir a éditer les templates 🙂 )

/**
     * Hook appellé APRES la récupération du contenu du template de l'email
     * @param array $params [
     * 'template' => $template,
     * 'template_html' => &$templateHtml,
     * 'template_txt' => &$templateTxt,
     * 'id_lang' => (int) $idLang,
     * ]
     */
    public function hookActionEmailAddAfterContent($params)
    {
        //Pour l'exemple ici on va supprimer la variable {shop_name} du contenu de l'email de contact
        if ( $params['template'] == 'contact'){
            $params['template_html'] = str_replace('{shop_name}','',$params['template_html']);
            $params['template_txt'] = str_replace('{shop_name}','',$params['template_txt']);
        }
    }

actionGetExtraMailTemplateVar

Ce hook permets de définir des nouvelles variables dans un template email existant.
L’inconvénient est qu’il faut modifier le template source pour ajouter les placeholder de vos variables
Pour la démo on va rajouter 2 variables dans l’email de contact
{date_envoi} et une {module_modification}

/**
     * Ce hook permets d'ajouter des nouvelles variables à un email existant
     * L'inconvénient est qu'il faut modifier le template source pour ajouter les placeholder de vos variables
     *
     * [
     * 'template' => $template,
     * 'template_vars' => $templateVars,
     * 'extra_template_vars' => &$extraTemplateVars,
     * 'id_lang' => (int) $idLang,
     * ],
     *
     * @param array $params
     */
    public function hookActionGetExtraMailTemplateVars($params)
    {
        //Ajout de variables personnalisées dans l'email de contact
        if ( $params['template'] == 'contact')
        {
            //Les variables sont passés par références, pas besoin de passer de return
            $params['extra_template_vars']['{date_envoi}'] = date('Y-m-d H:i:s');
            $params['extra_template_vars']['{module_modification}'] = $this->name;
        }
    }

actionMailAlterMessageBeforeSend

Ce hook renvoie une instance de Swift_Message sur laquelle vous pouvez intervenir.
De mon côté je n’ai pas (encore) trouvé d’utilité à ce hook.

/**
     * @param array $params
     * [
     * 'message' => &$message, //Instance de Swift_Message
     * ]
     */
    public function hookActionMailAlterMessageBeforeSend($params)
    {
        //Permets de jouer avec l'objet Swift_Message
        // De mon côté je n'ai pas eut l'utilisé de ce hook
    }

actionEmailSendBefore

Pour finir c’est le hook le plus intéressant, puisqu’il permets de faire énormément de choses au niveau de l’email, je réfléchi peut être à faire un article spécifique à ce hook.
Voici entre autre ce qu’il est possible de faire :

  • bloquer l’envoi de l’email
  • changer le template utilisé par l’email
  • changer le sujet de l’email
  • changer le destinataire de l’email
  • changer l’expéditeur de l’email
  • ajouter des emails en copie de l’email
  • ajouter des variables à l’email
  • ajouter des pièces jointes à l’email
  • ….

Pour illustrer mon propos nous allons partir sur les exemples suivant :

  • Ne pas envoyer d’email de contact si l’email est [email protected]
    • Dans le cas ou le destinataire est une adresse email spécifique « [email protected] », faire les modifications ci-dessous
    • changer le sujet de l’email par « Custom contact subject »
    • remplacer le nom de l’expéditeur par « Test Expéditeur »
    • rajouter une variable « {date_envoi} »
    • rajouter l’adresse « [email protected] » en bcc
  • Envoyer un pièce jointe supplémentaire sur avec l’email de confirmation de commande
/**
     * Excécuté AVANT l'envoi d'un emails
     * @param array $params [
     * 'idLang' => &$idLang,
     * 'template' => &$template,
     * 'subject' => &$subject,
     * 'templateVars' => &$templateVars,
     * 'to' => &$to,
     * 'toName' => &$toName,
     * 'from' => &$from,
     * 'fromName' => &$fromName,
     * 'fileAttachment' => &$fileAttachment,
     * 'mode_smtp' => &$mode_smtp,
     * 'templatePath' => &$templatePath,
     * 'die' => &$die,
     * 'idShop' => &$idShop,
     * 'bcc' => &$bcc,
     * 'replyTo' => &$replyTo,
     * ]
     */
    public function hookActionEmailSendBefore($params)
    {
 
         /**
         * Actions sur le formulaire de contact
         */
        if ($params['template'] == 'contact') {
 
            if ($params['to'] == '[email protected]') {
                //Sinon on ne veut pas envoyer d'email
                return false;
            }
 
            if ($params['to'] == '[email protected]' ) {
 
                $params['from'] = '[email protected]';
                $params['subject'] = 'Custom contact subject';
                $params['fromName'] = 'Test expéditeur';
                $params['template'] = 'contact_custom';
                $params['templatePath'] = _PS_MODULE_DIR_.$this->name . '/mails/';
                //Ajout d'une variable
                $params['templateVars']['{date_envoi}'] = date('Y-m-d H:i:s');
                //Ajout d'un email en bcc
                $params['bcc'] = ['[email protected]'];
            }
        }
 
        /**
         * Actions sur l'email de configuration de commande
         */
        if( $params['template'] == 'order_conf') {
            //Ex rajout d'un fichier pdf
            $params['fileAttachment'][] = array(
                'content' => file_get_contents(
                    dirname(__FILE__) . '/files/mon-fichier.pdf'
                ),
                'name' => 'mon-fichier.pdf',
                'mime' => 'application/pdf',
            );
        }
 
    }

Nous avons à présent fait le tour des hooks et de modifications possibles dans les emails via les modules, je pense avoir été assez exhaustif mais n’hésitez pas à partager vos problématiques pour enrichir cet article 🙂

Vous pouvez télécharger le module de démo ci-dessous :