← All posts

Build a SvelteKit contact form in minutes

Add a working contact form to a SvelteKit app with a one-line email action: no API routes to hand-roll, no email HTML to write. A step-by-step guide with Postboi.

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:

terminal
bunx postboi init

2. 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:

+page.server.ts
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:

+page.svelte
<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:

Keep going

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.

Start sending for free.

The Postboi mascot

Put the boi to work.

One command between you and your first delivered message.

Start sending, free