Formulaire de contact avec Ajax

Par défaut

Bonjour, voyons ensemble comment créer un formulaire de contact (je sais c’est un classique) avec Ajax, c’est-à-dire sans rechargement de la page.

Dans ce tuto nous verrons notamment comment envoyer des mails à l’aide de la fonction native mail de php, un serveur SMTP et une API (mailgun).

Si vous êtes intéressés uniquement par l’envoi de mail (sans ajax), vous pouvez sauter l’étape 2 et passer directement à l’étape 3.

Étape 1 : Le formulaire

J’utilise bootstrap pour le style, l’objectif c’est d’avoir un formulaire de contact fonctionnel donc ici, comme dirait un de mes étudiants, le css on s’en fout.

<h1 class="text-center">Formulaire de contact avec AJAX</h1>
<main class="container">
    <form id="contact-form" action="contact.php" method="post">
        <aside class="alert d-none">

        </aside>
        <ul class="list-unstyled">
            <li class="form-group">
                <label for="name">Nom</label>
                <input type="text" class="form-control" id="name" name="name">
            </li>
            <li class="form-group">
                <label for="email">Email</label>
                <input type="email" class="form-control" id="email" name="email">
            </li>
            <li class="form-group">
                <label for="subject">Sujet</label>
                <input type="text" class="form-control" id="subject" name="subject">
            </li>
            <li class="form-group">
                <label for="message">Message</label>
                <textarea name="message" id="message" cols="30" rows="10" class="form-control"></textarea>
            </li>
            <li class="form-group">
                <button class="btn btn-primary">Envoyer</button>
            </li>
        </ul>
    </form>
</main>

Les attributs name dans les champs input sont importants car nous allons récupérer les valeurs grâce à eux. Maintenant nous allons mettre en place le code qui gère la soumission du formulaire.

Pour cela il nous faudra charger 2 scripts :

  • La bibliothèque jQuery
  • Le fichier js qui enverra la requête Ajax
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="js/app.js"></script>

Étape 2 : Le JavaScript

'use strict';

$(function () {
    $('#contact-form').submit(function (event) {
        // Annule l'action par défaut (on ne veut pas que la page se recharge)
        event.preventDefault();

        // Envoi de la requête XHR
        $.post($(this).attr('action'), $(this).serializeArray(), function (data) {
            let $aside = $('#contact-form aside');

            // Notifications
            if (data.result) {
                $aside.addClass('alert-success').text('Le message a bien été envoyé !').removeClass('d-none');
            } else {
                $aside.addClass('alert-danger').text('Erreur lors de l\'envoi du message !').removeClass('d-none');
            }
        });
    });
});

Lorsque l’on soumet le formulaire on envoie une requête POST vers le fichier précisé dans l’attribut action du formulaire avec les données saisies par l’utilisateur (récupérées à l’aide de la fonction serializeArray de jQuery). La fonction callback s’occupera d’afficher un message pour nos donner le statut de l’envoi du mail.

Étape 3 : Le PHP

Envoi d’email avec sendmail

<?php

$to = 'destinataire@adresse.fr';
$subject = $_POST['subject'];
$message = $_POST['message'];
$headers = 'From: ' . $_POST['email'] . "\r\n" . 'Reply-To: ' . $_POST['email'] . "\r\n" . 'X-Mailer: PHP/' . phpversion();

// On envoie le mail et on stocke le résultat
$result = mail($to, $subject, $message, $headers);

// Le contenu sera renvoyé au format JSON
header('Content-Type: application/json');

echo json_encode([
    'result' => $result
]);

Rien d’exceptionnel ici, les commentaires suffisent pour la compréhension du code. N’hésitez pas à aller lire la doc de la fonction mail si vous souhaitez en savoir plus (par exemple si vous souhaitez envoyer du contenu au format html).

Cette première version est fonctionnelle et suffira peut-être à vos besoins mais elle reste un peu limitée. En effet les emails envoyés avec la fonction mail de php arrivent plus souvent dans les spams et ça peut être également plus compliqué à tester.

La solution : utiliser un serveur SMTP.

Envoi d’email avec un serveur SMTP

Introduction

Commençons par utiliser une bibliothèque qui va nous permettre d’envoyer un email avec un serveur SMTP. Les deux plus populaires sont probablement SwiftMailer et PHPMailer. Nous utiliserons la première mais la seconde est tout aussi simple à utiliser.

Installation de SwiftMailer

Suivons la doc’ pour l’installer : composer require "swiftmailer/swiftmailer:^6.0"

Bien sûr il faut préalable avoir téléchargé Composer. Si tout se passe vous allez voir des fichiers composer.json et composer.lock apparaître ainsi qu’un dossier vendor.

Envoi de l’email

Maintenant que nous avons installé SwiftMailer, il ne nous reste plus qu’à l’utiliser !

<?php

header('Content-Type: application/json');

// On inclut le fichier autoload du dossier vendor
require __DIR__ . '/vendor/autoload.php';

// Create the Transport
$transport = (new Swift_SmtpTransport('smtp.example.org', 25))
    ->setUsername('your username')
    ->setPassword('your password');

// Create the Mailer using your created Transport
$mailer = new Swift_Mailer($transport);

// Create a message
$message = (new Swift_Message("Nouveau message de {$_POST['name']}[{$_POST['email']}] : {$_POST['subject']}"))
    ->setFrom(['contact@monsite.fr'])
    ->setTo(['destinataire@adresse.fr'])
    ->setReplyTo($_POST['email'])
    ->setBody($_POST['message']);

// Send the message
$result = $mailer->send($message);

echo json_encode([
    'result' => $result
]);

La majeure partie du code est directement issu de la documentation.

Test de l’envoi

Pour vérifier que votre code fonctionne, il vous faut utiliser un serveur SMTP avec les identifiants (par exemple gmail ou ovh). Attention car les mails partiront vraiment vers les destinaires qui ont été précisés dans votre code même si vous testez en local ! Mais ne vous inquiétez pas, là aussi pour tester facilement, j’ai une petite astuce à vous proposer (non ne me remerciez pas c’est normal 😉 ).

J’utilise en général un service de « Fake SMTP » qui s’appelle Maitrap. Je vous invite donc à vous créer un compte dessus (c’est gratuit). Une fois créé, vous disposez d’une boîte avec des informations. Les plus importantes sont les suivantes :

  • Host : smtp.mailtrap.io
  • Port : 25 or 465 or 2525
  • Username : xxxxxxxxxxxx
  • Password : xxxxxxxxxxxx

Ce sont ces informations que nous allons renseigner dans notre code qui devrait maintenant ressembler à ça (il n’y a que quelques lignes à changer) :

$transport = (new Swift_SmtpTransport('smtp.mailtrap.io', 2525))
    ->setUsername('votre_username_mailtrap')
    ->setPassword('votre_password_mailtrap');

Voilà vous pouvez tester pour voir si cela fonctionne 🙂 . Si c’est le cas vous devriez recevoir un nouveau mail dans la boîte Mailtrap (sur le site mailtrap.io).

NB : « votre_username_mailtrap » et « votre_password_mailtrap » sont à remplacer par vos identifiants Mailtrap

Utiliser une API

Autre alternative à l’envoi de mail par SMTP qui peut être sympa : l’utilisation de services tels que mailjet ou mailgun.

Pourquoi utiliser un tel service ?

Pour des raisons de performance ou de limitations de votre hébergeur. À titre d’exemple, j’ai eu récemment un problème avec l’envoi de mails sur mon hébergement mutualisé (qui partaient bien pourtant en local avec la même configuration). Avec Mailgun plus de problème puisque l’on passe directement par l’API.

L’avantage de Mailgun c’est qu’il est gratuit jusqu’à 1000 emails par mois donc largement suffisant pour l’utilisation que j’en fais. Et en plus c’est bien documenté et facile à implémenter.

Voyons ensemble comment faire.

Créer un compte Mailgun et vérifier le domaine

Commençons par nous créer un compte sur le site https://www.mailgun.com/. Une fois ceci fait, il faudra créer un nouveau domaine, par exemple mg.monsite.fr. On renseignera ensuite ce domaine dans notre code pour l’envoi du mail.

Une fois créé, ce domaine apparaît comme « Non vérifié ». Mailgun demande en effet à vérifier qu’il s’agit bien de votre nom de domaine. Pour ce faire, il va falloir renseigner certaines informations au niveau de l’interface d’administration de votre hébergeur, dans la partie DNS.

Tout est bien indiqué sur le site de Mailgun, vous ne devriez donc pas avoir de difficultés à le paramétrer. N’hésitez pas à laisser un commentaire si toutefois vous en rencontriez.

Mise en place

Le domaine vérifié, il ne nous reste plus qu’à coder. Première chose à faire, installer la bibliothèque php pour Mailgun. Là encore Composer s’occupera de tout : composer require mailgun/mailgun-php php-http/guzzle6-adapter php-http/message

Ensuite l’utilisation :

<?php

header('Content-Type: application/json');

// On inclut le fichier autoload du dossier vendor
require __DIR__ . '/vendor/autoload.php';

$mg = \Mailgun\Mailgun::create('votre_cle_api');

$result = $mg->messages()->send('mailgun_domain', [
    'from' => 'contact@monsite.fr',
    'to' => 'destinataire@adresse.fr',
    'subject' => "Nouveau message de {$_POST['name']}[{$_POST['email']}] : {$_POST['subject']}",
    'text' => $_POST['message'],
    'h:Reply-To' => $_POST['email']
]);

echo json_encode([
    'result' => $result
]);

Et voilà !

NB : ‘votre_cle_api’ est à remplacer par la clé api sur votre espace Mailgun et ‘mailgun_domain’ est à remplacer par le domaine créé au tout début de cette partie.

Conclusion

Ce dernier bout de code conclut ce tuto. J’espère que vous avez trouvé ça intéressant et utile. Vous pouvez laisser un commentaire pour me dire ce que vous en avez pensé.

Attention cela n’a pas été abordé pour ne pas alourdir le tutoriel mais il est important de bien valider les données utilisateurs envoyées (ici tout particulièrement l’email de l’utilisateur).

Une réflexion au sujet de « Formulaire de contact avec Ajax »

Laisser un commentaire

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