Send email from Nuxt with emailr_
Send transactional email from Nuxt server routes with the emailr_ SDK, keep keys in runtimeConfig and verify delivery webhooks with raw bodies.
Nuxt's Nitro server routes are a natural home for email sending: they run only on the server, read secrets from runtimeConfig, and deploy anywhere Nitro does.
This guide adds the emailr SDK, sends from a server route and verifies signed delivery webhooks.
Set up emailr_ with Nuxt
- 01
Create an API key
Create a key under API keys in the dashboard. Keys start with
et_live_and are scoped to one domain workspace. Store it asEMAILR_API_KEYin your secret manager or environment, never in client-side code. - 02
Add and verify your sending domain
In the dashboard, open Domains and add the domain you send from. A subdomain such as
mail.yourcompany.comkeeps transactional reputation separate from your corporate mailbox.Emailr generates the DNS records: a DKIM TXT record on the
emailr._domainkeyselector, an SPF TXT record, and an MX + TXT pair on thesendsubdomain used as the MAIL FROM / Return-Path. A DMARC record is optional but recommended.Emailr's DKIM selector and
sendsubdomain don't collide with other providers' records, so you can add them before cutting over and send from both providers during the migration. A domain can only have one SPF record: if one already exists, merge Emailr'sinclude:into it instead of adding a second record. - 03
Install the SDK
Install the package in your Nuxt project.
Terminalbashnpm install emailr - 04
Declare private runtime config
Keys declared at the top level of
runtimeConfigare server-only. Nuxt fills them fromNUXT_-prefixed environment variables, so setNUXT_EMAILR_API_KEYandNUXT_EMAILR_WEBHOOK_SECRETin production.nuxt.config.tstsexport default defineNuxtConfig({ runtimeConfig: { emailrApiKey: '', emailrWebhookSecret: '', }, }) - 05
Send from a server route
Files in
server/apibecome endpoints. A.post.tssuffix restricts the route to POST requests.server/api/welcome.post.tstsimport { Emailr } from 'emailr' export default defineEventHandler(async (event) => { const { email } = await readBody<{ email: string }>(event) const { emailrApiKey } = useRuntimeConfig(event) const emailr = new Emailr({ apiKey: emailrApiKey }) const result = await emailr.emails.send({ from: 'Acme <[email protected]>', to: email, subject: 'Welcome to Acme', html: '<p>Thanks for signing up.</p>', }) return { id: result.message_id } }) - 06
Verify delivery webhooks
Use
readRawBodyso the HMAC is computed over the exact bytes emailr_ sent, then parse the JSON yourself.server/api/webhooks/emailr.post.tstsimport { createHmac, timingSafeEqual } from 'node:crypto' export default defineEventHandler(async (event) => { const body = (await readRawBody(event)) ?? '' const signature = getHeader(event, 'x-emailr-signature') ?? '' const { emailrWebhookSecret } = useRuntimeConfig(event) const expected = createHmac('sha256', emailrWebhookSecret).update(body).digest('hex') if (signature.length !== expected.length || !timingSafeEqual(Buffer.from(signature), Buffer.from(expected))) { throw createError({ statusCode: 401, statusMessage: 'Invalid signature' }) } const { event: type, data } = JSON.parse(body) // handle email.delivered, email.bounced, email.complained ... return { ok: true } })
Tips
- Call the route from a page with
$fetch('/api/welcome', { method: 'POST', body: { email } }). - On edge presets such as Cloudflare, swap
node:cryptofor the Web Crypto verification shown in the Cloudflare guide. - Vue Email or any other renderer works: render to an HTML string and pass it as
html.
Frequently asked questions
Where should I put my emailr_ API key in Nuxt?
In a top-level runtimeConfig key, filled from the NUXT_EMAILR_API_KEY environment variable. Top-level keys are only available on the server.
Can I send email from a Nuxt page or component?
Not directly. Pages run in the browser too, so call a server route with $fetch and send from there.
Does the SDK run on Nitro edge presets?
The SDK uses fetch and works on edge runtimes. For webhook verification on the edge, use Web Crypto instead of node:crypto.
How do I verify emailr_ webhooks in Nuxt?
Read the body with readRawBody, compute an HMAC-SHA256 with your webhook secret and compare it to the X-Emailr-Signature header.
Keep going
Documentation
Related guides
- Send email from Next.jsSend transactional email from Next.js App Router route handlers and server actions with the emailr_ SDK, and verify delivery webhooks safely.
- Send email from RemixSend transactional email from Remix actions with the emailr_ SDK, keep the client in a .server module and verify delivery webhooks in resource routes.
- Send email from Cloudflare WorkersSend transactional email from Cloudflare Workers with the fetch-based emailr_ SDK, store keys as Worker secrets and verify webhooks with Web Crypto.
Start sending in minutes
Create a free account, verify your domain and send your first email. No credit card required.