Comment envoyer un email en Javascript

Apprends à configurer Nodemailer pour envoyer des emails en Javascript via SMTP et améliorer l'expérience utilisateur dans React Router 7.

5 min read
Déverrouillez votre potentiel

avec React Router 7

Vous en avez marre de...

❌ perdre du temps à chercher des informations éparpillées
❌ ne pas avoir de retour sur votre progression
Assistant IA spécialisé

Posez vos questions 24/7 à notre IA experte en React Router 7

Quiz interactifs

Validez vos acquis avec des quiz personnalisés et un feedback instantané

9 modules
45 leçons
Accès à vie
299.00
-50%

Pourquoi gérer l’envoi d’e-mails côté serveur ?

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 :

  1. Installer et configurer Nodemailer pour envoyer un mail depuis notre serveur Express.
  2. Typiser les variables d’environnement afin d’éviter les « undefined » en production.
  3. Utiliser un provider SMTP (gratuit au départ) comme Mailgun ou Resend.
  4. Factoriser un helper sendPasswordResetEmail() réutilisable.
  5. Brancher ce helper dans 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.


1 – Installer Nodemailer

install.sh
1
npm install nodemailer
2
npm install -D @types/nodemailer

La dépendance de type n’est nécessaire qu’en dev ; pas de surcoût en prod.


2 – Préparer les variables d’environnement

Ajoute les valeurs SMTP dans ton .env (ici un compte Mailgun « Pay-as-you-go » : 1 000 mails/mois gratuits).

.env
1
SMTP_HOST=smtp.mailgun.org
2
SMTP_PORT=587
3
SMTP_USER=postmaster@sandbox123.mailgun.org
4
SMTP_PASSWORD=superSecret
5
SMTP_SENDER="Formation React Router 7 <contact@algomax.fr>"
6
7
FRONTEND_URL=http://localhost:5173 # lien absolu pendant le dev

3 – Créer le transport Nodemailer

app/server/emails.server.ts
1
import nodemailer from "nodemailer";
2
3
/**
4
* Le transporteur SMTP. Construit une seule fois (singleton).
5
*/
6
export const transporter = nodemailer.createTransport({
7
host: process.env.SMTP_HOST,
8
port: Number(process.env.SMTP_PORT ?? 587),
9
auth: {
10
user: process.env.SMTP_USER,
11
pass: process.env.SMTP_PASSWORD,
12
},
13
});
  • host + port : paramètres de ton provider.
  • auth.user / auth.pass : identifiants SMTP.

4 – Factoriser un helper générique sendEmail

app/server/emails.server.ts
1
export async function sendEmail({
2
to,
3
subject,
4
html,
5
text,
6
}: {
7
to: string
8
subject: string
9
html: string
10
text: string
11
}) {
12
const info = await transporter.sendMail({
13
from: process.env.SMTP_SENDER,
14
to,
15
subject,
16
text,
17
html,
18
});
19
20
console.log("📧 Email envoyé :", info.messageId);
21
}
  • from récupère le nom + l’adresse définis dans SMTP_SENDER.
  • La fonction loggue l’id, pratique pour le debug local.

5 – Spécialiser l’e-mail « Réinitialisation de mot de passe »

app/server/emails.server.ts
1
export async function sendPasswordResetEmail({
2
email,
3
token,
4
}: {
5
email: string
6
token: string
7
}) {
8
const resetUrl = `${process.env.FRONTEND_URL}/reset-password?token=${token}`
9
10
await sendEmail({
11
to: email,
12
subject: "Réinitialisation de votre mot de passe",
13
text: [
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"),
19
html: `
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
}

6 – Appeler le helper dans la logique serveur

app/server/sessions.server.ts
1
import { sendPasswordResetEmail } from "./emails.server";
2
3
// ...
4
5
export async function triggerResetPasswordRequest({ email }: { email: string }) {
6
const { userExists, userId } = await checkIfUserExists({ email, password: "" })
7
if (!userExists || !userId) return // pas d'info révélée
8
9
const token = crypto.randomUUID().slice(0, 32)
10
const expiresAt = new Date(Date.now() + 1000 * 60 * 30) // 30 min
11
await prisma.user.update({
12
where: { id: userId },
13
data: { resetToken: token, resetTokenExpiresAt: expiresAt },
14
})
15
16
await sendPasswordResetEmail({ email, token })
17
}
  1. On vérifie l’existence du compte (sans distinguer « email inconnu » pour éviter le credential enumeration).
  2. On génère un token + date d’expiration.
  3. On sauvegarde en base, puis on envoie l’e-mail.

7 – Tester en local

  1. Re-lance le serveur pour recharger le .env :
    Terminal
    1
    npm run dev
  2. Clique sur « Mot de passe oublié », entre un e-mail valide.
  3. Observe la console :
    1
    📧 Email envoyé : <202506021230@example.mailgun.org>
  4. Dans la boîte de réception (ou Mailgun sandbox) tu trouves bien ton mail avec le lien complet http://localhost:5173/reset-password?token=….

8 – Ajout d’un feedback visuel côté client

Dans la page /forgot-password, profite du hook useNavigation() pour désactiver le bouton pendant l’envoi :

{4,15} app/routes/forgot-password.tsx
1
const navigation = useNavigation()
2
/* … */
3
<button
4
type="submit"
5
disabled={navigation.state === "submitting"}
6
className="btn-primary w-full"
7
>
8
{navigation.state === "submitting" ? "Envoi en cours…" : "Réinitialiser"}
9
</button>

9 – Sécuriser et typiser tes variables .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.


Points clés à retenir

  • Nodemailer est la solution la plus simple pour envoyer un mail depuis Node.
  • Utilise un provider SMTP (Mailgun, Resend…) gratuit jusqu’à quelques milliers de messages.
  • Centralise la configuration : transporteur, helper sendEmail, helper métier sendPasswordResetEmail.
  • Lien absolu FRONTEND_URL indispensable pour cliquer depuis la messagerie.
  • Le token stocké en base est unique et temporaire (30 min dans l’exemple).
  • En dev, regarde la console pour vérifier l’envoi ; en prod, branche un vrai domaine.
  • Désactive le bouton via 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.

Premium
Quiz interactif
Testez vos connaissances et validez votre compréhension du module avec notre quiz interactif.
1

Comprendre les concepts fondamentaux

Quelle est la principale différence entre les composants client et serveur dans React ?

Les composants client s'exécutent uniquement dans le navigateur
Les composants serveur peuvent utiliser useState
Les composants client sont plus rapides
Il n'y a aucune différence significative
2

Optimisation des performances

Quelle technique est recommandée pour éviter les rendus inutiles dans React ?

Utiliser React.memo pour les composants fonctionnels
Ajouter plus d'états locaux
Éviter d'utiliser les props
Toujours utiliser les class components
3

Architecture des données

Quel hook permet de gérer les effets de bord dans un composant React ?

useEffect
useState
useMemo
useContext
4

Gestion des erreurs

Comment implémenter la gestion des erreurs pour les requêtes API dans React ?

Utiliser try/catch avec async/await
Ignorer les erreurs
Toujours afficher un message d'erreur
Rediriger l'utilisateur
5

Déploiement et CI/CD

Quelle est la meilleure pratique pour déployer une application React en production ?

Utiliser un service CI/CD comme GitHub Actions
Copier les fichiers manuellement via FTP
Envoyer le code source complet
Ne jamais mettre à jour l'application

Débloquez ce quiz et tous les autres contenus premium en achetant ce cours