import nodemailer from 'nodemailer' import type { Config } from './config.ts' export interface Mail { to: string subject: string text: string } export interface Mailer { send(mail: Mail): Promise } export function createMailer(config: Config): Mailer { if (config.smtpUrl) { const transport = nodemailer.createTransport(config.smtpUrl) return { send: async (mail) => void (await transport.sendMail({ from: config.mailFrom, ...mail })) } } if (config.production) { console.warn('[mail] SMTP_URL is not set: emails (sign-in links, password resets, notifications) will not be sent.') return { send: async (mail) => console.warn(`[mail] Not sent (no SMTP): "${mail.subject}" to ${mail.to}`) } } // Development: print the email so links can be clicked from the terminal. return { send: async (mail) => console.log(`\n[mail] To: ${mail.to}\n[mail] Subject: ${mail.subject}\n\n${mail.text}\n`) } } /** Collects emails instead of sending them (tests). */ export class MemoryMailer implements Mailer { sent: Mail[] = [] async send(mail: Mail) { this.sent.push(mail) } /** Most recent email to `to`. */ last(to: string): Mail | undefined { return this.sent.findLast((mail) => mail.to === to) } }