Send Nuxt email without turning a composable into a secret leak. Keep the call inside Nitro.
Put the credential and send call in a Nitro route, return the accepted message ID, and trace delivery without keeping the browser request open.
✓Server-side via Nitro. Never from a composable that ships to the browser.
One request, complete trace
Request
POST /api/v1/emails
Authorization: Bearer aem_…
Idempotency-Key: welcome-8f21
{ "to": "[email protected]", "template": "welcome" }
202 Accepted
{ "id": "msg_7ca31", "status": "queued" }
[ 01 / 03 ]Integration shape
Use Nuxt's private runtime, not client convenience.
Use Nitro server routes
A defineEventHandler route authenticates browser input and keeps the API key in Nitro's private runtime config.
Publish product events
Publish events from the server route or service that commits the change, so flows never depend on a client composable firing.
Verify the webhook
A server route using readRawBody(event) so the signature check sees the original bytes.
[ 02 / 03 ]Server quickstart
Queue one email from a Nitro route.
Private runtime config protects the key; the idempotency key protects the logical send from repeated requests.
Use private Nitro runtime config; never expose the key through public runtime configuration.
export default defineEventHandler(async (event) => {
const { email, userId } = await readBody(event);
const config = useRuntimeConfig(event);
return $fetch("https://sendandretain.com/api/v1/emails", {
method: "POST", headers: { Authorization: `Bearer ${config.aemKey}`,
"Idempotency-Key": `welcome-${userId}` },
body: { to: email, template: "welcome" },
});
});Accepted response
{ "id": "msg_7ca31", "status": "queued" }Questions people ask us
Keep Nuxt email private and traceable.
Queue one message from Nitro and follow its accepted ID to delivery.