import { Injectable, Logger } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import * as nodemailer from 'nodemailer'; import { Transporter } from 'nodemailer'; import { getVerificationEmailTemplate, getPasswordResetTemplate, getWelcomeEmailTemplate, } from './templates'; export interface EmailOptions { to: string; subject: string; html: string; text?: string; } @Injectable() export class EmailService { private readonly logger = new Logger(EmailService.name); private transporter: Transporter; constructor(private readonly configService: ConfigService) { this.createTransporter(); } private createTransporter() { const host = this.configService.get('SMTP_HOST'); const port = this.configService.get('SMTP_PORT'); const user = this.configService.get('SMTP_USER'); const pass = this.configService.get('SMTP_PASS'); if (!host || !user || !pass) { this.logger.warn('SMTP configuration incomplete. Emails will be logged only.'); return; } this.transporter = nodemailer.createTransport({ host, port: port || 465, secure: true, // SSL/TLS auth: { user, pass, }, }); // Verify connection this.transporter.verify((error) => { if (error) { this.logger.error('SMTP connection failed:', error); } else { this.logger.log('SMTP connection established successfully'); } }); } async sendEmail(options: EmailOptions): Promise { const from = this.configService.get('SMTP_FROM') || this.configService.get('SMTP_USER'); if (!this.transporter) { this.logger.warn('No SMTP transporter. Logging email instead:'); this.logger.log(`To: ${options.to}`); this.logger.log(`Subject: ${options.subject}`); this.logger.log(`Body: ${options.text || 'HTML email'}`); return false; } try { const info = await this.transporter.sendMail({ from: `"RE-QuestN" <${from}>`, to: options.to, subject: options.subject, html: options.html, text: options.text, }); this.logger.log(`Email sent successfully: ${info.messageId}`); return true; } catch (error) { this.logger.error(`Failed to send email to ${options.to}:`, error); return false; } } // ========================================== // EMAIL VERIFICATION // ========================================== async sendVerificationEmail(email: string, token: string, name?: string): Promise { const frontendUrl = this.configService.get('FRONTEND_URL') || 'http://localhost:3000'; const verificationUrl = `${frontendUrl}/verify-email?token=${token}`; const html = getVerificationEmailTemplate({ verificationUrl, name }); const text = `Welcome to RE-QuestN! Please verify your email by clicking this link: ${verificationUrl}`; return this.sendEmail({ to: email, subject: 'Verify Your Email - RE-QuestN', html, text, }); } // ========================================== // PASSWORD RESET // ========================================== async sendPasswordResetEmail(email: string, resetUrl: string): Promise { const html = getPasswordResetTemplate({ resetUrl }); const text = `Reset your password by clicking this link: ${resetUrl}. This link will expire in 1 hour.`; return this.sendEmail({ to: email, subject: 'Reset Your Password - RE-QuestN', html, text, }); } // ========================================== // WELCOME EMAIL // ========================================== async sendWelcomeEmail(email: string, name?: string): Promise { const frontendUrl = this.configService.get('FRONTEND_URL') || 'http://localhost:3000'; const html = getWelcomeEmailTemplate({ name, frontendUrl }); const text = `Welcome to RE-QuestN, ${name || 'User'}! Your real estate journey starts now.`; return this.sendEmail({ to: email, subject: 'Welcome to RE-QuestN!', html, text, }); } }