Next.js contact form without an API route

Next.js needs no API route and no mail provider for this. A client component posts straight to Mailiy. It works with the App Router and the Pages Router, static export included.

How to set it up

  1. Create a free account, add your website and copy the form's key.
  2. Create the file below and replace YOUR_ACCESS_KEY.
  3. Import it in app/contact/page.jsx and render <ContactForm />.
  4. Deploy as usual, for example on Vercel or as a static export.

app/contact/ContactForm.jsx

"use client";

import { useState } from "react";

export default function ContactForm() {
  const [status, setStatus] = useState("");
  const onSubmit = async (event) => {
    event.preventDefault();
    const data = Object.fromEntries(new FormData(event.currentTarget));
    const res = await fetch("https://mailiy.com/api/submit", {
      method: "POST",
      headers: { "content-type": "application/json", accept: "application/json" },
      body: JSON.stringify({ ...data, access_key: "YOUR_ACCESS_KEY" }),
    });
    const result = await res.json();
    setStatus(result.success ? "Thanks!" : result.message);
  };
  return (
    <form onSubmit={onSubmit}>
      <input type="email" name="email" required />
      <textarea name="message" required />
      <input type="checkbox" name="botcheck" style={{ display: "none" }} />
      <button>Send</button>
      <p role="status">{status}</p>
    </form>
  );
}

What to know about Next.js

Fields Mailiy understands

Every named field appears in the email and in the dashboard. Mailiy reads a few names itself and uses them to shape the mail and what happens after sending:

NameEffect
subjectSubject of the email. Without it, Mailiy uses the subject from the form settings.
from_nameSender name shown in the inbox, for example the name of your website.
email / replytoAddress of the person filling in the form. Hitting reply writes straight back to them.
redirectAddress the browser goes to after sending, for example your own thank-you page.
ccemail / bccemailMore recipients in Cc or Bcc, separated by semicolons. Only addresses confirmed in your account count.
consentConsent checkbox. If you require it in the dashboard, Mailiy refuses submissions without the tick.
botcheckInvisible trap for bots. As long as it stays empty, all is well.

Sending files

With a file input, your Next.js form accepts attachments too, up to five files with 10 MB in total. PDF, images, text and office files are allowed. Mailiy checks that each file's content matches its extension and refuses anything else.

The component above sends JSON, which has no room for files. For uploads, pass the FormData object to fetch() as the body and leave out the Content-Type header; the browser sets it itself.

If no email arrives

Mailiy answers every submission with a message. Usually it comes down to one of these:

After sending

Every submission lands in the dashboard, where you can search them and export them to CSV. In the form settings you can also set up an automatic reply that goes to the address in the email field, such as “Thanks, we'll get back to you within two days”.

If your team should see messages in chat too, Mailiy also posts them to Slack, Discord or Telegram. For your own workflows, webhooks send each submission as JSON to an address you choose.

Spam and privacy

The invisible botcheck field is a trap for bots. If they tick it, Mailiy drops the submission without storing or sending it. You can add more filters and a captcha in the dashboard.

Mailiy runs on servers in Germany and sets no trackers. What else a GDPR compliant form needs is covered in the GDPR checklist.

Frequently asked questions

Can I use a Server Action instead?

You can, but it gains you nothing. A request from the server carries no Origin header, so if you listed allowed domains in the dashboard, Mailiy refuses it. The client component is simpler.

Do I need my own server for a contact form in Next.js?

No. The form posts to Mailiy, and Mailiy sends the email. You need no PHP, no SMTP credentials and no server code.

Is it fine for the key to appear in the page source?

Yes. It only allows sending submissions to this one form and gives no access to your account. In the dashboard you choose which domains submissions are accepted from.

What does it cost?

The free plan includes 100 submissions a month for one website. Paid plans start at €9 a month.

Other platforms

Start for free