작업계획서대로 진행
This commit is contained in:
92
backend/utils/email.ts
Normal file
92
backend/utils/email.ts
Normal file
@@ -0,0 +1,92 @@
|
||||
import * as nodemailer from 'nodemailer'
|
||||
|
||||
/**
|
||||
* 이메일 발송 유틸리티
|
||||
*/
|
||||
|
||||
let transporter: nodemailer.Transporter | null = null
|
||||
|
||||
function getTransporter() {
|
||||
if (transporter) return transporter
|
||||
|
||||
const host = process.env.SMTP_HOST || 'smtp.gmail.com'
|
||||
const port = parseInt(process.env.SMTP_PORT || '587')
|
||||
const user = process.env.SMTP_USER || ''
|
||||
const pass = process.env.SMTP_PASS || ''
|
||||
|
||||
if (!user || !pass) {
|
||||
console.warn('SMTP credentials not configured')
|
||||
return null
|
||||
}
|
||||
|
||||
transporter = nodemailer.createTransport({
|
||||
host,
|
||||
port,
|
||||
secure: port === 465,
|
||||
auth: { user, pass }
|
||||
})
|
||||
|
||||
return transporter
|
||||
}
|
||||
|
||||
interface EmailOptions {
|
||||
to: string
|
||||
subject: string
|
||||
html: string
|
||||
text?: string
|
||||
}
|
||||
|
||||
export async function sendEmail(options: EmailOptions): Promise<boolean> {
|
||||
const t = getTransporter()
|
||||
if (!t) {
|
||||
console.error('Email transporter not configured')
|
||||
return false
|
||||
}
|
||||
|
||||
const from = process.env.SMTP_FROM || process.env.SMTP_USER || 'noreply@example.com'
|
||||
|
||||
try {
|
||||
await t.sendMail({
|
||||
from,
|
||||
to: options.to,
|
||||
subject: options.subject,
|
||||
html: options.html,
|
||||
text: options.text
|
||||
})
|
||||
return true
|
||||
} catch (e) {
|
||||
console.error('Email send error:', e)
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 임시 비밀번호 이메일 발송
|
||||
*/
|
||||
export async function sendTempPasswordEmail(
|
||||
toEmail: string,
|
||||
employeeName: string,
|
||||
tempPassword: string
|
||||
): Promise<boolean> {
|
||||
const subject = '[주간업무보고] 임시 비밀번호 발급'
|
||||
const html = `
|
||||
<div style="font-family: 'Malgun Gothic', sans-serif; max-width: 600px; margin: 0 auto; padding: 20px;">
|
||||
<h2 style="color: #333;">임시 비밀번호 발급</h2>
|
||||
<p>안녕하세요, <strong>${employeeName}</strong>님.</p>
|
||||
<p>요청하신 임시 비밀번호가 발급되었습니다.</p>
|
||||
<div style="background: #f5f5f5; padding: 20px; border-radius: 8px; margin: 20px 0;">
|
||||
<p style="margin: 0; font-size: 18px;"><strong>임시 비밀번호:</strong></p>
|
||||
<p style="margin: 10px 0 0; font-size: 24px; font-family: monospace; color: #007bff;">${tempPassword}</p>
|
||||
</div>
|
||||
<p style="color: #666;">
|
||||
※ 로그인 후 반드시 비밀번호를 변경해 주세요.<br/>
|
||||
※ 본인이 요청하지 않은 경우, 이 메일을 무시하세요.
|
||||
</p>
|
||||
<hr style="border: none; border-top: 1px solid #ddd; margin: 20px 0;" />
|
||||
<p style="color: #999; font-size: 12px;">주간업무보고 시스템</p>
|
||||
</div>
|
||||
`
|
||||
const text = `임시 비밀번호: ${tempPassword}\n\n로그인 후 비밀번호를 변경해 주세요.`
|
||||
|
||||
return sendEmail({ to: toEmail, subject, html, text })
|
||||
}
|
||||
Reference in New Issue
Block a user