Resend : envoie tes emails transactionnels avec React
Apprends à connecter Resend à ta boutique React Router 7 : installation du SDK, clé API, template HTML et envoi automatisé d’emails transactionnels.
Pourquoi utiliser Resend ?
Courier.com offre 10 000 envois gratuits mais :
- il agit comme un proxy SMTP (Mailgun, SES...) ;
- beaucoup de configuration avant le premier mail.
Resend, lui :
- un SDK ;
- une clé API ;
- un envoi immédiat.
Parfait pour notre boutique (faible volume). Si un jour tu dépasses plusieurs centaines de milliers de mails : passe à Mailgun ou Amazon SES.
Note
Étape 1 – installer le SDK
1npm install resend
Le paquet ajoute juste un client HTTP. Aucun serveur à maintenir.
Étape 2 – ajouter la clé API
1RESEND_API_KEY=__TA_CLE__2RESEND_FROM_EMAIL=contact@shop-router.algomax.fr
RESEND_API_KEY: copiée dans Dashboard → API keys.RESEND_FROM_EMAIL: domaine vérifié côté Resend.
Tip
.env (il est déjà dans .gitignore).Étape 3 – le client Resend
1import { Resend } from "resend";23export const resend = new Resend(process.env.RESEND_API_KEY);
Simple : une instance, typée, prête à envoyer.
Étape 4 – premier template : confirmation de commande
On crée un modèle HTML + fallback texte.
Seule donnée dynamique : OrderEmailData.
1interface OrderEmailData {2orderId: string;3customerName: string;4customerEmail: string;5orderItems: Array<{6productName: string;7quantity: number;8totalPriceCents: number;9}>;10subtotalCents: number;11totalCents: number;12currency: string;13orderDate: Date;14}1516const orderConfirmationTemplate = (d: OrderEmailData) => `17<h1 style="font-size:22px;margin:0 0 12px">✅ Commande confirmée</h1>18<p>Merci ${d.customerName} !</p>19<p>N° ${d.orderId} — ${d.orderDate.toLocaleDateString("fr-FR")}</p>20${d.orderItems21.map(22(i) =>23`<p>${i.productName} ×${i.quantity} — ${format(i.totalPriceCents, d.currency)}</p>`,24)25.join("")}26<p style="font-weight:bold">Total : ${format(d.totalCents, d.currency)}</p>27<a href="${process.env.FRONTEND_URL}/orders/${d.orderId}"28style="display:inline-block;padding:12px 24px;background:#2563eb;color:#fff;border-radius:6px">29Suivre ma commande30</a>31`;3233const format = (cents: number, currency: string) =>34new Intl.NumberFormat("fr-FR", { style: "currency", currency }).format(cents / 100);
Étape 5 – fonction d’envoi
1export async function sendOrderConfirmationEmail(data: OrderEmailData) {2await resend.emails.send({3from: process.env.RESEND_FROM_EMAIL!,4to: data.customerEmail,5subject: `Confirmation de commande #${data.orderId}`,6html: orderConfirmationTemplate(data),7text: `Merci ${data.customerName}. Commande ${data.orderId}. Total : ${format(8data.totalCents,9data.currency,10)}`,11});12}
from: adresse vérifiée.to: le client.subject: clair et unique (numéro de commande).
Étape 6 – appeler l’envoi dans la création de commande
1await prisma.order.update({ … });2await sendOrderConfirmationEmail({3orderId: order.id,4customerName: user?.name ?? "client",5customerEmail: user?.email ?? guestEmail!,6orderItems: order.items,7subtotalCents: order.subtotalCents,8totalCents: order.totalCents,9currency: order.currency,10orderDate: order.createdAt,11});
Pourquoi ici ?
- La commande est en base : on a l’ID.
- Les lignes sont définitives : prix et quantités figés.
- Si l’envoi échoue, on logue l’erreur mais la commande reste créée.
Étape 7 – tester en local
- Lance l’appli :
npm run dev. - Crée un compte (Email différent).
- Passe au checkout test Stripe → paiement.
- Resend Dashboard → Emails : un message apparaît.
- Vérifie la boîte mail : parfois en Spam (domaine tout neuf).
Warning
Étape 8 – autres mails (bonus)
Le même fichier contient déjà :
sendOrderStatusUpdateEmail()sendPasswordResetEmail()sendAccountCreatedEmail()
Ils partagent la même logique : template HTML + fallback texte. Tu pourras les appeler :
1// après changement de statut2await sendOrderStatusUpdateEmail({ … });34// lors de la création du compte (hook Better-Auth)5await sendAccountCreatedForUser(email, name);
Checklist avant merge
-
RESEND_API_KEY+RESEND_FROM_EMAILprésents en production (Settings → Secrets GitHub). - Domaine vérifié dans Resend (MX + TXT propagés).
- Fonction appelée après la création d’une commande.
- Pas de clé Resend dans le dépôt public.
Important
Commit :
1git add .2git commit -m "feat: emails transactionnels via Resend"3git push --set-upstream origin 7-16-envoi-emails-resend
La CI relance, ton VPS reçoit la nouvelle image ; les prochains clients recevront immédiatement leur confirmation de commande 📧.
Comprendre les concepts fondamentaux
Quelle est la principale différence entre les composants client et serveur dans React ?
Optimisation des performances
Quelle technique est recommandée pour éviter les rendus inutiles dans React ?
Architecture des données
Quel hook permet de gérer les effets de bord dans un composant React ?