import nodemailer from 'nodemailer'; import type { Account, EmailCtx } from './imap.js'; import type { EmailCredentials } from './multitenancy/credential-store.js'; const FETCHERPAY_SMTP_HOST = process.env['FETCHERPAY_SMTP_HOST'] ?? 'mail.fetcherpay.com'; const FETCHERPAY_SMTP_PORT = parseInt(process.env['FETCHERPAY_SMTP_PORT'] ?? '30587'); const SQCP_SMTP_HOST = process.env['SQCP_SMTP_HOST'] ?? 'smtp.azurecomm.net'; const SQCP_SMTP_PORT = parseInt(process.env['SQCP_SMTP_PORT'] ?? '587'); const SQCP_SMTP_USER = process.env['SQCP_SMTP_USER'] ?? ''; const SQCP_SMTP_PASS = process.env['SQCP_SMTP_PASS'] ?? ''; function fetcherpaySmtpTransport(user: string, pass: string) { return nodemailer.createTransport({ host: FETCHERPAY_SMTP_HOST, port: FETCHERPAY_SMTP_PORT, secure: false, auth: { user, pass }, tls: { rejectUnauthorized: false }, }); } function sqcpSmtpTransport() { return nodemailer.createTransport({ host: SQCP_SMTP_HOST, port: SQCP_SMTP_PORT, secure: false, auth: { user: SQCP_SMTP_USER, pass: SQCP_SMTP_PASS }, tls: { rejectUnauthorized: false }, }); } function getEnvSmtpTransport(account: Account = 'yahoo') { switch (account) { case 'fetcherpay': return fetcherpaySmtpTransport(process.env['FETCHERPAY_EMAIL']!, process.env['FETCHERPAY_PASSWORD']!); case 'garfield': return fetcherpaySmtpTransport(process.env['GARFIELD_EMAIL']!, process.env['GARFIELD_PASSWORD']!); case 'sales': return fetcherpaySmtpTransport(process.env['SALES_EMAIL']!, process.env['SALES_PASSWORD']!); case 'leads': return fetcherpaySmtpTransport(process.env['LEADS_EMAIL']!, process.env['LEADS_PASSWORD']!); case 'founder': return fetcherpaySmtpTransport(process.env['FOUNDER_EMAIL']!, process.env['FOUNDER_PASSWORD']!); case 'sqcp_garfield': return sqcpSmtpTransport(); case 'sqcp_info': return sqcpSmtpTransport(); case 'sqcp_sales': return sqcpSmtpTransport(); case 'sqcp_support': return sqcpSmtpTransport(); case 'sqcp_founder': return sqcpSmtpTransport(); case 'sqcp_contact': return sqcpSmtpTransport(); case 'sqcp_admin': return sqcpSmtpTransport(); case 'gmail': return nodemailer.createTransport({ host: 'smtp.gmail.com', port: 587, secure: false, auth: { user: process.env['GMAIL_EMAIL']!, pass: process.env['GMAIL_APP_PASSWORD']! }, }); default: return nodemailer.createTransport({ host: 'smtp.mail.yahoo.com', port: 587, secure: false, auth: { user: process.env['YAHOO_EMAIL']!, pass: process.env['YAHOO_APP_PASSWORD']! }, }); } } function resolveSmtpTransport(ctx: EmailCtx) { if (typeof ctx === 'object') { return nodemailer.createTransport({ host: ctx.smtpHost ?? ctx.host, port: ctx.smtpPort ?? 587, secure: false, auth: { user: ctx.user, pass: ctx.password }, tls: { rejectUnauthorized: false }, }); } return getEnvSmtpTransport(ctx); } function resolveSenderEmail(ctx: EmailCtx): string { if (typeof ctx === 'object') return ctx.user; const emailMap: Record = { yahoo: process.env['YAHOO_EMAIL'] ?? '', fetcherpay: process.env['FETCHERPAY_EMAIL'] ?? '', garfield: process.env['GARFIELD_EMAIL'] ?? '', sales: process.env['SALES_EMAIL'] ?? '', leads: process.env['LEADS_EMAIL'] ?? '', founder: process.env['FOUNDER_EMAIL'] ?? '', gmail: process.env['GMAIL_EMAIL'] ?? '', sqcp_garfield: process.env['SQCP_GARFIELD_EMAIL'] ?? '', sqcp_info: process.env['SQCP_INFO_EMAIL'] ?? '', sqcp_sales: process.env['SQCP_SALES_EMAIL'] ?? '', sqcp_support: process.env['SQCP_SUPPORT_EMAIL'] ?? '', sqcp_founder: process.env['SQCP_FOUNDER_EMAIL'] ?? '', sqcp_contact: process.env['SQCP_CONTACT_EMAIL'] ?? '', sqcp_admin: process.env['SQCP_ADMIN_EMAIL'] ?? '', }; return emailMap[ctx] ?? ''; } export async function sendEmail( to: string, subject: string, body: string, ctx: EmailCtx = 'yahoo', ): Promise { const transporter = resolveSmtpTransport(ctx); const info = await transporter.sendMail({ from: resolveSenderEmail(ctx), to, subject, text: body, }); return info.messageId; } export async function createDraft( to: string, subject: string, body: string, ctx: EmailCtx = 'yahoo', ): Promise { const { ImapFlow } = await import('imapflow'); let imapConfig: any; if (typeof ctx === 'object') { imapConfig = { host: ctx.host, port: ctx.port, secure: ctx.port === 993, auth: { user: ctx.user, pass: ctx.password }, tls: { rejectUnauthorized: false }, }; } else { const fetcherpayImapBase = { host: process.env['FETCHERPAY_IMAP_HOST'] ?? 'mail.fetcherpay.com', port: parseInt(process.env['FETCHERPAY_IMAP_PORT'] ?? '30993'), secure: true, tls: { rejectUnauthorized: false }, }; const fetcherpayAccounts: Partial> = { fetcherpay: { user: process.env['FETCHERPAY_EMAIL']!, pass: process.env['FETCHERPAY_PASSWORD']! }, garfield: { user: process.env['GARFIELD_EMAIL']!, pass: process.env['GARFIELD_PASSWORD']! }, sales: { user: process.env['SALES_EMAIL']!, pass: process.env['SALES_PASSWORD']! }, leads: { user: process.env['LEADS_EMAIL']!, pass: process.env['LEADS_PASSWORD']! }, founder: { user: process.env['FOUNDER_EMAIL']!, pass: process.env['FOUNDER_PASSWORD']! }, }; if (fetcherpayAccounts[ctx]) { imapConfig = { ...fetcherpayImapBase, auth: fetcherpayAccounts[ctx]! }; } else if (ctx === 'gmail') { imapConfig = { host: 'imap.gmail.com', port: 993, secure: true, auth: { user: process.env['GMAIL_EMAIL']!, pass: process.env['GMAIL_APP_PASSWORD']! }, }; } else { imapConfig = { host: 'imap.mail.yahoo.com', port: 993, secure: true, auth: { user: process.env['YAHOO_EMAIL']!, pass: process.env['YAHOO_APP_PASSWORD']! }, }; } } const client = new ImapFlow(imapConfig); await client.connect(); const from = resolveSenderEmail(ctx); const rawMessage = [ `From: ${from}`, `To: ${to}`, `Subject: ${subject}`, `MIME-Version: 1.0`, `Content-Type: text/plain; charset=UTF-8`, ``, body, ].join('\r\n'); await client.append('Drafts', Buffer.from(rawMessage), ['\\Draft', '\\Seen']); await client.logout(); return `Draft created: "${subject}" to ${to}`; }