const nodemailer = require("nodemailer"); const { env } = require("../config/env"); const logger = require("./logger"); let transporter = null; function getTransporter() { if (transporter) return transporter; transporter = nodemailer.createTransport({ host: env.smtp.host, port: env.smtp.port, secure: env.smtp.secure, // true for 465, false for other ports (STARTTLS) auth: env.smtp.user ? { user: env.smtp.user, pass: env.smtp.pass } : undefined, requireTLS: !env.smtp.secure, // enforce STARTTLS when not already on a TLS port }); return transporter; } async function sendMail({ to, subject, html, text }) { try { const info = await getTransporter().sendMail({ from: env.emailFrom, to, subject, html, text, }); return info; } catch (err) { // Email failures must never crash a request or leak SMTP credentials. logger.error("Failed to send email", { subject, error: err.message }); return null; } } function baseLayout(bodyHtml) { return `
| Bank name | ${bankDetails.name} |
| Account name | ${bankDetails.accountName} |
| Account number | ${bankDetails.accountNumber} |
| Routing number | ${bankDetails.routingNumber} |
| SWIFT/BIC | ${bankDetails.swiftBic} |
| Bank address | ${bankDetails.address} |
Please use order number ${order.orderNumber} as your payment reference.
` : `Send payment to Payoneer account ${payoneerDetails.accountEmail} or use your Payoneer app's "Request a Payment" link: ${payoneerDetails.paymentUrl}.
Please use order number ${order.orderNumber} as your payment note.
`; const html = baseLayout(`Hi ${name},
Thanks for enrolling in ${courseTitle}. Your order has been created and is awaiting payment${order.status === "awaiting_confirmation" ? " confirmation" : ""}.
Order number: ${order.orderNumber}
Amount due: ${order.currency} ${order.amount.toFixed(2)}
Payment method: ${order.paymentMethod === "bank_wire" ? "Bank wire transfer" : "Payoneer"}
Once our team confirms your payment, you'll receive a separate email and full course access will be unlocked automatically on your account.
`); return sendMail({ to, subject: `Your Aynwerd order ${order.orderNumber} — payment instructions`, html, text: `Order ${order.orderNumber} created for ${courseTitle}. Amount due: ${order.currency} ${order.amount.toFixed(2)}.`, }); } async function sendPaymentConfirmedEmail({ to, name, order, courseTitle }) { const html = baseLayout(`Hi ${name},
Great news — we've confirmed your payment for ${courseTitle}.
Order number: ${order.orderNumber}
Amount paid: ${order.currency} ${order.amount.toFixed(2)}
Confirmed on: ${new Date(order.confirmedAt).toUTCString()}
Full access to the course has been unlocked on your account. Log in any time to get started.
`); return sendMail({ to, subject: `Payment confirmed — order ${order.orderNumber}`, html, text: `Payment confirmed for order ${order.orderNumber}. Course access unlocked.`, }); } async function sendVoucherRedeemedEmail({ to, name, order, courseTitle, voucherCode }) { const html = baseLayout(`Hi ${name},
Your voucher ${voucherCode} has been redeemed for ${courseTitle} — no payment was required.
Order number: ${order.orderNumber}
Full access to the course has been unlocked on your account. Log in any time to get started.
`); return sendMail({ to, subject: `Voucher redeemed — ${courseTitle} unlocked`, html, text: `Voucher ${voucherCode} redeemed for ${courseTitle}. Course access unlocked. Order ${order.orderNumber}.`, }); } async function sendPaymentRejectedEmail({ to, name, order, courseTitle, reason }) { const html = baseLayout(`Hi ${name},
We were unable to confirm your payment for ${courseTitle} (order ${order.orderNumber}).
${reason ? `Reason: ${reason}
` : ""}Please reply to this email or contact support so we can help resolve this.
`); return sendMail({ to, subject: `Action needed on order ${order.orderNumber}`, html, text: `We could not confirm payment for order ${order.orderNumber}.${reason ? ` Reason: ${reason}` : ""}`, }); } async function sendAdminNewOrderAlert({ order, courseTitle, customerEmail }) { if (!env.adminNotifyEmail) return null; const html = baseLayout(`New order awaiting confirmation.
Order: ${order.orderNumber}
Customer: ${customerEmail}
Course: ${courseTitle}
Amount: ${order.currency} ${order.amount.toFixed(2)}
Method: ${order.paymentMethod}
Review and confirm it from the admin dashboard.
`); return sendMail({ to: env.adminNotifyEmail, subject: `New order ${order.orderNumber} awaiting confirmation`, html, }); } module.exports = { sendOrderPlacedEmail, sendPaymentConfirmedEmail, sendVoucherRedeemedEmail, sendPaymentRejectedEmail, sendAdminNewOrderAlert, };