Ajoute des notifications par e-mail à ton site de réservation IA
Envoie des e-mails de confirmation de réservation et des alertes au propriétaire en utilisant Supabase, Resend et Edge Functions.
Feuille de route et ressources
Tu débutes ? Commence ici en premier
Ce guide enrichit le projet du site de réservation IA avec des notifications par e-mail automatiques. Si tu n'as pas encore construit le site de réservation, commence d'abord par le guide principal.
Crée un site de réservation avec l'IA
Ouvre le guide principal
MAIN GUIDE
https://profitstudio.app/video/build-booking-website-ai
Configurer Resend pour les e-mails de réservation
Crée et configure ton compte Resend
Ouvrir Resend
https://resend.com/
Créez un compte Resend Générez une clé API Resend Copiez et enregistrez la clé API en lieu sûr
IMPORTANT
Garde la clé API Resend privée. Ne l'ajoute jamais au code frontend et ne la partage jamais publiquement.
Ajoute et vérifie ton domaine d'envoi
Ajoutez le domaine de votre site de réservation Sélectionnez la région la plus proche Copiez les enregistrements DNS depuis Resend Ajoutez les enregistrements chez votre fournisseur de domaine Revenez sur Resend et confirmez que le domaine est vérifié
La vérification DNS peut prendre quelques minutes, voire plus, selon ton fournisseur de domaine.
Créer la fonction d'e-mail de réservation
Crée l'Edge Function d'e-mail de réservation
Ouvrir Supabase
https://supabase.com/?utm_source=partner&utm_medium=social&utm_campaign=supasquad&dub_id=faVfKdcLWvKCbYNp
Ouvrez votre projet Supabase Ouvrez Edge Functions Créez une nouvelle fonction avec l'éditeur du navigateur Nommez la fonction `send-booking-email` Supprimez le code de démarrage par défaut
Personnalise et ajoute le code de la fonction
Saisissez l'e-mail du propriétaire Saisissez le domaine Resend vérifié Saisissez le nom de l'entreprise expéditrice Personnalisez les modèles d'e-mail si nécessaire Copiez et collez le code de fonction généré
Fonction d'e-mail de réservation
import { serve } from "https://deno.land/std/http/server.ts"; serve(async (req) => { try { const body = await req.json(); const record = body.record || {}; const resendKey = Deno.env.get("RESEND_API_KEY"); const supabaseUrl = Deno.env.get("SUPABASE_URL"); const supabaseServiceRoleKey = Deno.env.get("SUPABASE_SERVICE_ROLE_KEY"); if (!resendKey) { return new Response( JSON.stringify({ error: "Missing RESEND_API_KEY secret" }), { status: 500, headers: { "Content-Type": "application/json" }, } ); } const ownerEmail = "YOUR_OWNER_EMAIL"; const customerEmail = record.email || ""; const customerName = record.full_name || record.name || "Customer"; const phone = record.phone || ""; const appointmentDate = record.appointment_date || record.date || ""; const startTime = record.start_time || record.time || ""; const endTime = record.end_time || ""; const notes = record.notes || ""; const status = record.status || "New"; let serviceName = record.service_name || record.service || record.service_title || ""; // If the appointment only has service_id, fetch the service name from the services table if (!serviceName && record.service_id && supabaseUrl && supabaseServiceRoleKey) { try { const serviceId = encodeURIComponent(record.service_id); const serviceResponse = await fetch( `${supabaseUrl}/rest/v1/services?id=eq.${serviceId}&select=name`, { method: "GET", headers: { apikey: supabaseServiceRoleKey, Authorization: `Bearer ${supabaseServiceRoleKey}`, "Content-Type": "application/json", }, } ); const serviceData = await serviceResponse.json(); if (Array.isArray(serviceData) && serviceData.length > 0) { serviceName = serviceData[0].name || ""; } } catch (_serviceError) { serviceName = ""; } } if (!serviceName) { serviceName = "Appointment"; } // 1) Email to business owner const ownerResponse = await fetch("https://api.resend.com/emails", { method: "POST", headers: { Authorization: `Bearer ${resendKey}`, "Content-Type": "application/json", }, body: JSON.stringify({ from: "Bookings <bookings@YOUR_DOMAIN_NAME>", to: [ownerEmail], subject: "OWNER_NOTIFICATION_SUBJECT", html: ` <h2>OWNER_NOTIFICATION_HEADING</h2> <p>OWNER_NOTIFICATION_INTRO</p> <p><b>Customer Name:</b> ${customerName}</p> <p><b>Email:</b> ${customerEmail}</p> <p><b>Phone:</b> ${phone}</p> <p><b>Service:</b> ${serviceName}</p> <p><b>Date:</b> ${appointmentDate}</p> <p><b>Start Time:</b> ${startTime}</p> <p><b>End Time:</b> ${endTime}</p> <p><b>Notes:</b> ${notes}</p> <p><b>Status:</b> ${status}</p> `, }), }); const ownerData = await ownerResponse.json(); // 2) Email to customer let customerData = null; if (customerEmail) { const customerResponse = await fetch("https://api.resend.com/emails", { method: "POST", headers: { Authorization: `Bearer ${resendKey}`, "Content-Type": "application/json", }, body: JSON.stringify({ from: "YOUR_BUSINESS_NAME <bookings@YOUR_DOMAIN_NAME>", to: [customerEmail], subject: "CUSTOMER_CONFIRMATION_SUBJECT", html: ` <h2>CUSTOMER_CONFIRMATION_HEADING</h2> <p>Hi ${customerName},</p> <p>CUSTOMER_CONFIRMATION_INTRO</p> <p><b>Service:</b> ${serviceName}</p> <p><b>Date:</b> ${appointmentDate}</p> <p><b>Start Time:</b> ${startTime}</p> <p><b>End Time:</b> ${endTime}</p> <p>If you need to make any changes, please contact us before your appointment.</p> <p>CUSTOMER_CONFIRMATION_CLOSING</p> `, }), }); customerData = await customerResponse.json(); } return new Response( JSON.stringify({ success: true, ownerEmailSent: ownerData, customerEmailSent: customerData, }), { headers: { "Content-Type": "application/json" }, } ); } catch (error) { return new Response( JSON.stringify({ success: false, error: String(error), }), { status: 500, headers: { "Content-Type": "application/json" }, } ); } });
E-mail du propriétaire
owner@example.com
Domaine Resend vérifié
yourdomain.com
Nom du business expéditeur
Clinique dentaire Bright
Objet de l'e-mail au propriétaire
En-tête de l'e-mail au propriétaire
Texte d'introduction de l'e-mail au propriétaire
Objet de l'e-mail client
En-tête de l'e-mail client
Texte d'introduction de l'e-mail client
Texte de clôture de l'e-mail client
Déploie et configure la fonction
Déployez la fonction Ouvrez les paramètres de la fonction Désactivez `Verify JWT With Legacy Secret` Enregistrez les modifications Copiez et conservez l'URL de l'endpoint de la fonction pour la configuration du webhook
IMPORTANT
Désactive « Verify JWT With Legacy Secret » pour que le Database Webhook puisse appeler la fonction.
Ajouter la clé API Resend à Supabase
Ajoute la clé API Resend comme secret Supabase
Ouvrez Edge Function Secrets Créez un nouveau secret Définissez le nom sur `RESEND_API_KEY` Collez la clé API Resend Enregistrez le secret
IMPORTANT
Utilise exactement le nom de secret `RESEND_API_KEY`. La moindre faute de frappe empêchera la fonction d'accéder à Resend.
Connecter les e-mails aux nouvelles réservations
Crée le webhook d'e-mail de réservation
Déclenche la fonction d'e-mail de réservation à chaque nouveau rendez-vous ajouté.
Integrations Database Webhooks
Ouvrez Database Webhooks Activez Database Webhooks Créez un nouveau webhook Nommez-le `send-booking-email-webhook` Sélectionnez la table `public.appointments` Choisissez `Insert` comme événement Conservez `HTTP Request` comme type Utilisez `POST` comme méthode de requête Collez l'URL de l'endpoint de l'Edge Function Créez le webhook
Tester le système d'e-mail de réservation
Teste le flux complet d'e-mails de réservation
Teste le flux de réservation complet et vérifie que les deux e-mails sont bien distribués.
Ouvrez le site de réservation en ligne Envoyez un rendez-vous de test Confirmez que la réservation est enregistrée dans Supabase Vérifiez l'e-mail de confirmation du client Vérifiez l'e-mail de notification du propriétaire Vérifiez que les détails de la réservation sont corrects dans les deux e-mails Confirmez que la réservation apparaît dans le tableau de bord admin