import { env } from '$env/dynamic/private'; import nodemailer from 'nodemailer'; let transporter: ReturnType | undefined; function mailer() { if (!env.SMTP_HOST || !env.SMTP_FROM) { throw new Error('Email delivery is not configured.'); } if (!transporter) { transporter = nodemailer.createTransport({ host: env.SMTP_HOST, port: Number(env.SMTP_PORT || 587), secure: env.SMTP_SECURE === 'true', auth: env.SMTP_USER ? { user: env.SMTP_USER, pass: env.SMTP_PASSWORD } : undefined, requireTLS: env.SMTP_SECURE !== 'true', disableFileAccess: true, disableUrlAccess: true, }); } return transporter; } export function applicationOrigin(): string { return (env.APP_ORIGIN || 'http://localhost:5173').replace(/\/+$/, ''); } export function emailDeliveryConfigured(): boolean { return Boolean(env.SMTP_HOST && env.SMTP_FROM); } export async function sendAuthenticationLink( email: string, token: string, purpose: 'login' | 'verify_email', ): Promise { const url = `${applicationOrigin()}/auth/magic-link?token=${encodeURIComponent(token)}`; const subject = purpose === 'login' ? 'Sign in to SHD.build' : 'Verify your SHD.build email'; const action = purpose === 'login' ? 'SIGN IN TO SHD.BUILD' : 'VERIFY EMAIL ADDRESS'; await mailer().sendMail({ from: env.SMTP_FROM, to: email, subject, text: `${subject}\n\nOpen this one-time link within 15 minutes:\n${url}\n\nIf you did not request this, you can ignore this message.`, html: `

SHD IDENTITY NETWORK

${subject}

This one-time link expires in 15 minutes.

${action}

If you did not request this, you can ignore this message.

`, }); } export async function sendNotificationEmail( email: string, title: string, body: string, link: string | null, ): Promise { const url = link ? `${applicationOrigin()}${link.startsWith('/') ? link : `/${link}`}` : `${applicationOrigin()}/account/notifications`; await mailer().sendMail({ from: env.SMTP_FROM, to: email, subject: `${title} — SHD.build`, text: `${title}\n\n${body}\n\nOpen SHD.build: ${url}`, html: `

SHD NOTIFICATION NETWORK

${escapeHtml(title)}

${escapeHtml(body)}

OPEN SHD INBOX

`, }); } function escapeHtml(value: string) { return value.replace( /[&<>"']/g, (character) => ({ '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' })[ character ]!, ); }