React contact form that sends email (Vite, CRA, any React)
A small React component with loading, success and error states. Works in Vite, Remix, Gatsby or any React app.
Last updated October 25, 2026
1Create a FormSMTP project
Sign up free and add a project. Pick your email provider so the SMTP host and port fill in, enter your login, and click Test connection. Not sure which provider? Your existing mailbox works: see the Gmail or Zoho guides.
2Lock the project to your site
In Settings → Security, set Allowed websites to https://yourapp.com and Allowed recipients to your own address. Now the key in your page can only email you, only from your site, and only up to your hourly limit.
3Add the component
import { useState } from "react";
const ENDPOINT = "https://app.formsmtp.com/api/v1/form/" + import.meta.env.VITE_FORMSMTP_KEY;
export default function ContactForm() {
const [status, setStatus] = useState("idle"); // idle | sending | sent | error
const [error, setError] = useState("");
async function handleSubmit(e) {
e.preventDefault();
setStatus("sending");
try {
const res = await fetch(ENDPOINT, {
method: "POST",
headers: { Accept: "application/json" },
body: new URLSearchParams(new FormData(e.target)),
});
const data = await res.json();
if (!data.success) throw new Error(data.error);
setStatus("sent");
} catch (err) {
setError(err.message);
setStatus("error");
}
}
if (status === "sent") return <p>Thanks! We'll be in touch soon.</p>;
return (
<form onSubmit={handleSubmit}>
<input name="name" placeholder="Name" required />
<input name="email" type="email" placeholder="Email" required />
<textarea name="message" placeholder="Message" required />
<input name="_gotcha" style={{ display: "none" }} tabIndex={-1} autoComplete="off" />
<button disabled={status === "sending"}>{status === "sending" ? "Sending…" : "Send"}</button>
{status === "error" && <p role="alert">{error}</p>}
</form>
);
}Put VITE_FORMSMTP_KEY=… in .env (other bundlers: REACT_APP_… or NEXT_PUBLIC_…).
FAQ
Do I need a library like EmailJS’s SDK?
No. It’s one fetch() call, with no SDK and nothing to install.
Is it safe to put the API key in my HTML?
Yes, with the project locked down. Form submissions always go to your own inbox, and you can restrict the key to your website and an hourly limit, so a copied key can’t be used to email anyone else.
Why did my message land in spam?
Usually the From address and the SMTP account don’t match, or the domain has no SPF/DKIM records. Send from the address you log in with, and check the Deliverability panel in FormSMTP’s Settings.