릴리스: v1.4.45 이메일 인증 및 비밀번호 재설정 추가
This commit is contained in:
113
backend/src/lib/mailer.js
Normal file
113
backend/src/lib/mailer.js
Normal file
@@ -0,0 +1,113 @@
|
||||
const nodemailer = require('nodemailer')
|
||||
|
||||
const SMTP_HOST = process.env.SMTP_HOST || 'smtp.gmail.com'
|
||||
const SMTP_PORT = process.env.SMTP_PORT ? Number(process.env.SMTP_PORT) : 465
|
||||
const SMTP_SECURE = process.env.SMTP_SECURE ? process.env.SMTP_SECURE === 'true' : SMTP_PORT === 465
|
||||
const SMTP_USER = process.env.SMTP_USER || ''
|
||||
const SMTP_PASS = process.env.SMTP_PASS || ''
|
||||
const SMTP_FROM = process.env.SMTP_FROM || SMTP_USER
|
||||
|
||||
let transporterPromise = null
|
||||
|
||||
function isMailerConfigured() {
|
||||
return !!SMTP_USER && !!SMTP_PASS && !!SMTP_FROM
|
||||
}
|
||||
|
||||
async function getTransporter() {
|
||||
if (!isMailerConfigured()) {
|
||||
const error = new Error('mail_not_configured')
|
||||
error.code = 'mail_not_configured'
|
||||
throw error
|
||||
}
|
||||
|
||||
if (!transporterPromise) {
|
||||
transporterPromise = (async () => {
|
||||
const transporter = nodemailer.createTransport({
|
||||
host: SMTP_HOST,
|
||||
port: SMTP_PORT,
|
||||
secure: SMTP_SECURE,
|
||||
auth: {
|
||||
user: SMTP_USER,
|
||||
pass: SMTP_PASS,
|
||||
},
|
||||
})
|
||||
await transporter.verify()
|
||||
return transporter
|
||||
})()
|
||||
}
|
||||
|
||||
return transporterPromise
|
||||
}
|
||||
|
||||
async function sendMail({ to, subject, text, html }) {
|
||||
const transporter = await getTransporter()
|
||||
await transporter.sendMail({
|
||||
from: SMTP_FROM,
|
||||
to,
|
||||
subject,
|
||||
text,
|
||||
html,
|
||||
})
|
||||
}
|
||||
|
||||
async function sendEmailVerificationMail({ to, nickname, verificationUrl }) {
|
||||
const displayName = nickname || to.split('@')[0] || '사용자'
|
||||
await sendMail({
|
||||
to,
|
||||
subject: '[Tier Maker] 이메일 인증을 완료해주세요',
|
||||
text: [
|
||||
`${displayName}님, Tier Maker 가입을 완료하려면 아래 링크로 이메일 인증을 진행해주세요.`,
|
||||
'',
|
||||
verificationUrl,
|
||||
'',
|
||||
'이 링크는 24시간 동안 유효합니다.',
|
||||
'직접 요청하지 않았다면 이 메일은 무시하셔도 됩니다.',
|
||||
].join('\n'),
|
||||
html: `
|
||||
<div style="font-family:Arial,sans-serif;line-height:1.7;color:#111827">
|
||||
<h1 style="font-size:20px;margin:0 0 16px">Tier Maker 이메일 인증</h1>
|
||||
<p style="margin:0 0 16px">${displayName}님, Tier Maker 가입을 완료하려면 아래 버튼으로 이메일 인증을 진행해주세요.</p>
|
||||
<p style="margin:0 0 20px">
|
||||
<a href="${verificationUrl}" style="display:inline-block;padding:12px 18px;border-radius:999px;background:#4c85f5;color:#ffffff;text-decoration:none;font-weight:700">이메일 인증하기</a>
|
||||
</p>
|
||||
<p style="margin:0 0 8px;font-size:13px;color:#6b7280">버튼이 열리지 않으면 아래 주소를 브라우저에 직접 붙여넣어주세요.</p>
|
||||
<p style="margin:0 0 20px;font-size:13px;word-break:break-all;color:#2563eb">${verificationUrl}</p>
|
||||
<p style="margin:0;font-size:13px;color:#6b7280">이 링크는 24시간 동안 유효합니다. 직접 요청하지 않았다면 이 메일은 무시하셔도 됩니다.</p>
|
||||
</div>
|
||||
`,
|
||||
})
|
||||
}
|
||||
|
||||
async function sendPasswordResetMail({ to, nickname, resetUrl }) {
|
||||
const displayName = nickname || to.split('@')[0] || '사용자'
|
||||
await sendMail({
|
||||
to,
|
||||
subject: '[Tier Maker] 비밀번호 재설정 안내',
|
||||
text: [
|
||||
`${displayName}님, Tier Maker 비밀번호를 다시 설정하려면 아래 링크를 열어주세요.`,
|
||||
'',
|
||||
resetUrl,
|
||||
'',
|
||||
'이 링크는 1시간 동안 유효합니다.',
|
||||
'직접 요청하지 않았다면 이 메일은 무시하셔도 됩니다.',
|
||||
].join('\n'),
|
||||
html: `
|
||||
<div style="font-family:Arial,sans-serif;line-height:1.7;color:#111827">
|
||||
<h1 style="font-size:20px;margin:0 0 16px">Tier Maker 비밀번호 재설정</h1>
|
||||
<p style="margin:0 0 16px">${displayName}님, 비밀번호를 다시 설정하려면 아래 버튼을 눌러주세요.</p>
|
||||
<p style="margin:0 0 20px">
|
||||
<a href="${resetUrl}" style="display:inline-block;padding:12px 18px;border-radius:999px;background:#4c85f5;color:#ffffff;text-decoration:none;font-weight:700">비밀번호 재설정</a>
|
||||
</p>
|
||||
<p style="margin:0 0 8px;font-size:13px;color:#6b7280">버튼이 열리지 않으면 아래 주소를 브라우저에 직접 붙여넣어주세요.</p>
|
||||
<p style="margin:0 0 20px;font-size:13px;word-break:break-all;color:#2563eb">${resetUrl}</p>
|
||||
<p style="margin:0;font-size:13px;color:#6b7280">이 링크는 1시간 동안 유효합니다. 직접 요청하지 않았다면 이 메일은 무시하셔도 됩니다.</p>
|
||||
</div>
|
||||
`,
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
isMailerConfigured,
|
||||
sendEmailVerificationMail,
|
||||
sendPasswordResetMail,
|
||||
}
|
||||
Reference in New Issue
Block a user