No plugin in gatsby-config
Form plugins are a place things break on a major upgrade, and they are usually abandoned before your site is. There is nothing here to be incompatible with a future Gatsby version.
integrations · framework
Gatsby builds to static files, so a contact form has to reach outside the build somehow. The two habits people picked up both age badly: Gatsby Functions tie the form to a runtime, and the host's own form feature ties it to the host. Anyone who lived through Gatsby Cloud's shutdown and moved their site elsewhere found out which parts of their stack were actually portable, and form handling was usually not one of them.
A form that posts to a mailcontact endpoint has no such attachment. It is markup in a React component with an action, so it survives a host migration, a Gatsby version bump, and eventually a rewrite into something else entirely.
recommended setup
Add this HTML to your site, or use the form builder. Replace the form link with yours. The hosted script injects the hidden check, handles sending and automatic verification, and preserves the draft on errors. You control the HTML and CSS. Free forms display a visible “Processed by mailcontact.app” link; Pro and Plus do not. Feedback follows the browser’s language; set data-mailcontact-language="fr" on the form to force French.
<form action="https://mailcontact.app/api/forms/your-form-id" method="POST" data-mailcontact-form>
<fieldset>
<legend>Contact us</legend>
<label>
Name (optional)
<input name="name" type="text" autocomplete="name" maxlength="200" />
</label>
<label>
Email
<input name="email" type="email" autocomplete="email" maxlength="320" required />
</label>
<label>
Message
<textarea name="message" rows="5" maxlength="5000" required></textarea>
</label>
<noscript>
<div aria-hidden="true" style="position:absolute;left:-10000px;width:1px;height:1px;overflow:hidden;">
<label>Website
<input name="company_website" type="text" tabindex="-1" autocomplete="off" />
</label>
</div>
</noscript>
<button type="submit">Send message</button>
</fieldset>
<p data-contact-status role="status" aria-live="polite" aria-atomic="true"></p>
</form>
<script defer src="https://mailcontact.app/forms/v1.js" crossorigin="anonymous" referrerpolicy="no-referrer"></script>For a component with its own submit handler, load the same script and use MailContact.prepare(form) and MailContact.send() instead of the automatic marker. See the custom interface reference for loading, feedback and Free attribution.
the snippet
This example posts directly to the API. Keep the required company_website field present and empty. Native posts open JSON on success or a verification page when needed. Custom scripts without verification support send suspicious messages to Spam for review; strong spam is also held there without notifications or quota usage. A success response confirms reception, including review, or a silent discard of a filled check. See spam protection for the full behavior.
import * as React from "react";
// No src/api/ function. No host form feature. Nothing to migrate later.
export default function ContactPage() {
const [sent, setSent] = React.useState(false);
async function submit(event) {
event.preventDefault();
await fetch("https://mailcontact.app/api/forms/your-form-id", {
method: "POST",
body: new FormData(event.target),
});
setSent(true);
}
if (sent) return <p>Thanks. We'll be in touch.</p>;
return (
<form onSubmit={submit}>
<input name="name" placeholder="Your name" required />
<input name="email" type="email" placeholder="[email protected]" required />
<textarea name="message" placeholder="What's on your mind?" required />
<input name="company_website" type="text" tabIndex={-1} autoComplete="off"
style={{ position: "absolute", left: "-10000px" }} aria-hidden="true" />
<button>Send</button>
</form>
);
}how it works
One inbox per project, with a form endpoint and a project email address ready before the first build.
Drop it in src/pages/contact.js and swap the endpoint id. No gatsby-config plugin to install, no environment variable, and nothing to add to your build command.
Add a Discord, Slack, email, or webhook channel and delivered messages ping you there.
why mailcontact
Form plugins are a place things break on a major upgrade, and they are usually abandoned before your site is. There is nothing here to be incompatible with a future Gatsby version.
Netlify Forms only work on Netlify, and a Gatsby Function needs a host willing to run it. An action pointing at an external URL has no opinion about where the built files are served from.
Host-native form features leave the archive behind when you migrate. Messages live in your project inbox, so changing hosts does not lose the last two years of enquiries.
faq
Not by itself. gatsby build produces HTML, CSS and JS with nothing running to accept a POST. You need something outside the build to receive it, whether that is a Gatsby Function on a host that supports one, a third-party service, or your own API.
They work, but they turn a static site into one with a runtime, which is the thing you get to skip otherwise. You also write the mail delivery, the spam filtering and the storage yourself, and it only deploys on hosts that support Gatsby Functions. For a contact form, that is a lot of surface for very little.
No. This touches no config at all. It is a React component with a form element and a submit handler, so it needs no plugin, no GraphQL query, and no entry in gatsby-config.js.
That is your call, and plenty of Gatsby sites are running happily. What is worth noting is that the framework's momentum has slowed, so the pieces you can keep portable are the ones you will thank yourself for later. A form that is markup pointing at a URL is one of them.
related
Forms and a real email address, together, with notifications where you live. Start with a free account.
Create your free formNo credit card needed. Free includes one project and 50 form messages per month.