```typescript
import nodemailer from "nodemailer";
// ============================================
// Configuration
// ============================================
const transporter = nodemailer.createTransport({
host: process.env.SMTP_HOST || "smtp.example.com",
port: parseInt(process.env.SMTP_PORT || "587"),
secure: process.env.SMTP_SECURE === "true", // true for 465, false for other ports
auth: {
user: process.env.SMTP_USER,
pass: process.env.SMTP_PASS,
},
});
// ============================================
// Templates (Simple)
// ============================================
const templates = {
welcome: (name: string) => ({
subject: "Welcome to MyApp!",
html: `
<h1>Welcome, ${name}!</h1>
<p>We're excited to have you on board.</p>
<p>Click <a href="${process.env.DOMAIN}/dashboard">here</a> to get started.</p>
`,
text: `Welcome, ${name}!\nWe're excited to have you on board.\nGo to ${process.env.DOMAIN}/dashboard to get started.`,
}),
resetPassword: (token: string) => ({
subject: "Reset your password",
html: `
<h1>Reset Password</h1>
<p>Click the link below to reset your password:</p>
<p><a href="${process.env.DOMAIN}/reset-password?token=${token}">Reset Password</a></p>
<p>If you didn't request this, please ignore this email.</p>
`,
text: `Reset Password\nClick the link: ${process.env.DOMAIN}/reset-password?token=${token}\nIf you didn't request this, ignore this email.`,
}),
};
// ============================================
// Service
// ============================================
export const emailService = {
async sendEmail(to: string, subject: string, html: string, text?: string) {
try {
const info = await transporter.sendMail({
from: `"${process.env.FROM_NAME}" <${process.env.FROM_EMAIL}>`,
to,
subject,
html,
text: text || html.replace(/<[^>]*>?/gm, ""), // fallback strip tags
});
console.log(`Email sent: ${info.messageId}`);
return { success: true, messageId: info.messageId };
} catch (error) {
console.error("Error sending email:", error);
throw error;
}
},
async sendWelcome(to: string, name: string) {
const { subject, html, text } = templates.welcome(name);
return this.sendEmail(to, subject, html, text);
},
async sendPasswordReset(to: string, token: string) {
const { subject, html, text } = templates.resetPassword(token);
return this.sendEmail(to, subject, html, text);
},
// Validates connection at startup
async verifyConnection() {
try {
await transporter.verify();
console.log("✅ SMTP connection established");
return true;
} catch (error) {
console.error("❌ SMTP connection failed:", error);
return false;
}
},
};
/*
// For dev env (using Ethereal Email):
if (process.env.NODE_ENV !== 'production') {
nodemailer.createTestAccount().then((account) => {
// ... update config using account.user/pass
});
}
*/
```