Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x 1x | import nodemailer from 'nodemailer'
import type { Transporter } from 'nodemailer'
let _transport: Transporter | null = null
/**
* Lazily initialised Nodemailer transport — reuses the EMAIL_SERVER
* connection string already configured for NextAuth magic links.
*/
function ensureTransport(): Transporter {
if (_transport) return _transport
const server = process.env.EMAIL_SERVER
if (!server) {
throw new Error('[email] EMAIL_SERVER is not set')
}
_transport = nodemailer.createTransport(server)
return _transport
}
export interface SendEmailParams {
to: string
subject: string
html: string
from?: string
replyTo?: string
}
/**
* Send an email using the shared Nodemailer transport.
*
* Uses EMAIL_FROM as the default sender. Callers can override
* `from` and `replyTo` for channel-specific customisation.
*/
export async function sendEmail(params: SendEmailParams): Promise<void> {
const transport = ensureTransport()
const defaultFrom = process.env.EMAIL_FROM ?? 'Abaci One <hallock@gmail.com>'
await transport.sendMail({
from: params.from ?? defaultFrom,
to: params.to,
subject: params.subject,
html: params.html,
replyTo: params.replyTo,
})
}
/**
* Reset transport (for testing).
*/
export function _resetEmailTransport(): void {
_transport = null
}
|