Files
vexplor/backend-node/src/services/userMailSmtpService.ts

64 lines
2.1 KiB
TypeScript
Raw Normal View History

import nodemailer from 'nodemailer';
import { encryptionService } from './encryptionService';
import { UserMailAccount } from './userMailAccountService';
export interface SendMailDto {
to: string;
cc?: string;
subject: string;
html: string;
text?: string;
inReplyTo?: string;
references?: string;
}
class UserMailSmtpService {
private getSmtpConfig(account: UserMailAccount) {
const decryptedPassword = encryptionService.decrypt(account.password);
// IMAP host에서 SMTP host 추론
const smtpHost = account.host
.replace(/^imap\./, 'smtp.')
.replace(/^mail\./, 'smtp.');
// 포트 추론: TLS → 465, plain → 587
const port = account.useTls ? 465 : 587;
return {
host: smtpHost,
port,
secure: account.useTls, // 465: true, 587: false (STARTTLS)
auth: { user: account.username, pass: decryptedPassword },
tls: { rejectUnauthorized: false },
};
}
async sendMail(account: UserMailAccount, dto: SendMailDto): Promise<{ success: boolean; message: string }> {
try {
const transporter = nodemailer.createTransport(this.getSmtpConfig(account));
await transporter.sendMail({
from: `${account.displayName} <${account.email}>`,
to: dto.to,
cc: dto.cc,
subject: dto.subject,
html: dto.html,
text: dto.text,
inReplyTo: dto.inReplyTo,
references: dto.references,
});
return { success: true, message: '발송 완료' };
} catch (err) {
return { success: false, message: err instanceof Error ? err.message : '발송 실패' };
}
}
async testSmtpConnection(account: UserMailAccount): Promise<{ success: boolean; message: string }> {
try {
const transporter = nodemailer.createTransport(this.getSmtpConfig(account));
await transporter.verify();
return { success: true, message: 'SMTP 연결 성공' };
} catch (err) {
return { success: false, message: err instanceof Error ? err.message : 'SMTP 연결 실패' };
}
}
}
export const userMailSmtpService = new UserMailSmtpService();