import nodemailer from "nodemailer"; const smtpHost = process.env.SMTP_HOST; const smtpPort = parseInt(process.env.SMTP_PORT || "465", 10); const smtpUser = process.env.SMTP_USER; const smtpPassword = process.env.SMTP_PASSWORD; const fromEmail = process.env.SMTP_FROM_EMAIL || smtpUser || "support@aethex.tech"; const verifySupportEmail = process.env.VERIFY_SUPPORT_EMAIL ?? smtpUser ?? "support@aethex.tech"; let transporter: nodemailer.Transporter | null = null; function getTransporter() { if (transporter) return transporter; if (!smtpHost || !smtpUser || !smtpPassword) { throw new Error( "SMTP configuration is missing. Set SMTP_HOST, SMTP_USER, and SMTP_PASSWORD.", ); } transporter = nodemailer.createTransport({ host: smtpHost, port: smtpPort, secure: smtpPort === 465, auth: { user: smtpUser, pass: smtpPassword, }, }); // Verify connection immediately transporter.verify((error, success) => { if (error) { console.error("[Email] SMTP connection verification failed:", { host: smtpHost, port: smtpPort, user: smtpUser, error: error?.message || String(error), }); } else if (success) { console.log("[Email] SMTP connection verified successfully", { host: smtpHost, port: smtpPort, user: smtpUser, }); } }); return transporter; } export const emailService = { get isConfigured() { const configured = Boolean(smtpHost && smtpUser && smtpPassword); if (!configured) { console.warn("[EmailService] Not configured. Env check:", { SMTP_HOST: smtpHost ? "set" : "MISSING", SMTP_USER: smtpUser ? "set" : "MISSING", SMTP_PASSWORD: smtpPassword ? "set" : "MISSING", SMTP_PORT: smtpPort, }); } return configured; }, async sendVerificationEmail(params: { to: string; verificationUrl: string; fullName?: string | null; }) { console.log("[EmailService] sendVerificationEmail called for:", params.to); const transporter = getTransporter(); const { to, verificationUrl, fullName } = params; const safeName = fullName?.trim() || "there"; const subject = "Verify your AeThex account"; const previewText = "Confirm your AeThex account to access the dashboard."; const html = `

Welcome to AeThex, ${safeName}!

Click the button below to verify your account and unlock your personal dashboard.

Verify my account

If the button does not work, paste this link into your browser:

${verificationUrl}


Didn't create an account? Please ignore this email or contact ${verifySupportEmail}.

`; const text = [ `Welcome to AeThex, ${safeName}!`, "", "Use the link below to verify your account:", verificationUrl, "", `If you didn't request this, contact us at ${verifySupportEmail}.`, ].join("\n"); const result = await transporter.sendMail({ from: fromEmail, to, subject, html, text, headers: { "X-AeThex-Email": "verification", "X-Entity-Ref-ID": verificationUrl.slice(-24), }, }); console.log("[EmailService] Verification email sent successfully:", { to, messageId: result.messageId, response: result.response, }); }, async sendInviteEmail(params: { to: string; inviteUrl: string; inviterName?: string | null; message?: string | null; }) { const transporter = getTransporter(); const { to, inviteUrl, inviterName, message } = params; const safeInviter = inviterName?.trim() || "An AeThex member"; const subject = `${safeInviter} invited you to collaborate on AeThex`; const html = `

You're invited to AeThex

${safeInviter} sent you an invitation to connect and collaborate on AeThex.

${message ? `
${message}
` : ""}

Accept invitation

If the button does not work, paste this link into your browser:

${inviteUrl}

`; const text = [ `You're invited to AeThex by ${safeInviter}.`, message ? `\nMessage: ${message}` : "", "\nAccept here:", inviteUrl, ].join("\n"); await transporter.sendMail({ from: fromEmail, to, subject, html, text, headers: { "X-AeThex-Email": "invite" }, }); }, };