Skip to main content
New:Build with AI agents

Svelte contact forms
without mail code.

Use a Svelte submit handler or SvelteKit action while Form Plume handles notifications, stored submissions, spam filtering, file uploads, integrations, and signed webhooks.

Free foreverNo credit cardSvelte endpoint ready in under a minute
+page.svelte
async function submit(event: SubmitEvent) {
  const form = event.currentTarget as HTMLFormElement;
  status = "sending";

  const response = await fetch(FORM_PLUME_ENDPOINT, {
    method: "POST",
    headers: { Accept: "application/json" },
    body: new FormData(form),
  });

  status = response.ok ? "sent" : "error";
}

The full guide

A lightweight backend for Svelte contact forms.

Choose plain Svelte or a SvelteKit action, keep the form accessible, and avoid custom email infrastructure.

  1. 1
    Create your Form Plume accountStart free and give your Svelte form a hosted endpoint for email, submissions, spam filtering, uploads, integrations, and webhooks.Start free
  2. 2
    Create the form and copy the endpointCopy the endpoint URL from Form Plume. It looks like https://api.formplume.com/f/your-slug
  3. 3
    Connect it inside SvelteUse a plain Svelte submit handler or SvelteKit form actions, depending on whether the form should post from the browser or through the route. Send one test submission from the real Svelte app or preview environment and confirm it reaches Form Plume.

You can use this AI prompt to hand the platform-specific wiring to an assistant without accidentally creating a backend.

Plain Svelte component

For a static Svelte app, submit directly to Form Plume from the browser.

<script lang="ts">
  const FORM_PLUME_ENDPOINT = "PASTE_YOUR_FORM_PLUME_ENDPOINT_HERE";
  let status: "idle" | "sending" | "sent" | "error" = "idle";
 
  async function submit(event: SubmitEvent) {
    const form = event.currentTarget as HTMLFormElement;
    status = "sending";
 
    const response = await fetch(FORM_PLUME_ENDPOINT, {
      method: "POST",
      headers: { Accept: "application/json" },
      body: new FormData(form),
    });
 
    if (response.ok) {
      form.reset();
      status = "sent";
    } else {
      status = "error";
    }
  }
</script>
 
<form on:submit|preventDefault={submit}>
  <label for="email">Email</label>
  <input id="email" type="email" name="email" autocomplete="email" required>
 
  <label for="message">Message</label>
  <textarea id="message" name="message" rows="5" required />
 
  <button disabled={status === "sending"}>
    {status === "sending" ? "Sending..." : "Send message"}
  </button>
 
  {#if status === "sent"}
    <p role="status">Thanks, we got your message.</p>
  {:else if status === "error"}
    <p role="alert">Please try again.</p>
  {/if}
</form>

SvelteKit action

If you want the route to own validation and redirects, forward the form from a SvelteKit action.

// src/routes/contact/+page.server.ts
import { redirect, type Actions } from "@sveltejs/kit";
 
const FORM_PLUME_ENDPOINT = "PASTE_YOUR_FORM_PLUME_ENDPOINT_HERE";
 
export const actions: Actions = {
  default: async ({ request }) => {
    const formData = await request.formData();
 
    const response = await fetch(FORM_PLUME_ENDPOINT, {
      method: "POST",
      body: formData,
    });
 
    if (!response.ok) {
      return { ok: false };
    }
 
    throw redirect(303, "/thanks");
  },
};
<!-- src/routes/contact/+page.svelte -->
<form method="POST">
  <input name="email" type="email" required>
  <textarea name="message" required />
  <button>Send message</button>
</form>

Enhanced SvelteKit forms

Use SvelteKit's enhance helper when you want progressive enhancement while keeping the action as the source of truth. The unenhanced form still works.

A SvelteKit action is useful for redirects and validation, but it should not become a custom mail backend. Form Plume handles notifications, storage, spam filtering, uploads, integrations, and webhooks.

Uploads and field names

Use FormData for files and do not set multipart headers manually.

Keep fields named name, email, message, company, phone, or attachment where possible. Those names make dashboard review and downstream integrations easier.

Svelte-specific checks

Reset the form only after a successful response.

Keep success and error messages in the markup so assistive technology can announce them.

Avoid duplicating the submission into analytics or automation calls from the browser. Let Form Plume fan accepted submissions out after spam filtering.

Primary sources

FAQ

Svelte form questions
before ship.

Use a SvelteKit action when the route should own validation, redirects, or progressive enhancement. Use a plain Svelte submit handler for static apps.

One line. Zero backend.

The form backend you don’t have to build.

Free foreverNo credit cardSet up in under a minute