Email verification Backend

This commit is contained in:
magdo
2025-10-25 01:33:21 +02:00
parent 44645bb3fc
commit f746cfd23f
13 changed files with 843 additions and 101 deletions
@@ -1,6 +1,7 @@
import * as nodemailer from 'nodemailer';
import * as fs from 'fs';
import * as path from 'path';
import sharp from 'sharp';
import { logError, logAuth, logStartup } from './Logger';
import { EmailTemplateHelper, LocalizedSubjects } from './EmailTemplateHelper';
@@ -28,9 +29,14 @@ export class EmailService {
private transporter!: nodemailer.Transporter;
private config: EmailConfig;
private templatesPath: string;
private logoPath: string;
private resizedLogoBuffer?: Buffer;
constructor() {
this.templatesPath = path.join(__dirname, '../../Templates');
this.logoPath = path.join(__dirname, '../../../assets/Logo.png');
// Load logo asynchronously after initialization
this.loadLogoBase64().catch(err => console.error('[EmailService] Error loading logo:', err));
this.config = {
host: process.env.EMAIL_HOST || 'smtp.gmail.com',
@@ -63,6 +69,32 @@ export class EmailService {
}
}
/**
* Load and resize logo for email attachments - 32x32 pixels
*/
private async loadLogoBase64(): Promise<void> {
try {
if (fs.existsSync(this.logoPath)) {
const logoBuffer = fs.readFileSync(this.logoPath);
// Resize to 60x60 pixels with high quality and centered
this.resizedLogoBuffer = await sharp(logoBuffer)
.resize(60, 60, {
fit: 'contain',
background: { r: 255, g: 255, b: 255, alpha: 1 },
position: 'center'
})
.png()
.toBuffer();
console.log(`[EmailService] ✅ Logo loaded and resized to 60x60`);
}
} catch (error) {
console.error(`[EmailService] ❌ Failed to load/resize logo:`, error);
logError('Failed to load logo for emails', error instanceof Error ? error : new Error(String(error)));
}
}
/**
* Send email with template
* @param options - Email options including template and data
@@ -73,19 +105,29 @@ export class EmailService {
let textContent = options.text;
if (options.template) {
const templateResult = await this.loadTemplate(options.template, options.templateData || {});
const templateResult = await this.loadTemplate(options.template, options.templateData);
htmlContent = templateResult.html;
textContent = templateResult.text;
}
const mailOptions = {
const mailOptions: any = {
from: this.config.from,
to: options.to,
subject: options.subject,
html: htmlContent,
text: textContent
text: textContent,
attachments: []
};
// Add logo as CID attachment if available
if (this.resizedLogoBuffer) {
mailOptions.attachments.push({
filename: 'logo.png',
content: this.resizedLogoBuffer,
cid: 'logo@serpentrace' // Content-ID for referencing in HTML
});
}
const result = await this.transporter.sendMail(mailOptions);
logAuth('Email sent successfully', undefined, {
messageId: result.messageId,