A contact form is the most common reason to add email to a web app, and in SvelteKit it's also one of the quickest things you can build. With Postboi the entire server side is a single line, and the email body writes itself from your form fields.
Here's the whole thing, start to finish.
1. Set up Postboi
Run the CLI — it signs you in, writes a token, and installs Postboi:
bunx postboi init2. The server action — one line
postboi/kit reads the submitted FormData, sends it, and returns { success: true } — or fail(400, { error }) if something goes wrong.
Wire it up as your default form action:
import { mail } from 'postboi/kit'
export const actions = { default: mail }That's the entire back end. No API route, no request parsing, no email template.
3. The form
Point a multipart/form-data form at the action. Field names use fieldset→field syntax to group related fields, and _subject sets the
email subject. A hidden _reply_to field means hitting Reply in your inbox
goes straight back to the sender:
<script lang="ts">
import { enhance } from '$app/forms'
let email = $state('')
</script>
<form method="POST" use:enhance enctype="multipart/form-data">
<input type="hidden" name="_subject" value="Contact Form" />
<input type="hidden" name="_reply_to" value={email} />
<input name="contact→name" placeholder="Name" required />
<input name="contact→email" type="email" placeholder="Email" required bind:value={email} />
<textarea name="details→message" placeholder="Message"></textarea>
<input type="file" name="details→attachments" multiple />
<button type="submit">Send</button>
</form>That's it: a fully working SvelteKit contact form with file uploads and sensible reply-to behaviour.
4. What lands in your inbox
Submit that form and here's the email. Each fieldset→field group becomes a heading
with a table of its fields, files arrive as attachments, and hitting Reply goes straight
back to the sender — all without writing any email markup:
Subject Contact Form
Reply-To ada@example.com
Contact
| Name | Ada Lovelace |
|---|---|
| ada@example.com |
Details
| Message | Loved the demo — can we talk pricing? |
|---|
Keep going
- A full, runnable example lives in examples/sveltekit-provider-postboi.
- The SvelteKit guide covers the action in depth.
- The FormData guide explains grouped fields, special fields, and attachments.
Postboi is framework-agnostic, so the same one-line approach works in Next.js, Astro, Nuxt, Remix, and more. Postboi is currently in pre-release — pin your version and check the changelog before upgrading.