149 lines
3.5 KiB
TypeScript
149 lines
3.5 KiB
TypeScript
import { Resend } from "resend";
|
|
import { render } from "@react-email/render";
|
|
import log from "./logger";
|
|
|
|
/**
|
|
* Email service using Resend
|
|
*
|
|
* Environment variables required:
|
|
* - RESEND_API_KEY: API key from Resend dashboard
|
|
* - EMAIL_FROM: Sender email address (e.g., "FitAI <noreply@fitai.com>")
|
|
* - EMAIL_REPLY_TO: Reply-to email address (optional)
|
|
*/
|
|
|
|
const resend = new Resend(process.env.RESEND_API_KEY);
|
|
|
|
const DEFAULT_FROM = process.env.EMAIL_FROM || "FitAI <noreply@fitai.com>";
|
|
const DEFAULT_REPLY_TO = process.env.EMAIL_REPLY_TO;
|
|
|
|
export interface SendEmailOptions {
|
|
to: string | string[];
|
|
subject: string;
|
|
react: React.ReactElement;
|
|
from?: string;
|
|
replyTo?: string;
|
|
}
|
|
|
|
/**
|
|
* Send an email using Resend
|
|
*
|
|
* @param options - Email options including recipient, subject, and React component
|
|
* @returns Response from Resend API
|
|
*
|
|
* @example
|
|
* ```tsx
|
|
* import { WelcomeEmail } from '@/emails/welcome-email';
|
|
*
|
|
* await sendEmail({
|
|
* to: 'user@example.com',
|
|
* subject: 'Welcome to FitAI',
|
|
* react: <WelcomeEmail name="John" />
|
|
* });
|
|
* ```
|
|
*/
|
|
export async function sendEmail({
|
|
to,
|
|
subject,
|
|
react,
|
|
from = DEFAULT_FROM,
|
|
replyTo = DEFAULT_REPLY_TO,
|
|
}: SendEmailOptions) {
|
|
try {
|
|
// Check if email is configured
|
|
if (!process.env.RESEND_API_KEY) {
|
|
log.warn("RESEND_API_KEY not configured. Email not sent.", {
|
|
to,
|
|
subject,
|
|
});
|
|
return { success: false, error: "Email not configured" };
|
|
}
|
|
|
|
const { data, error } = await resend.emails.send({
|
|
from,
|
|
to,
|
|
subject,
|
|
react,
|
|
...(replyTo && { replyTo }),
|
|
});
|
|
|
|
if (error) {
|
|
log.error("Failed to send email", error, { to, subject });
|
|
return { success: false, error: error.message };
|
|
}
|
|
|
|
log.info("Email sent successfully", { to, subject, emailId: data?.id });
|
|
return { success: true, data };
|
|
} catch (error) {
|
|
log.error("Email service error", error, { to, subject });
|
|
return { success: false, error: "Email service error" };
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Send a welcome email to a new user
|
|
*/
|
|
export async function sendWelcomeEmail(email: string, name: string) {
|
|
const { WelcomeEmail } = await import("@/emails/welcome-email");
|
|
|
|
return sendEmail({
|
|
to: email,
|
|
subject: "Welcome to FitAI!",
|
|
react: WelcomeEmail({ name }),
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Send an invitation email to a new user
|
|
*/
|
|
export async function sendInvitationEmail(
|
|
email: string,
|
|
role: string,
|
|
inviteUrl: string,
|
|
) {
|
|
const { UserInvitationEmail } = await import(
|
|
"@/emails/user-invitation-email"
|
|
);
|
|
|
|
return sendEmail({
|
|
to: email,
|
|
subject: "You've been invited to join FitAI",
|
|
react: UserInvitationEmail({ email, role, inviteUrl }),
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Send a trainer assignment notification email
|
|
*/
|
|
export async function sendTrainerAssignmentEmail(
|
|
clientEmail: string,
|
|
clientName: string,
|
|
trainerName: string,
|
|
) {
|
|
const { TrainerAssignmentEmail } = await import(
|
|
"@/emails/trainer-assignment-email"
|
|
);
|
|
|
|
return sendEmail({
|
|
to: clientEmail,
|
|
subject: "You've been assigned a trainer",
|
|
react: TrainerAssignmentEmail({ clientName, trainerName }),
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Send a recommendation notification email to a client
|
|
*/
|
|
export async function sendRecommendationEmail(
|
|
clientEmail: string,
|
|
clientName: string,
|
|
recommendationText: string,
|
|
) {
|
|
const { RecommendationEmail } = await import("@/emails/recommendation-email");
|
|
|
|
return sendEmail({
|
|
to: clientEmail,
|
|
subject: "New fitness recommendation from your trainer",
|
|
react: RecommendationEmail({ clientName, recommendationText }),
|
|
});
|
|
}
|