Apprends à configurer Nodemailer pour envoyer des emails en Javascript via SMTP et améliorer l'expérience utilisateur dans React Router 7.
avec React Router 7
Posez vos questions 24/7 à notre IA experte en React Router 7
Validez vos acquis avec des quiz personnalisés et un feedback instantané
Dans le module précédent tu as mis en place le flow « Mot de passe oublié ». Tout fonctionne... sauf l’e-mail : le lien de réinitialisation n’apparaît que dans la console ! Pas très user-friendly. Nous allons :
sendPasswordResetEmail()
réutilisable.triggerResetPasswordRequest()
afin de transformer ton console.log
en vrai e-mail.Avec cette brique, tu peux ensuite envoyer n’importe quel courrier : newsletter, confirmation d’inscription, alerte, etc.
1npm install nodemailer2npm install -D @types/nodemailer
La dépendance de type n’est nécessaire qu’en dev ; pas de surcoût en prod.
Ajoute les valeurs SMTP dans ton .env
(ici un compte Mailgun « Pay-as-you-go » : 1 000 mails/mois gratuits).
1SMTP_HOST=smtp.mailgun.org2SMTP_PORT=5873SMTP_USER=postmaster@sandbox123.mailgun.org4SMTP_PASSWORD=superSecret5SMTP_SENDER="Formation React Router 7 <contact@algomax.fr>"67FRONTEND_URL=http://localhost:5173 # lien absolu pendant le dev
FRONTEND_URL
par ton nom de domaine.1import nodemailer from "nodemailer";23/**4* Le transporteur SMTP. Construit une seule fois (singleton).5*/6export const transporter = nodemailer.createTransport({7host: process.env.SMTP_HOST,8port: Number(process.env.SMTP_PORT ?? 587),9auth: {10user: process.env.SMTP_USER,11pass: process.env.SMTP_PASSWORD,12},13});
host
+ port
: paramètres de ton provider.auth.user
/ auth.pass
: identifiants SMTP..env
est déjà listé dans ton .gitignore
.sendEmail
1export async function sendEmail({2to,3subject,4html,5text,6}: {7to: string8subject: string9html: string10text: string11}) {12const info = await transporter.sendMail({13from: process.env.SMTP_SENDER,14to,15subject,16text,17html,18});1920console.log("📧 Email envoyé :", info.messageId);21}
from
récupère le nom + l’adresse définis dans SMTP_SENDER
.1export async function sendPasswordResetEmail({2email,3token,4}: {5email: string6token: string7}) {8const resetUrl = `${process.env.FRONTEND_URL}/reset-password?token=${token}`910await sendEmail({11to: email,12subject: "Réinitialisation de votre mot de passe",13text: [14"Bonjour,",15"Vous avez demandé à réinitialiser votre mot de passe.",16`Lien de réinitialisation : ${resetUrl}`,17"Si ce n'est pas vous, ignorez cet e-mail.",18].join("\n"),19html: `20<p>Bonjour,</p>21<p>Vous avez demandé à réinitialiser votre mot de passe.</p>22<p><a href="${resetUrl}">Cliquez ici pour choisir un nouveau mot de passe</a></p>23<p style="font-size:12px;color:#666">Ce lien expire dans 30 min.</p>24`,25})26}
FRONTEND_URL
. Sans ça, le navigateur ne saurait pas où rediriger depuis une boîte mail.1import { sendPasswordResetEmail } from "./emails.server";23// ...45export async function triggerResetPasswordRequest({ email }: { email: string }) {6const { userExists, userId } = await checkIfUserExists({ email, password: "" })7if (!userExists || !userId) return // pas d'info révélée89const token = crypto.randomUUID().slice(0, 32)10const expiresAt = new Date(Date.now() + 1000 * 60 * 30) // 30 min11await prisma.user.update({12where: { id: userId },13data: { resetToken: token, resetTokenExpiresAt: expiresAt },14})1516await sendPasswordResetEmail({ email, token })17}
.env
:
1npm run dev
1📧 Email envoyé : <202506021230@example.mailgun.org>
http://localhost:5173/reset-password?token=…
.Dans la page /forgot-password
, profite du hook useNavigation()
pour désactiver le bouton pendant l’envoi :
1const navigation = useNavigation()2/* … */3<button4type="submit"5disabled={navigation.state === "submitting"}6className="btn-primary w-full"7>8{navigation.state === "submitting" ? "Envoi en cours…" : "Réinitialiser"}9</button>
.env
(aperçu)Un oubli d’SMTP_HOST
en production = crash à chaud.
Dans une prochaine leçon nous verrons comment valider le fichier .env
avec Zod au démarrage du serveur pour prévenir ces erreurs avant qu’elles ne touchent tes utilisateurs.
sendEmail
, helper métier sendPasswordResetEmail
.FRONTEND_URL
indispensable pour cliquer depuis la messagerie.navigation.state === "submitting"
pour une UX soignéTu as désormais un système d’e-mail prêt pour la production !Dans la prochaine étape, on s’assure que toutes tes variables d’environnement sont validées et typées afin d’éviter les surprises lors du déploiement.
Quelle est la principale différence entre les composants client et serveur dans React ?
Quelle technique est recommandée pour éviter les rendus inutiles dans React ?
Quel hook permet de gérer les effets de bord dans un composant React ?
Comment implémenter la gestion des erreurs pour les requêtes API dans React ?
Quelle est la meilleure pratique pour déployer une application React en production ?