Prestashop : gérer les emails dans vos modules

Ce tutoriel est compatible avec les versions de Prestashop suivantes :
1.6 1.7 1.7.8 8.0 +
Cet article est assez ancien, malgré toute l'attention que j' apporte à mes contenus il est possible que celui-ci ne soit plus d'actualité.
N'hésitez pas à me le signaler si nécessaire via le formulaire de contact.

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.

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

Générer les templates d’email

Pour terminer suite à la remarque de Rémi , je vous précise également qu’il est possible de générer les templates de vos emails en définissant uniquement le contenu via des templates twig.
Je ne détaillerais pas le processus car la documentation officielle est très bien faite sur le sujet : cf. https://devdocs.prestashop.com/1.7/modules/concepts/mail-templates/add-a-layout-from-module/

Télécharger le module de démo

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

21 réflexions sur “Prestashop : gérer les emails dans vos modules”

  1. Bonjour Hervé,

    Une fois de plus vos tutos me sont d’une aide précieuse !

    J’aurai une question un peu particulière : je crée un module qui va envoyer un email. En temps normal, je copie un mail existant (par exemple /mail/fr/account.html) et le modifie à ma sauce. Le problème est que je copie un fichier « généré », donc si je modifie par la suite mes templates de mails globaux, mon mail de module ne sera pas mis à jour.

    Ma question est : est-il possible d’avoir des mails de modules « à générer » ? C’est-à-dire avoir des fichiers .twig (comme dans /mails/themes/modern/core/account.html.twig) qui me permettront une énorme souplesse d’intégration et de mise à jour ?

    J’ai beau chercher dans la doc, les threads github et le code source, je ne trouve rien à ce sujet.
    Je suis sur la version 1.7.7.1.

    Je suis certain qu’on peut arriver à trouver une super-mega solution trop bien 😀

    Rémi

    1. Bonjour Rémi,
      Merci pour le partage de l’information.
      Je n’ai jamais été amené à utiliser cette fonctionnalité pour l’instant.
      Mais j’imagine qu’il serait intéressant de mettre à jour cet article en le prenant en compte !
      Je me note de tester cela prochainement,
      Cordialement,
      Hervé

  2. Bonjour Herve,
    Je débute dans presta et je souhaiterai ajouter un bouton qui lui envoi un email (exemple confirmation de commande ou facture). Cependant cet email sera envoyé à une autre adresse que celle du client exemple sa comptabilité (qui se trouve dans ma base de données). Je ne sais pas si vous pouvez m’aiguiller, dois je créer un module ? et si oui comment dois-je m’y prendre ?

    MErci d’avance de votre réponse

    1. Bonjour Jeremy,
      Dans tous les cas il faudra créer un module.
      Je vous invite déjà à mettre à jour vos connaissances en lisant la documentation officielle qui est relativement complète pour vous donner des bases
      https://devdocs.prestashop.com/1.7/modules/
      Si vous souhaitez envoyer une copie de l’email de commande à une autre adresse que le client, il existe déjà le module natif « mailalerts » qui fait cette action.
      Sinon cet article explique comment jouer avec les modules dans les emails mais il nécessite déjà une certaine compréhension que je ne pourrais pas détailler ici.

      Cordialement,
      Hervé

  3. Bonjour,
    Merci de votre réponse,
    Ce que je souhaite c’est juste que les factures soit envoyer (automatiquement de préférence) à l’adresse mail de la comptabilité de mes clients en cc ou cci mais seulement pour les factures et rien d’autre.
    Je dois donc créer un module si je comprends bien ? ou connaissait vous un module existant pouvant faire cela ?

    Merci,
    Bien cordialement

    1. Bonjour,
      En recherchant rapidement sur addons j’ai trouvé un module qui semble correspondre à vos besoins : https://addons.prestashop.com/fr/comptabilite-facturation/48883-facture-pdf-copie-e-mail.html
      Il sera certainement plus complet qu’un développement personnalisé
      En revanche si vous voulez le faire vous même il faudrait identifier quels statuts entraînent la création de la facturation de votre commande.
      Visible dans la page des statuts de commandes dans le back office.
      Puis utiliser le hook hookActionMailAlterMessageBeforeSend pour rajouter un bcc ou pour même envoyer un email totalement différent.

      Cordialement,
      Hervé

  4. Je viens de découvrir votre blog et vos ressources Prestashop, un régal Merci.

    J’ai peut-être trouvé une utilité au hook actionMailAlterMessageBeforeSend, peut être pourriez-vous me confirmer que je suis sur la bonne voix.

    Il faudrait que j’utilise un paramétrage SMTP différent selon la langue du destinataire. (FR=> smtp sendinblue FR, EN => autre SMTP, etc…).

  5. Bonjour,

    Merci pour tous vos tutos, quand je fais une recherche j’arrive souvent chez vous 🙂
    Aujourd’hui, ce tuto semble correspondre exactement à ma recherche, car je voudrais soit ajouter un message au mail de création de compte, soit déclencher un second mail si le client a coché s’abonner à la newsletter.

    Je suis sur 1.7.6.1, je voudrais tester les exemples, mais je n’arrive pas à comprendre où se placent ces codes ?
    Si je créé un fichier en copiant un exemple de fonction, quel nom faut-il donner au fichier et où le placer ?

    1. Bonjour,

      Ce blog cible avant tout un public technique, c’est pour cela que les « basiques » tels que la création de module ou leur rangement dans Prestashop ne sont pas évoqués.
      Pour autant c’est déjà bien documenté sur la documentation officielle de prestashop (cf. https://devdocs.prestashop.com/1.7/modules/creation/tutorial/ )
      Vous pouvez tout à fait télécharger le module qui est dans l’article et l’adapter à vos besoins, en supprimant ce qui n’est pas nécessaire et en ajoutant vos spécificités.

      Cordialement,
      Hervé

      1. Merci pour cet éclaircissement.
        Je pensais avoir lu l’article en entier mais je n’avais pas vu qu’on pouvait télécharger les fichiers.
        Merci pour votre aide 😉

  6. Bonjour Hervé, super article qui va m’aider en tant que débutant sur prestashop ! J’aurais une question néanmoins.

    Le schéma est le suivant :
    – Le client réalise sa commande et paie
    – Un QR Code est généré et ajouté au mail de confirmation de commande
    – Le client se rend au comptoir du bar, scanne son QR Code
    – Le QR Code pointe vers une action du contrôleur admin qui permettrait de passer la commande comme « terminée »

    Est-ce possible de faire cela ?

    Merci

    1. Bonjour Eliot,

      Sur le principe votre logique semble possible effectivement.
      Concernant la partie QR code je ne connais pas assez leur fonctionnement, mais j’imagine que si vous générez une image que vous insérez dans le mail ça devrait fonctionner.
      Pour la réponse il faudrait mieux pointer vers un controller front si vous ne voulez pas avoir de problèmes d’authentification administrateur.

      Cordialement,
      Hervé

  7. Bonjour Hervé,
    Merci pour cet article très intéressant. J’essaie de m’en inspirer pour résoudre mon problème : Mon client souhaite d’ajouter la facture PDF au mail envoyé par le module ps_emailalerts avec la notification d’une nouvelle commande. J’ai essayé avec le hook hookActionValidateOrder mais je n’arrive pas à avoir la facture jointe au mail. Auriez-vous une piste svp ?
    Bien cordialement
    Ewa

    1. Bonjour Ewa,

      C’est une problématique intéressante et je pense qu’elle est bien traitable via un module spécifique en plusieurs étapes.
      Je n’ai pas de code complet et fonctionnel sous la main mais vous pouvez suivre l’analyse suivante
      En utilisant le hook actionEmailSendBefore et en le conditionnant au template new_order
      Vous pouvez récupérer la référence de la commande depuis la variable {order_name}
      Ce qui vous permets de charger la commande.
      Vous pouvez ensuite vous inspirer de comment est géré l’ajout de la pièce jointe à l’email dans la fonction \OrderHistoryCore::sendEmail pour ajouter votre pièce jointe.

      Et ensuite le fichier pdf pourra bien être joint à l’email concerné.

      Cordialement,
      Hervé

      1. Bonjour Hervé,
        Merci de votre réponse. Je n’ai pas réussi à résoudre mon problème, mais finalement, j’ai trouvé un module qui le fait très bien… Il ne me reste qu’à l’éplucher pour comprendre mes erreurs…
        En tout cas merci beaucoup 🙂

  8. Bonjour,

    Merci pour cet article très complet et utile! J’essaye pour ma part d’envoyer un mail à partir d’un nouveau template custom. Cependant, même en suivant les étapes que vous décrivez et après avoir épluché tous les forums sur le sujet, aucun courriel n’est envoyé et j’ai l’erreur suivante: « Erreur – Le modèle d’e-mail suivant n’existe pas : demo ». Auriez-vous une piste de solution à me suggérer ou auriez-vous rencontré ce problème par le passé? Merci d’avance!

    1. Bonjour,
      Essayez de créer votre modèle email dans un dossier « en » également.
      C’est la langue de fallback par défaut.
      Mais l’erreur en elle même est assez claire, il n’arrive pas à trouver le chemin vers le template que vous avez saisi.

      Cordialement,
      Hervé

      1. Merci de votre réponse.

        L’erreur est, j’en conviens, très claire, mais elle ne m’avance à rien. Ce qui me dérange, c’est le fait que même en reprenant votre démo, je n’arrive à rien. Il ne s’agit donc pas d’un problème de traductions.

        En tous les cas, je vais continuer de chercher et modifier un template existant inutilisé si je n’arrive pas à trouver une solution.

        Au plaisir.

        1. Je n’ai pas dit que c’était un problème de traduction 😉
          En fait l’utilisation du dossier « en » est codée en dur ici : https://github.com/PrestaShop/PrestaShop/blob/develop/classes/Mail.php#L396
          Pour avancer vous pouvez tout à fait jouer avec les lignes autour de celle-ci.
          En regardant par exemple quelle est la valeur renseignée pour $templatePath.
          Et si elle correspond bien au chemin dans lequel vous avez rangé votre email.

          Au passage vous pouvez télécharger en fin d’article le module de démo.
          Lorsque vous l’installez et si vous allez dans la configuration admin, il va envoyer un email.
          Je l’ai testé sur une version 8.0.4 sans problème particulier.

          Cordialement,
          Hervé

Laisser un commentaire

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