Add Email Notifications to Your AI Booking Website

Send booking confirmation emails and owner alerts using Supabase, Resend, and Edge Functions.

Roadmap & Resources

New Here? Start Here First

This guide upgrades the AI Booking Website project with automatic email notifications. If you haven’t built the booking website yet, start with the main guide first.

Build a Booking Website with AI

Open the main guide

MAIN GUIDE

https://profitstudio.app/video/build-booking-website-ai

Set Up Resend for Booking Emails

Create and Configure Your Resend Account

Open Resend

https://resend.com/

Create a Resend Account Generate a Resend API Key Copy and Save the API Key Securely

IMPORTANT

Keep the Resend API key private. Never add it to frontend code or share it publicly.

Add and Verify Your Sending Domain

Add Your Booking Website Domain Select the Closest Region Copy the DNS Records From Resend Add the Records to Your Domain Provider Return to Resend and Confirm the Domain Is Verified

DNS verification may take a few minutes or longer depending on your domain provider.

Create the Booking Email Function

Create the Booking Email Edge Function

Open Supabase

https://supabase.com/?utm_source=partner&utm_medium=social&utm_campaign=supasquad&dub_id=faVfKdcLWvKCbYNp

Open Your Supabase Project Open Edge Functions Create a New Function Using the Browser Editor Name the Function `send-booking-email` Remove the Default Starter Code

Customize and Add the Function Code

Enter the Owner Email Enter the Verified Resend Domain Enter the Sender Business Name Customize the Email Templates if Needed Copy and Paste the Generated Function Code

Booking Email Function

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" }, } ); } });

Owner Email

owner@example.com

Verified Resend Domain

yourdomain.com

Sender Business Name

Bright Dental Clinic

Owner Email Subject

Owner Email Heading

Owner Email Intro Text

Customer Email Subject

Customer Email Heading

Customer Email Intro Text

Customer Email Closing Text

Deploy and Configure the Function

Deploy the Function Open the Function Settings Turn Off `Verify JWT With Legacy Secret` Save the Changes Copy and Save the Function Endpoint URL for the Webhook Setup

IMPORTANT

Turn off “Verify JWT With Legacy Secret” so the Database Webhook can call the function.

Add the Resend API Key to Supabase

Add the Resend API Key as a Supabase Secret

Open Edge Function Secrets Create a New Secret Set the Name to `RESEND_API_KEY` Paste the Resend API Key Save the Secret

IMPORTANT

Use the exact secret name `RESEND_API_KEY`. Any typo will prevent the function from accessing Resend.

Connect Emails to New Bookings

Create the Booking Email Webhook

Trigger the booking email function whenever a new appointment is added.

Integrations Database Webhooks

Open Database Webhooks Enable Database Webhooks Create a New Webhook Name It `send-booking-email-webhook` Select the `public.appointments` Table Choose `Insert` as the Event Keep `HTTP Request` as the Type Use `POST` as the Request Method Paste the Edge Function Endpoint URL Create the Webhook

Test the Booking Email System

Test the Complete Booking Email Flow

Test the complete booking flow and confirm that both emails are delivered correctly.

Open the Live Booking Website Submit a Test Appointment Confirm the Booking Is Saved in Supabase Check the Customer Confirmation Email Check the Owner Notification Email Verify the Booking Details Are Correct in Both Emails Confirm the Booking Appears in the Admin Dashboard