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.