Un formulaire de mail sur site statique & Jamstack

Quelles solutions pour envoyer un email à partir d'un formulaire quand on a pas de serveur ?

Habituellement quand on veut envoyer un email à partir d'un formulaire sur son site, il faut avoir un serveur qui va traiter notre formulaire et qui va ensuite envoyer le mail. Par exemple, notre formulaire va pointer vers un script en PHP (ou Node, Python ...) qui appellera la fonction "mail()" pour envoyer notre courrier électronique. Mais comment ça se passe quand on a pas de serveur ? On va voir deux solutions pour y arriver.

Avec Netlify : La solution facile

Avoir un site Jamstack propulsé par Netlify apporte quelques avantages non négligeables. En effet le service propose leur propre système d'envoi de mail et l'intégration est vraiment simple.

En effet il suffit de se faire son petit formulaire à l'ancienne et de rajouter dans la balise "form" la propriété "data-netlify='true'". Rien de plus !

Exemple de formulaire :

<form name="contact" method="POST" data-netlify="true">
    <p><label>Votre e-mail * : <input required type="email" name="email" /></label></p>

    <p><label>Votre message: <textarea required name="message" rows="4"></textarea></label></p>

    <p><button type="submit">Envoyer</button></p>
</form>

Le mail envoyé sera disponible dans la console d'administration Netlify, mais il est possible de l'avoir directement dans sa boite mail en ajoutant une "form notification" toujours dans la console d'administration.

Les 100 premiers emails sont gratuits, après il faudra passer à la caisse, mais cela devrait suffire à la plupart des usages personnels.

En ce qui me concerne mon site n'utilise pas Netlify, mais Zeit. J'ai donc du trouver une solution. Comme j'utilise déjà Firebase pour sa base de données Firestore, pourquoi ne pas essayer avec ce service ?

Firebase : Merci ... mais non merci.

Firebase propose, tout comme sur AWS, d'avoir ses propres fonctions en Javascript ou Typescript dans le cloud. Mais comme il ne permet pas d'envoyer des emails nativement il faut passer par un service extérieur comme Sendgrid.

Cela signifie concrêtement qui me mon formulaire va pointer vers une fonction Firebase qui va pointer vers le SMTP de Sendgrid.

Je ne vais pas détailler le procésus car l'aventure s'est arrêtée assez vite. Je me suis retrouvé coincé avec une fonction en locale qui marchait très bien et une fonction en ligne qui me sortait des erreurs de connexion au moment d'envoyer le mail.

Après avoir retourné Stackoverflow deux fois j'ai compris que les connexions sortantes (vers Sendgrid donc) sont bloquées dans la formule gratuite de Firebase. Pour voir ma pauvre fonction de 20 lignes fonctionner il me faudrait débourser 25$ par moi. Sérieusement ?

Après avoir respiré un bon coup je me suis dit que c'était l'occasion d'aller s'essayer à :

AWS : L'usine à gaz

Avec Amazon Web Service il va falloir utiliser plusieurs services :

SES : Simple Email Service pour envoyer des mails

Lambda : Qui permet de créer une fonction dans le langage que l'on souhaite, qui va récupérer les données et envoyer le mail avec SES

IAM : Pour gérer les droits des fonctions

API Gateway : Qui va permettre de créer un point d'accès de l'extérieur vers la lambda

Je vais détailler ici comment se faire sa petite fonction envoi des mails. Je me suis appuyé sur le tuto officiel d'amazon.

Etape 1 : Valider le mail de l'expédieur dans SES

Dans la console AWS on va chercher SES et aller dans "Identity Management" > "Email Addresses". Cliquer sur "Verify new address" et ajouter son adresse email d'envoi. Il faudra la confirmer dans sa messagerie ensuite.

Etape 2 : Créer sa fonction Lambda

Pour cela on cherche le service Lambda dans la console AWS et on clique sur ... hô surprise : "créer une fonction". On lui donne un petit nom "sendMail" par exemple et on part de zéro avec comme choix de langage node.js. Je vous propose le code suivant à copier / coller / modifier dans l'éditeur de code en ligne :

var AWS = require('aws-sdk');
var ses = new AWS.SES();
 
var RECEIVER = 'EMAIL_QUI_ENVOIE@XXXX.XX';
var SENDER = 'EMAIL_QUI_RECOIT@YYYY.YY';

var response = {
 "isBase64Encoded": false,
 "headers": { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': 'example.com'},
 "statusCode": 200,
 "body": "{\"result\": \"Success.\"}"
 };

exports.handler = function (event, context) {
    console.log('Received event:', event);
    sendEmail(event, function (err, data) {
        context.done(err, null);
    });
};
 
function sendEmail (event, done) {
    var params = {
        Destination: {
            ToAddresses: [
                RECEIVER
            ]
        },
        Message: {
            Body: {
                Text: {
                    Data: 'message: ' + event.message + '\nemail: ' + event.email,
                    Charset: 'UTF-8'
                }
            },
            Subject: {
                Data: 'Email de mon site : ' + event.email,
                Charset: 'UTF-8'
            }
        },
        Source: SENDER
    };
    ses.sendEmail(params, done);
}

Maintenant il va falloir autoriser notre fonction à utiliser SES (par défaut ça n'est pas le cas et vous allez tomber sur une erreur si vous essayez de passer cette étape). Pour cela, à partir de l'éditeur de ma fonction, il va falloir aller dans "autorisations" > "Gérer ces autorisations sur la console IAM" . C'est écrit en tout petit et galère à trouver.

Ajoutez le code JSON suivant :

{ 
    "Version": "2012-10-17","Statement": 
    [ 
        { 
            "Effect": "Allow",
            "Action": [ 
                "ses:SendEmail", 
                "ses:SendRawEmail" 
            ],
            "Resource": "*" 
        }
    ] 
}

On peut alors enfin tester notre lambda en cliquant sur "tester". La console nous demandera un jeu de valeur. Par exemple :

{
    "email" : "Email@email.fr",
    "message" : "Hello world"
}

C'est presque terminé :)

Etape 3 : Créer un point d'entrée avec API Gateway

Nous avons notre lambda prête à faire le job mais maintenant comment l’appeler ? C'est là qu'API Gateway entre en jeu.
Tout d'abord il faut chercher le service dans la console AWS et ouvrir le bousin.

Maintenant Il va falloir se créer notre API par exemple "contactMail" en cliquant sur "Créer une API" puis choisir "API REST".
On va ajouter une méthode en cliquant sur le bouton "Actions". Ici ce sera la méthode "POST" et il va ensuite falloir saisir le nom de sa lambda dans le champ "fonction Lambda".

Dernière étape : la publication de notre API. Pour cela cliquez sur "POST", puis sur "ACTIONS" > "Déployer l'API". Il va falloir entrer une étape de déploiement. Choisissez "Nouvelle étape" dans le menu déroulant et lui donner le nom "prod" par exemple. Le chemin de notre API apparaîtra alors et sera prêt à être utilisé dans Postman ou dans code javascript de votre formulaire de mail.

Je ne vais pas détailler comment réaliser le formulaire en Javascript car cela dépendra si vous utilisez de JQuery, Vue, React ... Dans mon cas j'ai utilisé Vue.js, qui envoie les données à ma Lambda avec Axios, une librairie qui permet de faire des appels HTTP.

Au final l'approche AWS est plus difficile à mettre en oeuvre que celle de Netlify, mais la création de cette Lambda toute simple permet de tremper un doigt de pied dans l'océan de services AWS. C'est une entrée en douceur avant de se mettre à coder des trucs bien plus foufous. Pour moi l'avenir est dans le Cloud, alors autant s'y mettre dès maintenant non ?