SvelteKit
Send transactional email from SvelteKit through eusend — from a form action or a server endpoint, with the API key kept in private environment variables.
In SvelteKit, sending belongs in code that only runs on the server: a form action in
+page.server.ts, or an endpoint in +server.ts. The eusend SDK uses the native fetch,
so it runs on the Node, Vercel, Netlify and Cloudflare adapters alike.
Setup
npm install @eusend_dev/sdkEUSEND_API_KEY=eu_test_...Read the key through $env/static/private. SvelteKit refuses to build if a private variable
is imported into client code, which is the guarantee you want for an API key.
import { Eusend } from '@eusend_dev/sdk'
import { EUSEND_API_KEY } from '$env/static/private'
export const eusend = new Eusend(EUSEND_API_KEY)Files under src/lib/server cannot be imported from the browser either.
Send from a form action
import { fail } from '@sveltejs/kit'
import { eusend } from '$lib/server/eusend'
import type { Actions } from './$types'
export const actions = {
default: async ({ request }) => {
const form = await request.formData()
const email = String(form.get('email') ?? '')
const message = String(form.get('message') ?? '')
if (!email || !message) return fail(400, { email, missing: true })
const { error } = await eusend.emails.send({
from: 'Acme <hello@yourdomain.com>',
to: 'support@yourdomain.com',
replyTo: email,
subject: 'New contact form message',
text: message,
})
if (error) return fail(502, { email, code: error.name })
return { sent: true }
},
} satisfies Actions<script lang="ts">
import { enhance } from '$app/forms'
let { form } = $props()
</script>
{#if form?.sent}
<p>Thanks — we will get back to you.</p>
{:else}
<form method="POST" use:enhance>
<input name="email" type="email" value={form?.email ?? ''} required />
<textarea name="message" required></textarea>
<button>Send</button>
{#if form?.code}<p>Could not send your message. Please try again.</p>{/if}
</form>
{/if}The SDK returns { data, error } rather than throwing. error.name is the
error code — log it, and show the visitor something plainer.
Send form submissions to your own address with the visitor in replyTo. A form field that chooses
the recipient lets anyone send mail from your domain.
Send from an endpoint
import { json } from '@sveltejs/kit'
import { eusend } from '$lib/server/eusend'
import type { RequestHandler } from './$types'
export const POST: RequestHandler = async ({ request }) => {
const { orderId, email } = await request.json()
const { data, error } = await eusend.emails.send(
{
from: 'Acme <billing@yourdomain.com>',
to: email,
subject: `Receipt for order ${orderId}`,
html: `<p>Thanks — order ${orderId} is confirmed.</p>`,
},
{ idempotencyKey: `receipt-${orderId}` },
)
if (error) return json({ code: error.name }, { status: error.statusCode ?? 502 })
return json({ id: data.id })
}The idempotencyKey makes a retry return the original email instead of sending a second one.
Next steps
- Verify a domain to send to real recipients from your own address.
- Templates to keep email markup out of your routes.
- Webhooks to learn when a message is delivered, bounced or complained about.
Auth.js (NextAuth)
Send Auth.js magic-link sign-in email through eusend, over SMTP with the Nodemailer provider or over HTTP with a custom provider.
FastAPI
Send transactional email from FastAPI through eusend with the Python SDK — in a background task so the response is not held up, with idempotent retries and typed errors.