diff --git a/backend-node/src/controllers/mailAccountFileController.ts b/backend-node/src/controllers/mailAccountFileController.ts index 702a5dd4..668dedf3 100644 --- a/backend-node/src/controllers/mailAccountFileController.ts +++ b/backend-node/src/controllers/mailAccountFileController.ts @@ -178,14 +178,19 @@ export class MailAccountFileController { try { const { id } = req.params; - // TODO: 실제 SMTP 연결 테스트 구현 - // const account = await mailAccountFileService.getAccountById(id); - // nodemailer로 연결 테스트 + const account = await mailAccountFileService.getAccountById(id); + if (!account) { + return res.status(404).json({ + success: false, + message: '계정을 찾을 수 없습니다.', + }); + } - return res.json({ - success: true, - message: '연결 테스트 성공 (미구현)', - }); + // mailSendSimpleService의 testConnection 사용 + const { mailSendSimpleService } = require('../services/mailSendSimpleService'); + const result = await mailSendSimpleService.testConnection(id); + + return res.json(result); } catch (error: unknown) { const err = error as Error; return res.status(500).json({ diff --git a/backend-node/src/controllers/mailSendSimpleController.ts b/backend-node/src/controllers/mailSendSimpleController.ts index cbd9b647..15a1bea0 100644 --- a/backend-node/src/controllers/mailSendSimpleController.ts +++ b/backend-node/src/controllers/mailSendSimpleController.ts @@ -7,10 +7,12 @@ export class MailSendSimpleController { */ async sendMail(req: Request, res: Response) { try { + console.log('📧 메일 발송 요청 수신:', { accountId: req.body.accountId, to: req.body.to, subject: req.body.subject }); const { accountId, templateId, to, subject, variables, customHtml } = req.body; // 필수 파라미터 검증 if (!accountId || !to || !Array.isArray(to) || to.length === 0) { + console.log('❌ 필수 파라미터 누락'); return res.status(400).json({ success: false, message: '계정 ID와 수신자 이메일이 필요합니다.', diff --git a/backend-node/src/services/mailSendSimpleService.ts b/backend-node/src/services/mailSendSimpleService.ts index c5d2fc4f..473f3959 100644 --- a/backend-node/src/services/mailSendSimpleService.ts +++ b/backend-node/src/services/mailSendSimpleService.ts @@ -6,6 +6,7 @@ import nodemailer from 'nodemailer'; import { mailAccountFileService } from './mailAccountFileService'; import { mailTemplateFileService } from './mailTemplateFileService'; +import { encryptionService } from './encryptionService'; export interface SendMailRequest { accountId: string; @@ -56,18 +57,39 @@ class MailSendSimpleService { throw new Error('메일 내용이 없습니다.'); } - // 4. SMTP 연결 생성 + // 4. 비밀번호 복호화 + const decryptedPassword = encryptionService.decrypt(account.smtpPassword); + console.log('🔐 비밀번호 복호화 완료'); + console.log('🔐 암호화된 비밀번호 (일부):', account.smtpPassword.substring(0, 30) + '...'); + console.log('🔐 복호화된 비밀번호 길이:', decryptedPassword.length); + + // 5. SMTP 연결 생성 + // 포트 465는 SSL/TLS를 사용해야 함 + const isSecure = account.smtpPort === 465 ? true : (account.smtpSecure || false); + + console.log('📧 SMTP 연결 설정:', { + host: account.smtpHost, + port: account.smtpPort, + secure: isSecure, + user: account.smtpUsername, + }); + const transporter = nodemailer.createTransport({ host: account.smtpHost, port: account.smtpPort, - secure: account.smtpSecure, // SSL/TLS + secure: isSecure, // SSL/TLS (포트 465는 자동으로 true) auth: { user: account.smtpUsername, - pass: account.smtpPassword, + pass: decryptedPassword, // 복호화된 비밀번호 사용 }, + // 타임아웃 설정 (30초) + connectionTimeout: 30000, + greetingTimeout: 30000, }); - // 5. 메일 발송 + console.log('📧 메일 발송 시도 중...'); + + // 6. 메일 발송 const info = await transporter.sendMail({ from: `"${account.name}" <${account.email}>`, to: request.to.join(', '), @@ -75,6 +97,12 @@ class MailSendSimpleService { html: htmlContent, }); + console.log('✅ 메일 발송 성공:', { + messageId: info.messageId, + accepted: info.accepted, + rejected: info.rejected, + }); + return { success: true, messageId: info.messageId, @@ -83,6 +111,8 @@ class MailSendSimpleService { }; } catch (error) { const err = error as Error; + console.error('❌ 메일 발송 실패:', err.message); + console.error('❌ 에러 상세:', err); return { success: false, error: err.message, @@ -178,22 +208,42 @@ class MailSendSimpleService { */ async testConnection(accountId: string): Promise<{ success: boolean; message: string }> { try { + console.log('🔌 SMTP 연결 테스트 시작:', accountId); + const account = await mailAccountFileService.getAccountById(accountId); if (!account) { throw new Error('계정을 찾을 수 없습니다.'); } + // 비밀번호 복호화 + const decryptedPassword = encryptionService.decrypt(account.smtpPassword); + console.log('🔐 비밀번호 복호화 완료'); + + // 포트 465는 SSL/TLS를 사용해야 함 + const isSecure = account.smtpPort === 465 ? true : (account.smtpSecure || false); + + console.log('🔌 SMTP 연결 설정:', { + host: account.smtpHost, + port: account.smtpPort, + secure: isSecure, + user: account.smtpUsername, + }); + const transporter = nodemailer.createTransport({ host: account.smtpHost, port: account.smtpPort, - secure: account.smtpSecure, + secure: isSecure, auth: { user: account.smtpUsername, - pass: account.smtpPassword, + pass: decryptedPassword, // 복호화된 비밀번호 사용 }, + connectionTimeout: 10000, // 10초 타임아웃 + greetingTimeout: 10000, }); + console.log('🔌 SMTP 연결 검증 중...'); await transporter.verify(); + console.log('✅ SMTP 연결 검증 성공!'); return { success: true, @@ -201,6 +251,7 @@ class MailSendSimpleService { }; } catch (error) { const err = error as Error; + console.error('❌ SMTP 연결 실패:', err.message); return { success: false, message: `연결 실패: ${err.message}`, diff --git a/frontend/app/(main)/admin/mail/accounts/page.tsx b/frontend/app/(main)/admin/mail/accounts/page.tsx index 0171f2b6..ca0cf0b9 100644 --- a/frontend/app/(main)/admin/mail/accounts/page.tsx +++ b/frontend/app/(main)/admin/mail/accounts/page.tsx @@ -10,6 +10,7 @@ import { createMailAccount, updateMailAccount, deleteMailAccount, + testMailAccountConnection, CreateMailAccountDto, UpdateMailAccountDto, } from "@/lib/api/mail"; @@ -104,6 +105,24 @@ export default function MailAccountsPage() { } }; + const handleTestConnection = async (account: MailAccount) => { + try { + setLoading(true); + const result = await testMailAccountConnection(account.id); + + if (result.success) { + alert(`✅ SMTP 연결 성공!\n\n${result.message || '정상적으로 연결되었습니다.'}`); + } else { + alert(`❌ SMTP 연결 실패\n\n${result.message || '연결에 실패했습니다.'}`); + } + } catch (error: any) { + console.error('연결 테스트 실패:', error); + alert(`❌ SMTP 연결 테스트 실패\n\n${error.message || '알 수 없는 오류가 발생했습니다.'}`); + } finally { + setLoading(false); + } + }; + return (