- Domain: NotificationLog/NotificationPreference entities, repositories, channel value object - Infrastructure: EmailService (nodemailer/SMTP), FcmService (firebase-admin), TemplateService (Handlebars) - Application: SendNotification CQRS command, UserRegistered + AgentVerified event listeners - Presentation: NotificationsController with history, preferences, and templates endpoints - Prisma: NotificationLog and NotificationPreference models with proper indexes - Templates: Vietnamese notification templates for user.registered, agent.verified, listing.approved, inquiry.received, password.reset Co-Authored-By: Paperclip <noreply@paperclip.ing>
64 lines
1.7 KiB
TypeScript
64 lines
1.7 KiB
TypeScript
import { Injectable, type OnModuleInit } from '@nestjs/common';
|
|
import { LoggerService } from '@modules/shared/infrastructure/logger.service';
|
|
import * as nodemailer from 'nodemailer';
|
|
|
|
export interface SendEmailDto {
|
|
to: string;
|
|
subject: string;
|
|
html: string;
|
|
}
|
|
|
|
@Injectable()
|
|
export class EmailService implements OnModuleInit {
|
|
private transporter!: nodemailer.Transporter;
|
|
|
|
constructor(private readonly logger: LoggerService) {}
|
|
|
|
onModuleInit(): void {
|
|
const host = process.env['SMTP_HOST'] ?? 'localhost';
|
|
const port = Number(process.env['SMTP_PORT'] ?? '1025');
|
|
const user = process.env['SMTP_USER'];
|
|
const pass = process.env['SMTP_PASS'];
|
|
|
|
this.transporter = nodemailer.createTransport({
|
|
host,
|
|
port,
|
|
secure: port === 465,
|
|
...(user && pass ? { auth: { user, pass } } : {}),
|
|
});
|
|
|
|
this.logger.log(`Email transport configured: ${host}:${port}`, 'EmailService');
|
|
}
|
|
|
|
async send(dto: SendEmailDto): Promise<{ messageId: string }> {
|
|
const from = process.env['SMTP_FROM'] ?? 'noreply@goodgo.vn';
|
|
|
|
try {
|
|
const info = await this.transporter.sendMail({
|
|
from,
|
|
to: dto.to,
|
|
subject: dto.subject,
|
|
html: dto.html,
|
|
});
|
|
|
|
this.logger.log(`Email sent to ${dto.to}: ${info.messageId}`, 'EmailService');
|
|
return { messageId: info.messageId };
|
|
} catch (error) {
|
|
this.logger.error(
|
|
`Failed to send email to ${dto.to}: ${error instanceof Error ? error.message : String(error)}`,
|
|
'EmailService',
|
|
);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async verify(): Promise<boolean> {
|
|
try {
|
|
await this.transporter.verify();
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
}
|