feat: add email notification channel
This commit is contained in:
+31
-8
@@ -4,14 +4,8 @@ function hasSmtpEnv() {
|
|||||||
return Boolean(process.env.SMTP_HOST && process.env.SMTP_PORT && process.env.SMTP_USER && process.env.SMTP_PASS)
|
return Boolean(process.env.SMTP_HOST && process.env.SMTP_PORT && process.env.SMTP_USER && process.env.SMTP_PASS)
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function sendLoginCodeEmail({ to, code }) {
|
function createTransporter() {
|
||||||
if (!hasSmtpEnv()) {
|
return nodemailer.createTransport({
|
||||||
// dev fallback
|
|
||||||
console.log(`[DEV] login code for ${to}: ${code}`)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
const transporter = nodemailer.createTransport({
|
|
||||||
host: process.env.SMTP_HOST,
|
host: process.env.SMTP_HOST,
|
||||||
port: Number(process.env.SMTP_PORT),
|
port: Number(process.env.SMTP_PORT),
|
||||||
secure: process.env.SMTP_SECURE === 'true',
|
secure: process.env.SMTP_SECURE === 'true',
|
||||||
@@ -20,7 +14,15 @@ export async function sendLoginCodeEmail({ to, code }) {
|
|||||||
pass: process.env.SMTP_PASS,
|
pass: process.env.SMTP_PASS,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function sendLoginCodeEmail({ to, code }) {
|
||||||
|
if (!hasSmtpEnv()) {
|
||||||
|
console.log(`[DEV] login code for ${to}: ${code}`)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const transporter = createTransporter()
|
||||||
const from = process.env.MAIL_FROM || process.env.SMTP_USER
|
const from = process.env.MAIL_FROM || process.env.SMTP_USER
|
||||||
|
|
||||||
await transporter.sendMail({
|
await transporter.sendMail({
|
||||||
@@ -31,3 +33,24 @@ export async function sendLoginCodeEmail({ to, code }) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function sendNotificationEmail({ to, subject, html }) {
|
||||||
|
if (!hasSmtpEnv()) {
|
||||||
|
console.log(`[DEV] notification email to ${to}: ${subject}`)
|
||||||
|
return { success: true }
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const transporter = createTransporter()
|
||||||
|
const from = process.env.MAIL_FROM || process.env.SMTP_USER
|
||||||
|
|
||||||
|
await transporter.sendMail({
|
||||||
|
from,
|
||||||
|
to,
|
||||||
|
subject,
|
||||||
|
html,
|
||||||
|
})
|
||||||
|
return { success: true }
|
||||||
|
} catch (err) {
|
||||||
|
return { success: false, error: err.message }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,37 @@
|
|||||||
|
// server/src/lib/notifications/channels/email-channel.js
|
||||||
|
import { sendNotificationEmail } from '../../email.js'
|
||||||
|
import {
|
||||||
|
renderOrderCreatedEmail,
|
||||||
|
renderOrderStatusChangedEmail,
|
||||||
|
renderOrderMessageEmail,
|
||||||
|
renderPaymentStatusChangedEmail,
|
||||||
|
renderAdminOrderCreatedEmail,
|
||||||
|
renderAdminNewReviewEmail,
|
||||||
|
renderAuthCodeEmail,
|
||||||
|
} from '../templates/email-templates.js'
|
||||||
|
|
||||||
|
const templateRenderers = {
|
||||||
|
'order:created': renderOrderCreatedEmail,
|
||||||
|
'order:statusChanged': renderOrderStatusChangedEmail,
|
||||||
|
'orderMessage:adminReply': renderOrderMessageEmail,
|
||||||
|
'payment:statusChanged': renderPaymentStatusChangedEmail,
|
||||||
|
'order:created:admin': renderAdminOrderCreatedEmail,
|
||||||
|
'orderMessage:sent': renderOrderMessageEmail,
|
||||||
|
'review:created': renderAdminNewReviewEmail,
|
||||||
|
'auth:codeRequested': renderAuthCodeEmail,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const emailChannel = {
|
||||||
|
name: 'email',
|
||||||
|
|
||||||
|
async send({ recipient, eventType, payload }) {
|
||||||
|
const renderer = templateRenderers[eventType]
|
||||||
|
if (!renderer) {
|
||||||
|
return { success: false, error: `No email template for event: ${eventType}` }
|
||||||
|
}
|
||||||
|
|
||||||
|
const { subject, html } = renderer(payload)
|
||||||
|
const result = await sendNotificationEmail({ to: recipient, subject, html })
|
||||||
|
return result
|
||||||
|
},
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user