60 lines
1.6 KiB
TypeScript
60 lines
1.6 KiB
TypeScript
import nodemailer from "nodemailer";
|
|
import { render } from "@react-email/render";
|
|
import { InvitationEmail } from "./templates/invitation";
|
|
|
|
function createTransport() {
|
|
const host = process.env.SMTP_HOST;
|
|
if (!host) throw new Error("SMTP_HOST is not configured");
|
|
|
|
return nodemailer.createTransport({
|
|
host,
|
|
port: parseInt(process.env.SMTP_PORT ?? "587"),
|
|
secure: process.env.SMTP_SECURE === "true",
|
|
auth:
|
|
process.env.SMTP_USER && process.env.SMTP_PASS
|
|
? { user: process.env.SMTP_USER, pass: process.env.SMTP_PASS }
|
|
: undefined,
|
|
});
|
|
}
|
|
|
|
const FROM = () => process.env.EMAIL_FROM ?? "CubeAdmin <noreply@example.com>";
|
|
|
|
export async function sendMagicLinkEmail({
|
|
email,
|
|
url,
|
|
token: _token,
|
|
}: {
|
|
email: string;
|
|
url: string;
|
|
token: string;
|
|
}): Promise<void> {
|
|
await createTransport().sendMail({
|
|
from: FROM(),
|
|
to: email,
|
|
subject: "Your CubeAdmin sign-in link",
|
|
html: `<p>Click the link below to sign in to CubeAdmin. This link expires in 1 hour.</p><p><a href="${url}">${url}</a></p>`,
|
|
text: `Sign in to CubeAdmin: ${url}\n\nThis link expires in 1 hour.`,
|
|
});
|
|
}
|
|
|
|
export async function sendInvitationEmail({
|
|
to,
|
|
invitedByName,
|
|
inviteUrl,
|
|
role,
|
|
}: {
|
|
to: string;
|
|
invitedByName: string;
|
|
inviteUrl: string;
|
|
role: string;
|
|
}): Promise<void> {
|
|
const html = await render(InvitationEmail({ invitedByName, inviteUrl, role }));
|
|
await createTransport().sendMail({
|
|
from: FROM(),
|
|
to,
|
|
subject: `You've been invited to CubeAdmin`,
|
|
html,
|
|
text: `${invitedByName} invited you to CubeAdmin as ${role}.\n\nAccept your invitation: ${inviteUrl}\n\nThis link expires in 48 hours.`,
|
|
});
|
|
}
|