ERP-node/backend-node/src/controllers/mailSendSimpleController.ts

154 lines
4.8 KiB
TypeScript
Raw Normal View History

2025-10-01 16:15:53 +09:00
import { Request, Response } from 'express';
import { mailSendSimpleService } from '../services/mailSendSimpleService';
export class MailSendSimpleController {
/**
* ( ) -
2025-10-01 16:15:53 +09:00
*/
async sendMail(req: Request, res: Response) {
try {
console.log('📧 메일 발송 요청 수신:', {
accountId: req.body.accountId,
to: req.body.to,
cc: req.body.cc,
bcc: req.body.bcc,
subject: req.body.subject,
attachments: req.files ? (req.files as Express.Multer.File[]).length : 0,
});
// FormData에서 JSON 문자열 파싱
const accountId = req.body.accountId;
const templateId = req.body.templateId;
const to = req.body.to ? JSON.parse(req.body.to) : [];
const cc = req.body.cc ? JSON.parse(req.body.cc) : undefined;
const bcc = req.body.bcc ? JSON.parse(req.body.bcc) : undefined;
const subject = req.body.subject;
const variables = req.body.variables ? JSON.parse(req.body.variables) : undefined;
const customHtml = req.body.customHtml;
2025-10-01 16:15:53 +09:00
// 필수 파라미터 검증
if (!accountId || !to || !Array.isArray(to) || to.length === 0) {
2025-10-02 15:46:23 +09:00
console.log('❌ 필수 파라미터 누락');
2025-10-01 16:15:53 +09:00
return res.status(400).json({
success: false,
message: '계정 ID와 수신자 이메일이 필요합니다.',
});
}
if (!subject) {
return res.status(400).json({
success: false,
message: '메일 제목이 필요합니다.',
});
}
// 템플릿 또는 커스텀 HTML 중 하나는 있어야 함
if (!templateId && !customHtml) {
return res.status(400).json({
success: false,
message: '템플릿 또는 메일 내용이 필요합니다.',
});
}
// 첨부파일 처리 (한글 파일명 지원)
const attachments: Array<{ filename: string; path: string; contentType?: string }> = [];
if (req.files && Array.isArray(req.files)) {
const files = req.files as Express.Multer.File[];
// 프론트엔드에서 전송한 정규화된 파일명 사용 (한글-분석.txt 방식)
let parsedFileNames: string[] = [];
if (req.body.fileNames) {
try {
parsedFileNames = JSON.parse(req.body.fileNames);
console.log('📎 프론트엔드에서 받은 파일명들:', parsedFileNames);
} catch (e) {
console.warn('파일명 파싱 실패, multer originalname 사용');
}
}
files.forEach((file, index) => {
// 클라이언트에서 전송한 파일명 우선 사용, 없으면 multer의 originalname 사용
let originalName = parsedFileNames[index] || file.originalname;
// NFC 정규화 확실히 수행
originalName = originalName.normalize('NFC');
attachments.push({
filename: originalName,
path: file.path,
contentType: file.mimetype,
});
});
console.log('📎 최종 첨부파일 정보:', attachments.map(a => ({
filename: a.filename,
path: a.path.split('/').pop()
})));
}
2025-10-01 16:15:53 +09:00
// 메일 발송
const result = await mailSendSimpleService.sendMail({
accountId,
templateId,
to,
cc,
bcc,
2025-10-01 16:15:53 +09:00
subject,
variables,
customHtml,
attachments: attachments.length > 0 ? attachments : undefined,
2025-10-01 16:15:53 +09:00
});
if (result.success) {
return res.json({
success: true,
data: result,
message: '메일이 발송되었습니다.',
});
} else {
return res.status(500).json({
success: false,
message: result.error || '메일 발송 실패',
});
}
} catch (error: unknown) {
const err = error as Error;
return res.status(500).json({
success: false,
message: '메일 발송 중 오류가 발생했습니다.',
error: err.message,
});
}
}
/**
* SMTP
*/
async testConnection(req: Request, res: Response) {
try {
const { accountId } = req.body;
if (!accountId) {
return res.status(400).json({
success: false,
message: '계정 ID가 필요합니다.',
});
}
const result = await mailSendSimpleService.testConnection(accountId);
return res.json(result);
} catch (error: unknown) {
const err = error as Error;
return res.status(500).json({
success: false,
message: '연결 테스트 실패',
error: err.message,
});
}
}
}
export const mailSendSimpleController = new MailSendSimpleController();