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

Send emails with SvelteKit

Transactional and marketing email from a +server.ts route or form action. Your key stays in private env, out of the client build.

✓Free to start. Unlimited contacts on every tier.

Server quickstart
Sveltekit

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 / 05 ]Quickstart

How do I send email from SvelteKit?

Create a key, keep it on the server, and call one endpoint from a +server.ts route or form action.

  1. Get an API key

    Open Settings → API & MCP and create a key with the Send + manage permission (the default). It starts with aem_ and is shown once.

  2. Store it as a server-side environment variable

    Set AEM_KEY=aem_… in .env and read it through $env/dynamic/private. SvelteKit refuses to import $lib/server code into the browser.

    src/lib/server/email.ts
    import { env } from "$env/dynamic/private";
    
    export const EMAIL_URL = "https://sendandretain.com/api/v1/emails";
    
    export const authHeaders = (idempotencyKey: string) => ({
      Authorization: `Bearer ${env.AEM_KEY}`,
      "Content-Type": "application/json",
      "Idempotency-Key": idempotencyKey,
    });
  3. Send the email

    A server route posts to the email API. A retry with the same Idempotency-Key won't send a second email.

    src/routes/api/welcome/+server.ts
    import { json } from "@sveltejs/kit";
    import { EMAIL_URL, authHeaders } from "$lib/server/email";
    import type { RequestHandler } from "./$types";
    
    export const POST: RequestHandler = async ({ request }) => {
      const input = await request.json();
      const res = await fetch(EMAIL_URL, { method: "POST",
        headers: authHeaders(`welcome-${input.userId}`),
        body: JSON.stringify({ to: input.email, template: "welcome" }) });
      return json(await res.json(), { status: res.status });
    };
  4. Check the response

    A 202 means queued, not delivered. Keep the id, then follow delivery in the message log or through a signed webhook.

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

[ 02 / 05 ]Where it goes

Where should email code live in your SvelteKit app?

Server routes and form actions

Use a form action for a page mutation, or +server.ts for an API endpoint. Both can read private env.

Events after the mutation

Send events after the server-side change succeeds, so automations follow what really happened.

A raw body for webhooks

In +server.ts, read await request.text() before parsing.

[ 03 / 05 ]Marketing email

Can I send marketing emails from SvelteKit too?

Yes. Send an event from the same form action when a user signs up, starts a trial, or goes quiet, and an automation sends the right email. Automations start paused, and every email goes to one person: no newsletter blasts.

  • Transactional and marketing email share one contact record and one unsubscribe list.
  • Unsubscribes, bounces, and complaints are suppressed for you before every send.
  • Templates are react.email components; published versions never change under you.

[ 04 / 05 ]Example prompts

What can you ask your coding agent to do in SvelteKit?

Claude Code, Cursor, and Codex can do these over the Send & Retain MCP server, with your repo open. Automations they build stay paused until you turn them on.

  • Welcome email

    “Add a welcome email to our SvelteKit signup action using Send & Retain, with an idempotency key.”

  • Order receipt

    “Send an order receipt email from our checkout form action, with the API key in $env/dynamic/private.”

  • Webhook

    “Add a SvelteKit +server.ts route that verifies Send & Retain delivery webhooks and flags bounced users.”

  • Trial automation

    “Send a trial_started event from our SvelteKit app and build a paused trial-conversion automation for it.”

Questions people ask us

Send your first email from SvelteKit today.

Create a key, paste the code into a +server.ts route or form action, and watch the email land in the message log.