import nodemailer from 'nodemailer'; import db from '../db.js'; let transporter = null; export function getEmailConfig() { return db.prepare('SELECT * FROM email_config WHERE id = 1').get(); } export async function initTransporter() { const config = getEmailConfig(); if (!config) return null; try { transporter = nodemailer.createTransport({ host: config.smtp_host, port: config.smtp_port, secure: config.smtp_port === 465, auth: { user: config.email, pass: config.app_password, }, }); await transporter.verify(); return true; } catch (err) { console.error('Email transporter init failed:', err.message); transporter = null; return false; } } export async function testConnection(host, port, email, password) { const t = nodemailer.createTransport({ host, port, secure: port === 465, auth: { user: email, pass: password }, }); await t.verify(); await t.close(); } export async function sendMail({ to, subject, html, replyTo, inReplyTo, references }) { if (!transporter) await initTransporter(); if (!transporter) throw new Error('Email not configured'); const config = getEmailConfig(); const msg = { from: `"TeamFlow" <${config.email}>`, to, subject, html, headers: {}, }; if (replyTo) msg.replyTo = replyTo; if (inReplyTo) msg.headers['In-Reply-To'] = inReplyTo; if (references) msg.headers.References = references; const info = await transporter.sendMail(msg); db.prepare(`INSERT INTO email_log (from_email, to_email, subject, direction, status, message_id) VALUES (?, ?, ?, 'sent', 'sent', ?)`) .run(config.email, to, subject, info.messageId); return info; } export function buildCardUrl(cardId, boardId) { const origin = process.env.APP_URL || 'http://localhost:5173'; return `${origin}/board/${boardId}?card=${cardId}`; } export function buildCardNotificationHtml({ userName, boardTitle, cardTitle, action, cardUrl, comment }) { const actionMessages = { assigned: `assigned you to a card`, commented: `commented on a card`, moved: `moved a card`, mentioned: `mentioned you in a comment`, due_soon: `has a due date coming up`, }; return `
${userName} ${actionMessages[action] || action}