Every dashboard action is an MCP tool your agent can call.Read the docs
Remix email

Send Remix email from the mutation, not the component. An action accepts it; a webhook reports the outcome.

Queue transactional mail from a server action or resource route, return the accepted message ID, and keep delivery work out of the browser lifecycle.

Server-side in actions and resource routes only.

Server quickstart
Remix

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" }

RuntimeServer process
RequestPOST /api/v1/emails
Result202 · queued
Credentials stay server-side

[ 01 / 03 ]Integration shape

Keep the email boundary aligned with the data mutation.

Use actions and server loaders

Actions belong with form mutations; resource routes expose a focused HTTP boundary for services and webhooks.

Publish product events

Publish the event after the action commits the product change, rather than sending because a component rendered.

Verify the webhook

A resource route reading await request.text() for signature verification.

[ 02 / 03 ]Server quickstart

Queue one email from a Remix action.

The action keeps the key private, protects repeated submissions with an idempotency key, and returns an accepted ID.

Keep the call inside the server action, not the browser component.

app/routes/welcome.tsx
export async function action({ request }: ActionFunctionArgs) {
  const input = await request.json();
  return fetch(EMAIL_URL, { method: "POST",
    headers: authHeaders(`welcome-${input.userId}`),
    body: JSON.stringify({ to: input.email, template: "welcome" }) });
}

Accepted response

{ "id": "msg_7ca31", "status": "queued" }

Questions people ask us

Give your next Remix action a delivery trail.

Queue the message with a stable key and verify the result in a resource route.