fix the email sent
This commit is contained in:
+1
-1
@@ -48,7 +48,7 @@ NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME=your-cloud-name
|
|||||||
|
|
||||||
# ─── Resend (Email) ────────────────────────────────────────────
|
# ─── Resend (Email) ────────────────────────────────────────────
|
||||||
RESEND_API_KEY=re_...
|
RESEND_API_KEY=re_...
|
||||||
EMAIL_FROM=noreply@rentaldrivego.com
|
EMAIL_FROM=rentaldrivego@gmail.com
|
||||||
EMAIL_FROM_NAME=RentalDriveGo
|
EMAIL_FROM_NAME=RentalDriveGo
|
||||||
|
|
||||||
# ─── Twilio (SMS + WhatsApp) ───────────────────────────────────
|
# ─── Twilio (SMS + WhatsApp) ───────────────────────────────────
|
||||||
|
|||||||
@@ -5,11 +5,15 @@ import { prisma } from '../lib/prisma'
|
|||||||
import { redis } from '../lib/redis'
|
import { redis } from '../lib/redis'
|
||||||
import { NotificationType, NotificationChannel } from '@rentaldrivego/database'
|
import { NotificationType, NotificationChannel } from '@rentaldrivego/database'
|
||||||
|
|
||||||
const resend =
|
const resendApiKey =
|
||||||
process.env.RESEND_API_KEY && process.env.RESEND_API_KEY !== 're_...'
|
process.env.RESEND_API_KEY &&
|
||||||
? new Resend(process.env.RESEND_API_KEY)
|
process.env.RESEND_API_KEY !== 're_...' &&
|
||||||
|
process.env.RESEND_API_KEY.startsWith('re_')
|
||||||
|
? process.env.RESEND_API_KEY
|
||||||
: null
|
: null
|
||||||
|
|
||||||
|
const resend = resendApiKey ? new Resend(resendApiKey) : null
|
||||||
|
|
||||||
const emailFromAddress =
|
const emailFromAddress =
|
||||||
process.env.EMAIL_FROM && process.env.EMAIL_FROM !== 'noreply@example.com'
|
process.env.EMAIL_FROM && process.env.EMAIL_FROM !== 'noreply@example.com'
|
||||||
? process.env.EMAIL_FROM
|
? process.env.EMAIL_FROM
|
||||||
@@ -125,6 +129,85 @@ function renderEmailHtml(body: string) {
|
|||||||
.join('')
|
.join('')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolveSmtpReplyTo() {
|
||||||
|
if (!process.env.MAIL_REPLY_TO_ADDRESS || process.env.MAIL_REPLY_TO_ADDRESS.includes('${')) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
|
|
||||||
|
if (process.env.MAIL_REPLY_TO_NAME && !process.env.MAIL_REPLY_TO_NAME.includes('${')) {
|
||||||
|
return `${process.env.MAIL_REPLY_TO_NAME} <${process.env.MAIL_REPLY_TO_ADDRESS}>`
|
||||||
|
}
|
||||||
|
|
||||||
|
return process.env.MAIL_REPLY_TO_ADDRESS
|
||||||
|
}
|
||||||
|
|
||||||
|
async function sendEmailWithProviders(opts: {
|
||||||
|
to: string
|
||||||
|
subject: string
|
||||||
|
html: string
|
||||||
|
text: string
|
||||||
|
}) {
|
||||||
|
const errors: string[] = []
|
||||||
|
|
||||||
|
if (resend) {
|
||||||
|
try {
|
||||||
|
if (!emailFromAddress || !emailFromName) {
|
||||||
|
throw new Error('Email sender identity is not configured')
|
||||||
|
}
|
||||||
|
|
||||||
|
const { data, error } = await resend.emails.send({
|
||||||
|
from: `${emailFromName} <${emailFromAddress}>`,
|
||||||
|
to: opts.to,
|
||||||
|
subject: opts.subject,
|
||||||
|
html: opts.html,
|
||||||
|
text: opts.text,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
throw new Error(error.message)
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
provider: 'resend' as const,
|
||||||
|
providerMessageId: data?.id ?? null,
|
||||||
|
}
|
||||||
|
} catch (err: any) {
|
||||||
|
errors.push(`Resend: ${err?.message ?? String(err)}`)
|
||||||
|
console.warn('[Notifications] Resend delivery failed, falling back if possible:', err?.message ?? String(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (smtpTransport) {
|
||||||
|
try {
|
||||||
|
if (!smtpFromAddress) {
|
||||||
|
throw new Error('SMTP sender identity is not configured')
|
||||||
|
}
|
||||||
|
|
||||||
|
const info = await smtpTransport.sendMail({
|
||||||
|
from: smtpFromName ? `${smtpFromName} <${smtpFromAddress}>` : smtpFromAddress,
|
||||||
|
to: opts.to,
|
||||||
|
subject: opts.subject,
|
||||||
|
html: opts.html,
|
||||||
|
text: opts.text,
|
||||||
|
replyTo: resolveSmtpReplyTo(),
|
||||||
|
})
|
||||||
|
|
||||||
|
return {
|
||||||
|
provider: 'smtp' as const,
|
||||||
|
providerMessageId: info.messageId ?? null,
|
||||||
|
}
|
||||||
|
} catch (err: any) {
|
||||||
|
errors.push(`SMTP: ${err?.message ?? String(err)}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (errors.length) {
|
||||||
|
throw new Error(errors.join(' | '))
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('No email provider is configured')
|
||||||
|
}
|
||||||
|
|
||||||
export async function sendNotification(opts: SendNotificationOptions) {
|
export async function sendNotification(opts: SendNotificationOptions) {
|
||||||
const results: Array<{ channel: NotificationChannel; success: boolean; error?: string }> = []
|
const results: Array<{ channel: NotificationChannel; success: boolean; error?: string }> = []
|
||||||
|
|
||||||
@@ -148,44 +231,14 @@ export async function sendNotification(opts: SendNotificationOptions) {
|
|||||||
let success = false
|
let success = false
|
||||||
|
|
||||||
if (channel === 'EMAIL' && opts.email) {
|
if (channel === 'EMAIL' && opts.email) {
|
||||||
if (resend) {
|
const emailResult = await sendEmailWithProviders({
|
||||||
if (!emailFromAddress || !emailFromName) {
|
to: opts.email,
|
||||||
throw new Error('Email sender identity is not configured')
|
subject: opts.title,
|
||||||
}
|
html: renderEmailHtml(opts.body),
|
||||||
const { data, error } = await resend.emails.send({
|
text: opts.body,
|
||||||
from: `${emailFromName} <${emailFromAddress}>`,
|
})
|
||||||
to: opts.email,
|
providerMessageId = emailResult.providerMessageId
|
||||||
subject: opts.title,
|
success = true
|
||||||
html: renderEmailHtml(opts.body),
|
|
||||||
text: opts.body,
|
|
||||||
})
|
|
||||||
if (error) {
|
|
||||||
throw new Error(error.message)
|
|
||||||
}
|
|
||||||
providerMessageId = data?.id ?? null
|
|
||||||
success = true
|
|
||||||
} else if (smtpTransport) {
|
|
||||||
if (!smtpFromAddress) {
|
|
||||||
throw new Error('SMTP sender identity is not configured')
|
|
||||||
}
|
|
||||||
const info = await smtpTransport.sendMail({
|
|
||||||
from: smtpFromName ? `${smtpFromName} <${smtpFromAddress}>` : smtpFromAddress,
|
|
||||||
to: opts.email,
|
|
||||||
subject: opts.title,
|
|
||||||
html: renderEmailHtml(opts.body),
|
|
||||||
text: opts.body,
|
|
||||||
replyTo:
|
|
||||||
process.env.MAIL_REPLY_TO_ADDRESS && !process.env.MAIL_REPLY_TO_ADDRESS.includes('${')
|
|
||||||
? process.env.MAIL_REPLY_TO_NAME && !process.env.MAIL_REPLY_TO_NAME.includes('${')
|
|
||||||
? `${process.env.MAIL_REPLY_TO_NAME} <${process.env.MAIL_REPLY_TO_ADDRESS}>`
|
|
||||||
: process.env.MAIL_REPLY_TO_ADDRESS
|
|
||||||
: undefined,
|
|
||||||
})
|
|
||||||
providerMessageId = info.messageId ?? null
|
|
||||||
success = true
|
|
||||||
} else {
|
|
||||||
throw new Error('No email provider is configured')
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (channel === 'SMS' && opts.phone) {
|
if (channel === 'SMS' && opts.phone) {
|
||||||
@@ -259,30 +312,5 @@ export async function sendTransactionalEmail(opts: {
|
|||||||
html: string
|
html: string
|
||||||
text: string
|
text: string
|
||||||
}) {
|
}) {
|
||||||
if (resend) {
|
await sendEmailWithProviders(opts)
|
||||||
if (!emailFromAddress || !emailFromName) throw new Error('Email sender identity is not configured')
|
|
||||||
const { error } = await resend.emails.send({
|
|
||||||
from: `${emailFromName} <${emailFromAddress}>`,
|
|
||||||
to: opts.to,
|
|
||||||
subject: opts.subject,
|
|
||||||
html: opts.html,
|
|
||||||
text: opts.text,
|
|
||||||
})
|
|
||||||
if (error) throw new Error(error.message)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if (smtpTransport) {
|
|
||||||
if (!smtpFromAddress) throw new Error('SMTP sender identity is not configured')
|
|
||||||
await smtpTransport.sendMail({
|
|
||||||
from: smtpFromName ? `${smtpFromName} <${smtpFromAddress}>` : smtpFromAddress,
|
|
||||||
to: opts.to,
|
|
||||||
subject: opts.subject,
|
|
||||||
html: opts.html,
|
|
||||||
text: opts.text,
|
|
||||||
})
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new Error('No email provider is configured')
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user