import { createTransport, type Transporter } from "nodemailer"; import { logger } from "./logger.server.ts"; const FROM = process.env.SMTP_FROM ?? "trails.cool "; let transporter: Transporter | null = null; function getTransporter(): Transporter { if (!transporter) { const url = process.env.SMTP_URL; if (!url) throw new Error("SMTP_URL is not set"); transporter = createTransport(url); } return transporter; } export async function sendEmail( to: string, subject: string, html: string, text: string, ): Promise { if (process.env.NODE_ENV !== "production") { logger.info({ to, subject }, "Email sent (dev mode — logged, not delivered)"); logger.debug({ text }, "Email text content"); return; } await getTransporter().sendMail({ from: FROM, to, subject, html, text }); } // --- Templates --- export function magicLinkTemplate(link: string, code?: string): { html: string; text: string } { const codeSection = code ? `

Or enter this code on the login page:

${code}
` : ""; const html = `

Sign in to trails.cool

Click the button below to sign in to your account. This link expires in 15 minutes.

Sign In ${codeSection}

If the button doesn't work, copy and paste this link:
${link}


If you didn't request this link, you can safely ignore this email.

`.trim(); const codeText = code ? `\nOr enter this code: ${code}\n` : ""; const text = [ "Sign in to trails.cool", "", `Click here to sign in: ${link}`, codeText, "This link expires in 15 minutes.", "", "If you didn't request this link, you can safely ignore this email.", ].join("\n"); return { html, text }; } export function welcomeTemplate(username: string): { html: string; text: string } { const html = `

Welcome to trails.cool, ${username}!

Your account is ready. Here's what you can do:

  • Save and manage your routes
  • Track outdoor activities
  • Plan routes collaboratively in the Planner
  • Export routes as GPX for any GPS device
View Your Routes

trails.cool — Your outdoor activity journal

`.trim(); const text = [ `Welcome to trails.cool, ${username}!`, "", "Your account is ready. Here's what you can do:", "- Save and manage your routes", "- Track outdoor activities", "- Plan routes collaboratively in the Planner", "- Export routes as GPX for any GPS device", "", "View your routes: https://trails.cool/routes", ].join("\n"); return { html, text }; } // --- Convenience wrappers --- export async function sendMagicLink(email: string, link: string, code?: string): Promise { const { html, text } = magicLinkTemplate(link, code); await sendEmail(email, "Sign in to trails.cool", html, text); } export async function sendWelcome(email: string, username: string): Promise { const { html, text } = welcomeTemplate(username); await sendEmail(email, "Welcome to trails.cool!", html, text); }