SvelteKit
A form action and $env/dynamic/private, which fails the build if you import it client side.
SvelteKit will not let you import a private environment variable into client code: the build fails rather than shipping the key. Use $env/static/private when the key is set at build time and $env/dynamic/private when it comes from the platform at runtime, which is the case on most adapters.
Install
npm install @emails.sh/sdk# .env, gitignored by the SvelteKit starter.
# The key comes from https://emails.sh/dashboard/api-keys.
EMAILSSH_API_KEY=esh_your_key_hereA form action
// src/routes/subscribe/+page.server.ts
import { fail } from '@sveltejs/kit';
import { env } from '$env/dynamic/private';
import { Emailssh } from '@emails.sh/sdk';
import type { Actions } from './$types';
export const actions: Actions = {
default: async ({ request }) => {
const data = await request.formData();
const address = String(data.get('email') ?? '');
if (!address.includes('@')) return fail(400, { message: 'Enter an email address.' });
const mail = new Emailssh({ apiKey: env.EMAILSSH_API_KEY });
try {
const { id } = await mail.send({
from: 'Acme <hello@acme.com>',
to: [address],
subject: 'Confirm your subscription',
html: '<p>Click the link in this email to confirm.</p>',
idempotencyKey: `subscribe-${address}`
});
return { id };
} catch (err) {
console.error('emails.sh refused the send', err);
return fail(502, { message: 'Could not send that email. Try again in a minute.' });
}
}
};<!-- src/routes/subscribe/+page.svelte -->
<script lang="ts">
let { form } = $props();
</script>
<form method="POST">
<label for="email">Email</label>
<input id="email" name="email" type="email" required />
<button type="submit">Subscribe</button>
</form>
{#if form?.message}<p>{form.message}</p>{/if}
{#if form?.id}<p>Check your inbox.</p>{/if}On Cloudflare
With adapter-cloudflare the variable arrives through platform.env rather than the process environment, and $env/dynamic/private reads it for you. Set it with npx wrangler secret put EMAILSSH_API_KEY, and see /docs/cloudflare-workers for the Worker case.