Page d'accueil Mes articles

Envoyer un mail après la création d'une ressource sur Strapi

Lorsqu'un internaute utilisera le endpoint de création d'un message, Strapi se chargera d'envoyer un email avec son contenu à l'administrateur du site.

Publié en Septembre 2024.

Pour le moment, nous n'avons pas eu besoin d'écrire une ligne de code pour mettre en place Strapi. J'ai été capable dans la première partie de ce parcours de créer un type biographie, venir ensuite définir un contenu textuel ainsi que deux photos, et les récupérer grâce à mon client REST HTTPie.

Mais qu'est-ce qui s'est passé concrètement ? Eh bien, lorsque j'ai créé mon Content Type, Strapi m'a informé au travers d'un message que le serveur devait être redémarré. Si vous faites du Node.js, vous connaissez son fonctionnement. Lorsqu'on démarre un serveur Node, se crée alors une boucle d'événements. Si vous modifiez le contenu d'un fichier, cela n'aura pas d'impact sur le serveur actuellement en route. Si vous souhaitez que sa modification soit prise en compte, vous devez impérativement couper et redémarrer le serveur. Si Strapi m'a informé du redémarrage du serveur, c'est parce que lorsque j'ai ajouté un Content Type, cela a eu pour effet de modifier le code de mon projet.

Si je me rends dans le répertoire src/api, je découvre le nouveau Content Type biography qui a été créé.

❯ cd src/api
❯ tree
.
└── biography
    ├── content-types
    │   └── biography
    │       └── schema.json
    ├── controllers
    │   └── biography.js
    ├── routes
    │   └── biography.js
    └── services
        └── biography.js

7 directories, 4 files

Si vous regardez le fichier schema.json, vous verrez qu'il décrit parfaitement ce que l'on a fait lorsque l'on a créé le Content Type au travers du panel d'administration. Le Content Type n'est donc pas quelque chose qui est stocké en base de données, mais qui fait bien partie intégrante du code de notre application. Je découvre également trois répertoires : Controllers, Routes, Services. Dans chacun de ces répertoires sont présents un fichier biography.js. Comme je le disais dans l'article précédent, je préfère largement coder en TypeScript plutôt qu'en JavaScript. J'aimerais bien faire en sorte que mon projet génère des fichiers TS à la place des fichiers JavaScript. Lorsque l'on a créé le projet, nous avons choisi le Quick Start. Cela a eu pour effet de partir sur une base SQLite, mais également sur du JavaScript sans nous laisser le choix de partir sur du TypeScript. Je choisis donc de recommencer mon projet en partant sur TypeScript et tant qu'à faire en choisissant une base de données Postgres.

Une fois l'installation terminée et mon compte admin créé, je peux découvrir le schéma de base de données utilisé par Strapi. Je découvre notamment que mon utilisateur est stocké dans la table admin_users. Après avoir recréé mon Content Type biography, lorsque j'ouvre mon code sur VS Code, les fichiers ne sont plus des fichiers Javascript mais bien des fichiers Typescript.

Mon but maintenant, c'est de mettre en place une ressource permettant de gérer côté Angular un formulaire de contact. Ce que je souhaite, c'est que les données soient sauvegardées directement sur Strapi, mais qu'en plus un mail soit envoyé à l'administrateur pour lui signaler la réception d'un nouveau message. Mon formulaire va être assez basique. Il va contenir le nom, l'email et le message. Pour ce faire, je vais créer un Content Type de type Collection Type et procéder de la même manière qu'avec le type Biography.

Si vous vous rendez sur la documentation de Strapi, elle est séparée en deux parties. Une partie à destination des développeurs et une partie à destination des utilisateurs. Pour le moment, je vais rester côté utilisateur. Un utilisateur, qui n'est donc potentiellement pas un développeur, peut tout de même faire beaucoup de choses avec Strapi. Un peu comme sur Wordpress au final. Il existe sur Strapi un mécanisme de plugin. Si dans le menu de gauche, vous allez dans "Général" => "Plugins", vous allez voir les plugins installés par défaut sur votre système. On y trouve par exemple le Content Type Builder et le Content Manager que l'on a déjà utilisé lors de la découverte de Strapi. Mais ce qui nous intéresse dans cette étape, c'est le plugin Email.

Si on se rend sur "Settings" => "Email Plugins" => "Configuration", on nous informe que la configuration de ce plugin s'effectue dans le fichier ./config/plugins.js et on nous fournit un lien vers la documentation du plugin. Je pensais éviter d'écrire du code pour configurer l'envoi d'email à la création d'un contact, mais a priori ça ne sera pas le cas.

Sur cette page de la documentation, on nous présente un mécanisme nous permettant de déclencher l'envoi d'email après la création d'une ressource. Ce mécanisme se nomme lifecycle hook. Je crée donc un nouveau fichier et je m'inspire de la documentation src/api/contact/content-types/contact/lifecycles.ts

export default {
    async afterCreate(event) {
        const { result } = event;
        
        try{
            await strapi.plugins['email'].services.email.send({
              to: 'member@monsite.local',
              from: 'contact@monsite.local',
              subject: 'Nouveau message depuis votre site web.',
              text: `
                Nom: ${result.name}
                Email: ${result.email}
                Message:
                ${result.content}
              `,
              html: `
                <dl>
                    <dt>Nom</dt>
                    <dd>${result.name}</dd>
                    <dt>Email</dt>
                    <dd>${result.email}</dd>
                    <dt>Message</dt>
                    <dd>
                        ${result.content}
                    </dd>
                </dl>
            `,
            })
        } catch(err) {
            console.log(err);
        }
    }
}

Lors d'un POST /api/contacts, un email sera envoyé à member@mon-site.local avec le contenu du message envoyé. Pour tester cela, je vais désactiver le fait que le endpoint POST /api/contacts soit réservé aux personnes authentifiées. Pour ce faire, je me rends sur « Settings », « Rôles », je choisis « Public » et j'ajoute la création d'un contact dans le rôle « Public ». De cette manière, je n'ai pas besoin de définir un jeton API pour utiliser ce endpoint.

Je me rends dans mon outil HTTPie pour tester l'envoi de la requête. En méthode POST, j'envoie le payload suivant.

{
  "data": {
    "name": "John",
    "email": "john@doe.io",
    "content": "Je souhaite avoir des informations sur vos services."
  }
}

La ressource est bien créée, mais par contre j'obtiens dans les logs l'erreur suivante

Error: can not connect to any SMTP server

Effectivement, SendMail, le provider par défaut utilisé avec le plugin Email, ne trouve pas de serveur SMTP auquel se connecter. En développement, j'ai tendance à utiliser un outil très intéressant qui s'appelle MailCatcher. Vous pouvez l'installer simplement avec le package manager de Ruby.

❯ sudo gem install mailcatcher
❯ mailcatcher
Starting MailCatcher v0.10.0
==> smtp://127.0.0.1:1025
==> http://127.0.0.1:1080

Le serveur SMTP est automatiquement démarré et vous pouvez accéder à votre webmail sur le port 1080.

Il ne nous reste plus qu'à configurer Strapi pour utiliser notre serveur SMTP local.

export default ({env}) => ({
    email: {
        config: {
          provider: 'sendmail',
          providerOptions: {
            devPort: env('SMTP_PORT', 1025),
            devHost: env('SMTP_HOST', 'localhost'),
          },
        },
      },
});

On redémarre bien le serveur Strapi et si on retente l'envoi d'une ressource sur contact, on reçoit bien l'email créé.

L'email est correctement envoyé sur mon serveur.

Sendmail est parfait pour le développement, mais en production, Strapi vous recommande d'utiliser un provider adapté à votre service de mail. Il en existe plusieurs, comme par exemple strapi-provider-email-mailjet ou strapi-provider-email-sendgrid.

Ce n'était pas compliqué à mettre en place et ça fait plutôt bien le travail. Mais par contre, ce n'est pas satisfaisant pour une production. En effet, je n'ai pas de mécanisme pour éviter le spam sur ce endpoint. Et si je ne mets pas de captcha, cela risque de coûter cher en envoi de mail. Ce sera donc le prochain sujet de ce parcours découverte sur Strapi.

Cet article vous a été utile ? Faites le connaître sur les réseaux sociaux Twitter twitter LinkedIn linkedin

Un commentaire ?

codeur
Ou connectez-vous avec GitHub