Next.js
Send from the server, never from the browser: an API key must never reach a page.
npm install @heraldmail/sdk @react-email/renderSend from a server action
'use server'
import { Herald } from '@heraldmail/sdk'
import { Welcome } from '@/emails/welcome'
const herald = new Herald(process.env.HERALD_API_KEY)
export async function welcome(userId: string, email: string, name: string) {
const { error } = await herald.emails.send(
{
from: 'Mentor <hello@mentor.app>',
to: email,
subject: 'Welcome to Mentor',
react: <Welcome name={name} />,
},
{ idempotencyKey: `welcome/${userId}` },
)
if (error) console.error('Herald refused the welcome email', error.name, error.message)
}react takes a React Email element. The SDK renders it to HTML and plain text in your app, with @react-email/render, before sending: your components never run on Herald’s servers.
Take webhooks in a route handler
Verify the signature over the raw body, before you parse it, or anyone could post you events.
import { verifyWebhook, WebhookVerificationError } from '@heraldmail/sdk'
export async function POST(request: Request) {
const body = await request.text()
try {
const event = await verifyWebhook<{ type: string; data: { email_id: string } }>(
body,
request.headers,
process.env.HERALD_WEBHOOK_SECRET!,
)
if (event.type === 'email.bounced') {
// mark the address as bad in your own records
}
return new Response(null, { status: 204 })
} catch (err) {
if (err instanceof WebhookVerificationError) return new Response(null, { status: 400 })
throw err
}
}Answer with a 2xx within 10 seconds; anything else is retried. See Webhooks for every event and what it carries.
Environment
HERALD_API_KEY=hrld_live_…
HERALD_WEBHOOK_SECRET=whsec_…Keep both server-side only: never give either a NEXT_PUBLIC_ name.