Files

154 lines
3.6 KiB
TypeScript

import { JSXElementConstructor, ReactElement } from "react";
import { render, toPlainText } from "@react-email/render";
import { Resend } from "resend";
import prisma from "@/lib/prisma";
import { log, nanoid } from "@/lib/utils";
export const resend = process.env.RESEND_API_KEY
? new Resend(process.env.RESEND_API_KEY)
: null;
export const sendEmail = async ({
to,
subject,
react,
from,
marketing,
system,
verify,
test,
cc,
replyTo,
scheduledAt,
unsubscribeUrl,
}: {
to: string;
subject: string;
react: ReactElement<any, string | JSXElementConstructor<any>>;
from?: string;
marketing?: boolean;
system?: boolean;
verify?: boolean;
test?: boolean;
cc?: string | string[];
replyTo?: string;
scheduledAt?: string;
unsubscribeUrl?: string;
}) => {
if (!resend) {
// Throw an error if resend is not initialized
throw new Error("Resend not initialized");
}
const html = await render(react);
const plainText = toPlainText(html);
const appName = process.env.NEXT_PUBLIC_APP_NAME || "Hanzo Dataroom";
const defaultFrom = process.env.EMAIL_FROM || `${appName} <[email protected]>`;
const fromAddress =
from ??
(marketing
? process.env.EMAIL_FROM_MARKETING || defaultFrom
: system
? process.env.EMAIL_FROM_SYSTEM || defaultFrom
: verify
? process.env.EMAIL_FROM_VERIFY || defaultFrom
: defaultFrom);
try {
const { data, error } = await resend.emails.send({
from: fromAddress,
to: test ? "[email protected]" : to,
cc: cc,
replyTo: marketing ? "[email protected]" : replyTo,
subject,
react,
scheduledAt,
text: plainText,
headers: {
"X-Entity-Ref-ID": nanoid(),
...(unsubscribeUrl
? {
"List-Unsubscribe": `<${unsubscribeUrl}>`,
"List-Unsubscribe-Post": "List-Unsubscribe=One-Click",
}
: {}),
},
});
// Check if the email sending operation returned an error and throw it
if (error) {
log({
message: `Resend returned error when sending email: ${error.name} \n\n ${error.message}`,
type: "error",
mention: true,
});
throw error;
}
// If there's no error, return the data
return data;
} catch (exception) {
// Log and rethrow any caught exceptions for upstream handling
log({
message: `Unexpected error when sending email: ${exception}`,
type: "error",
mention: true,
});
throw exception; // Rethrow the caught exception
}
};
export const subscribe = async (email: string): Promise<void> => {
if (!resend) {
console.error("RESEND_API_KEY is not set in the .env. Skipping.");
return;
}
const { data, error } = await resend.contacts.create({
email,
});
if (error || !data?.id) {
console.error("Failed to create contact:", error);
return;
}
if (
process.env.NODE_ENV === "production" &&
process.env.RESEND_MARKETING_SEGMENT_ID
) {
await resend.contacts.segments.add({
contactId: data.id,
segmentId: process.env.RESEND_MARKETING_SEGMENT_ID as string,
});
}
};
export const unsubscribe = async (email: string): Promise<void> => {
if (!resend) {
console.error("RESEND_API_KEY is not set in the .env. Skipping.");
return;
}
if (!email) {
return;
}
const user = await prisma.user.findUnique({
where: { email },
select: { email: true },
});
if (!user || !user.email) {
return;
}
await resend.contacts.update({
email: user.email,
unsubscribed: true,
});
};