import { sendCustomWorkflowEmail } from "@calcom/emails/workflow-email-service"; import { BookingRepository } from "@calcom/features/bookings/repositories/BookingRepository"; import { BookingSeatRepository } from "@calcom/features/bookings/repositories/BookingSeatRepository"; import { CalendarEventBuilder } from "@calcom/features/CalendarEventBuilder"; import { EmailWorkflowService } from "@calcom/features/ee/workflows/lib/service/EmailWorkflowService"; import { WorkflowReminderRepository } from "@calcom/features/ee/workflows/repositories/WorkflowReminderRepository"; import { prisma } from "@calcom/prisma"; import { bookingMetadataSchema } from "@calcom/prisma/zod-utils"; import { z } from "zod"; export const ZSendWorkflowEmailsSchemaEager = z.object({ to: z.array(z.string()), subject: z.string(), html: z.string(), replyTo: z.string().optional(), sender: z.string().nullable().optional(), attachments: z .array( z .object({ content: z.string(), filename: z.string(), }) .passthrough() ) .optional(), }); const ZSendWorkflowEmailsSchemaLazy = z.object({ bookingUid: z.string(), workflowReminderId: z.number(), platformClientId: z.string().optional(), platformRescheduleUrl: z.string().optional(), platformCancelUrl: z.string().optional(), platformBookingUrl: z.string().optional(), }); export const ZSendWorkflowEmailsSchema = z.union([ ZSendWorkflowEmailsSchemaEager, ZSendWorkflowEmailsSchemaLazy, ]); export async function sendWorkflowEmails(payload: string): Promise { const mailData = ZSendWorkflowEmailsSchema.parse(JSON.parse(payload)); // Generate workflow body to send if ("bookingUid" in mailData && "workflowReminderId" in mailData) { const bookingRepository = new BookingRepository(prisma); const booking = await bookingRepository.getBookingForCalEventBuilderFromUid(mailData.bookingUid); if (!booking) { throw new Error("Booking not found"); } const bookingMetadata = bookingMetadataSchema.parse(booking.metadata || {}); const calendarEvent = ( await CalendarEventBuilder.fromBooking(booking, { platformClientId: mailData.platformClientId ?? bookingMetadata?.platformClientId, platformRescheduleUrl: mailData.platformRescheduleUrl, platformCancelUrl: mailData.platformCancelUrl, platformBookingUrl: mailData.platformBookingUrl, }) ).build(); if (!calendarEvent) { throw new Error("Calendar event could not be built"); } // Check if videoCallUrl exists in booking metadata and add it to evt.metadata const metadata = bookingMetadata?.videoCallUrl ? { videoCallUrl: bookingMetadata.videoCallUrl, } : undefined; const evtWithMetadata = { ...calendarEvent, metadata }; const workflowReminderRepository = new WorkflowReminderRepository(prisma); const bookingSeatRepository = new BookingSeatRepository(prisma); const emailWorkflowService = new EmailWorkflowService(workflowReminderRepository, bookingSeatRepository); await emailWorkflowService.handleSendEmailWorkflowTask({ evt: evtWithMetadata, workflowReminderId: mailData.workflowReminderId, }); return; } await Promise.all( mailData.to.map((to) => sendCustomWorkflowEmail({ ...mailData, to, }) ) ); }