diff options
| author | JustZvan <justzvan@justzvan.xyz> | 2026-02-06 12:16:40 +0100 |
|---|---|---|
| committer | JustZvan <justzvan@justzvan.xyz> | 2026-02-06 12:16:40 +0100 |
| commit | e904e9634548e47d611bdcbb88d7b180b927fd5f (patch) | |
| tree | 21aa5be08fc5b22585508c0263ee5ea4effcc593 /src/email | |
feat: initial commit!
Diffstat (limited to 'src/email')
| -rw-r--r-- | src/email/confirm.ts | 75 | ||||
| -rw-r--r-- | src/email/email.ts | 66 |
2 files changed, 141 insertions, 0 deletions
diff --git a/src/email/confirm.ts b/src/email/confirm.ts new file mode 100644 index 0000000..b885438 --- /dev/null +++ b/src/email/confirm.ts @@ -0,0 +1,75 @@ +/** Generates the HTML template for email verification messages */ +export function verificationEmailHtml(verificationCode: string): string { + return ` +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8" /> + <meta name="viewport" content="width=device-width, initial-scale=1.0" /> + <title>Buddy Email Verification</title> +</head> +<body style="margin:0; padding:0; background-color:#eef2f7; font-family:Arial, Helvetica, sans-serif;"> + <table width="100%" cellpadding="0" cellspacing="0" role="presentation" style="background-color:#eef2f7; padding:24px 0;"> + <tr> + <td align="center"> + <table width="600" cellpadding="0" cellspacing="0" role="presentation" style="background-color:#ffffff; border-radius:14px; overflow:hidden; box-shadow:0 10px 25px rgba(0,0,0,0.05);"> + + <!-- Header --> + <tr> + <td style="padding:28px; text-align:center; background-color:#f42e2e;"> + <h1 style="margin:0; font-size:24px; color:#ffffff;"> + 🐶 Buddy + </h1> + <p style="margin:8px 0 0 0; font-size:14px; color:#dbeafe;"> + Verification code + </p> + </td> + </tr> + + <!-- Content --> + <tr> + <td style="padding:36px; color:#111827;"> + <p style="margin:0 0 20px 0; font-size:16px; line-height:1.6;"> + Enter this code to verify your account: + </p> + + <div style="margin:32px 0; text-align:center;"> + <span style=" + display:inline-block; + font-size:30px; + letter-spacing:6px; + font-weight:700; + padding:18px 26px; + border-radius:10px; + color:black; + border:2px dashed #f42e2e; + "> + ${verificationCode} + </span> + </div> + + <p style="margin:0 0 16px 0; font-size:14px; line-height:1.6; color:#374151;"> + Code expires soon. Didn't request this? Ignore it. + </p> + + <p style="margin:0; font-size:14px; color:#6b7280;"> + Buddy Team + </p> + </td> + </tr> + + <!-- Footer --> + <tr> + <td style="background-color:#f8fafc; padding:18px; text-align:center; font-size:12px; color:#9ca3af;"> + © ${new Date().getFullYear()} Buddy + </td> + </tr> + + </table> + </td> + </tr> + </table> +</body> +</html> +`; +} diff --git a/src/email/email.ts b/src/email/email.ts new file mode 100644 index 0000000..61ec18a --- /dev/null +++ b/src/email/email.ts @@ -0,0 +1,66 @@ +import nodemailer from "nodemailer"; +import { logger } from "../lib/pino"; + +let transporter: nodemailer.Transporter | null = null; + +/** + * Gets or creates the nodemailer transporter instance. + * Configuration is loaded from SMTP environment variables. + */ +export function getTransporter(): nodemailer.Transporter { + if (!transporter) { + try { + if (!process.env.SMTP_HOST) { + logger.error("SMTP_HOST environment variable not set"); + throw new Error("SMTP_HOST is required"); + } + + if (!process.env.SMTP_PORT) { + logger.error("SMTP_PORT environment variable not set"); + throw new Error("SMTP_PORT is required"); + } + + if (!process.env.SMTP_USER) { + logger.error("SMTP_USER environment variable not set"); + throw new Error("SMTP_USER is required"); + } + + if (!process.env.SMTP_PASS) { + logger.error("SMTP_PASS environment variable not set"); + throw new Error("SMTP_PASS is required"); + } + + const port = Number(process.env.SMTP_PORT); + if (isNaN(port) || port <= 0 || port > 65535) { + logger.error( + { port: process.env.SMTP_PORT }, + "Invalid SMTP_PORT value", + ); + throw new Error("SMTP_PORT must be a valid port number"); + } + + transporter = nodemailer.createTransport({ + host: process.env.SMTP_HOST, + port, + secure: process.env.SMTP_SECURE == "1", + auth: { + user: process.env.SMTP_USER, + pass: process.env.SMTP_PASS, + }, + }); + + logger.info( + { + host: process.env.SMTP_HOST, + port, + secure: process.env.SMTP_SECURE == "1", + }, + "Email transporter created successfully", + ); + } catch (error) { + logger.error({ error }, "Failed to create email transporter"); + throw error; + } + } + return transporter; +} |