เพิ่มการแจ้งเตือนทางอีเมลให้เว็บจอง AI ของคุณ

ส่งอีเมลยืนยันการจองและแจ้งเตือนเจ้าของร้านด้วย Supabase, Resend และ Edge Functions

แผนการทำงานและแหล่งข้อมูล

เพิ่งเริ่มใช่ไหม? เริ่มตรงนี้ก่อน

คู่มือนี้เป็นการอัปเกรดโปรเจกต์เว็บจอง AI ด้วยการแจ้งเตือนทางอีเมลอัตโนมัติ ถ้ายังไม่ได้สร้างเว็บจอง ให้เริ่มจากคู่มือหลักก่อน

สร้างเว็บจองคิวด้วย AI

เปิดคู่มือหลัก

MAIN GUIDE

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

ตั้งค่า Resend สำหรับอีเมลการจอง

สร้างและตั้งค่าบัญชี Resend ของคุณ

เปิด Resend

https://resend.com/

สร้างบัญชี Resend สร้าง Resend API Key คัดลอกและเก็บ API Key ไว้อย่างปลอดภัย

สำคัญ

เก็บ Resend API Key ไว้เป็นความลับ อย่าใส่ไว้ในโค้ดฝั่งหน้าเว็บหรือเผยแพร่สู่สาธารณะ

เพิ่มและยืนยันโดเมนผู้ส่ง

เพิ่มโดเมนเว็บไซต์จองของคุณ เลือกภูมิภาคที่ใกล้ที่สุด คัดลอกระเบียน DNS จาก Resend เพิ่มระเบียนที่ผู้ให้บริการโดเมนของคุณ กลับไปที่ Resend และยืนยันว่าโดเมนผ่านการยืนยันแล้ว

การยืนยัน DNS อาจใช้เวลาไม่กี่นาทีหรือนานกว่านั้น ขึ้นอยู่กับผู้ให้บริการโดเมนของคุณ

สร้างฟังก์ชันส่งอีเมลการจอง

สร้าง Edge Function สำหรับอีเมลการจอง

เปิด Supabase

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

เปิดโปรเจกต์ Supabase ของคุณ เปิด Edge Functions สร้างฟังก์ชันใหม่โดยใช้ตัวแก้ไขในเบราว์เซอร์ ตั้งชื่อฟังก์ชันว่า `send-booking-email` ลบโค้ดเริ่มต้นที่มาโดยค่าเริ่มต้น

ปรับแต่งและเพิ่มโค้ดของฟังก์ชัน

กรอกอีเมลของเจ้าของ กรอกโดเมน Resend ที่ยืนยันแล้ว กรอกชื่อธุรกิจผู้ส่ง ปรับแต่งเทมเพลตอีเมลหากจำเป็น คัดลอกและวางโค้ดฟังก์ชันที่สร้างขึ้น

ฟังก์ชันส่งอีเมลการจอง

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@example.com

โดเมน Resend ที่ยืนยันแล้ว

yourdomain.com

ชื่อร้านผู้ส่ง

คลินิกทันตกรรมไบรท์

หัวข้ออีเมลถึงเจ้าของร้าน

หัวเรื่องในอีเมลถึงเจ้าของร้าน

ข้อความเปิดอีเมลถึงเจ้าของร้าน

หัวข้ออีเมลถึงลูกค้า

หัวเรื่องในอีเมลถึงลูกค้า

ข้อความเปิดอีเมลถึงลูกค้า

ข้อความปิดท้ายอีเมลถึงลูกค้า

ดีพลอยและตั้งค่าฟังก์ชัน

ดีพลอยฟังก์ชัน เปิดการตั้งค่าของฟังก์ชัน ปิด `Verify JWT With Legacy Secret` บันทึกการเปลี่ยนแปลง คัดลอกและเก็บ URL ปลายทางของฟังก์ชันไว้สำหรับตั้งค่า Webhook

สำคัญ

ปิด “Verify JWT With Legacy Secret” เพื่อให้ Database Webhook เรียกใช้ฟังก์ชันได้

เพิ่ม Resend API key ใน Supabase

เพิ่ม Resend API Key เป็น Secret ใน Supabase

เปิด Edge Function Secrets สร้าง Secret ใหม่ ตั้งชื่อเป็น `RESEND_API_KEY` วาง Resend API Key บันทึก Secret

สำคัญ

ใช้ชื่อ Secret ให้ตรงกับ `RESEND_API_KEY` พอดี หากพิมพ์ผิดแม้เพียงเล็กน้อย ฟังก์ชันจะเข้าถึง Resend ไม่ได้

เชื่อมอีเมลเข้ากับการจองใหม่

สร้าง Webhook สำหรับอีเมลการจอง

เรียกใช้ฟังก์ชันอีเมลการจองทุกครั้งที่มีการเพิ่มการนัดหมายใหม่

Integrations Database Webhooks

เปิด Database Webhooks เปิดใช้งาน Database Webhooks สร้าง Webhook ใหม่ ตั้งชื่อว่า `send-booking-email-webhook` เลือกตาราง `public.appointments` เลือก `Insert` เป็นเหตุการณ์ คงประเภทไว้เป็น `HTTP Request` ใช้ `POST` เป็นเมธอดของคำขอ วาง URL ปลายทางของ Edge Function สร้าง Webhook

ทดสอบระบบอีเมลการจอง

ทดสอบขั้นตอนอีเมลการจองทั้งหมด

ทดสอบขั้นตอนการจองทั้งหมด และยืนยันว่าอีเมลทั้งสองฉบับถูกส่งอย่างถูกต้อง

เปิดเว็บไซต์จองที่ใช้งานจริง ส่งการนัดหมายทดสอบ ยืนยันว่าการจองถูกบันทึกใน Supabase ตรวจสอบอีเมลยืนยันที่ส่งถึงลูกค้า ตรวจสอบอีเมลแจ้งเตือนที่ส่งถึงเจ้าของ ตรวจสอบว่ารายละเอียดการจองถูกต้องในอีเมลทั้งสองฉบับ ยืนยันว่าการจองปรากฏในแดชบอร์ดผู้ดูแล