Files
ims/lib/notifications/mailer.ts
T
adminandClaude Sonnet 4.6 d785d86636 feat(email): phase 6 — replace Resend with Brevo transactional email
Removes resend npm dependency. Adds lib/notifications/mailer.ts with a
raw-HTTP Brevo wrapper (sendEmail + sendPasswordResetEmail). All three
notification files updated to use the new wrapper.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-23 22:20:12 +08:00

63 lines
1.8 KiB
TypeScript

import 'server-only'
interface MailOptions {
to: string | string[]
subject: string
html: string
text?: string
}
export async function sendEmail({ to, subject, html, text }: MailOptions): Promise<void> {
const apiKey = process.env.BREVO_API_KEY
if (!apiKey) {
console.error('BREVO_API_KEY not set — email not sent')
return
}
const fromEmail = process.env.BREVO_FROM_EMAIL ?? 'noreply@setia.com.my'
const fromName = process.env.BREVO_FROM_NAME ?? 'Setia IMS'
const recipients = Array.isArray(to) ? to : [to]
const body = {
sender: { name: fromName, email: fromEmail },
to: recipients.map(email => ({ email })),
subject,
htmlContent: html,
...(text ? { textContent: text } : {}),
}
const res = await fetch('https://api.brevo.com/v3/smtp/email', {
method: 'POST',
headers: {
'api-key': apiKey,
'Content-Type': 'application/json',
Accept: 'application/json',
},
body: JSON.stringify(body),
})
if (!res.ok) {
const detail = await res.text().catch(() => '')
console.error(`Brevo send failed (${res.status}): ${detail}`)
}
}
interface PasswordResetOptions {
to: string
name: string | null
resetLink: string
}
export async function sendPasswordResetEmail({ to, name, resetLink }: PasswordResetOptions): Promise<void> {
const displayName = name ?? 'User'
const subject = '[IMS] Password Reset Request'
const html = `
<p>Hi ${displayName},</p>
<p>You requested a password reset for your IMS account.</p>
<p><a href="${resetLink}">Reset your password</a></p>
<p>This link expires in 1 hour. If you did not request this, you can safely ignore this email.</p>
`
const text = `Hi ${displayName},\n\nReset your IMS password: ${resetLink}\n\nThis link expires in 1 hour.`
await sendEmail({ to, subject, html, text })
}