integrations · site builder

A contact form for Ghost, which has no way to receive one.

Ghost will take an email address off a visitor and turn it into a member. That is the only inbound path it has. There is no contact form, no form block in the editor, and nothing in the admin that stores a message someone typed to you. The standard workaround is to publish your email address on a contact page, which is how you end up on every scraper's list within a fortnight.

The fix is not a plugin, because Ghost does not have those. It is markup. Paste a form into an HTML card, a page, or your theme, point it at a mailcontact endpoint, and messages land in your project inbox with a ping in Discord, Slack, email, or a webhook.

recommended setup

Use the MailContact script with your own design.

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.

contact.html
<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

Alternative: a direct integration for Ghost.

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.

HTML card, or themes/your-theme/page-contact.hbs
<!-- Editor: insert an HTML card and paste this in.
     Theme: drop it into page-contact.hbs and publish a page
     with the "contact" slug. Either works; the card needs no theme edit. -->

<form action="https://mailcontact.app/api/forms/your-form-id" method="POST">
  <input type="text" name="name" placeholder="Your name" required />
  <input type="email" name="email" placeholder="[email protected]" required />
  <textarea name="message" placeholder="What's on your mind?" required></textarea>

  <!-- Honeypot: bots fill it, humans never see it. -->
  <input type="text" name="company_website" type="text" tabindex="-1" autocomplete="off"
      style="position:absolute;left:-10000px" aria-hidden="true" />

  <button type="submit">Send</button>
</form>

how it works

Three steps, start to finish.

01

Create an inbox

One inbox per publication. You get a form endpoint and a project email address like [email protected] straight away.

02

Paste it into a page

In the editor, add an HTML card to a new page called Contact and paste the form. If you would rather it live in the theme, put it in page-contact.hbs instead. The card route needs no theme access at all.

03

Get notified

Add a Discord, Slack, email, or webhook channel. A reader's message reaches you without you logging into Ghost admin to find it.

why mailcontact

Built to pair well with Ghost.

Ghost has no plugin system to fight

There is no marketplace to search and no extension to keep compatible across Ghost upgrades. An HTML card is a supported, first-class thing in the editor, so this survives every future version by construction.

Members are not messages

Ghost's signup form creates a member and sends them a magic link, which is the wrong shape for someone asking a question. A reader who wants to talk to you should not become a subscriber as a side effect.

Your address stays off the page

The alternative to a form on Ghost is publishing your email in plain text where every harvester on the internet can read it. A form gives readers the same reach with none of that.

faq

Ghost + mailcontact, answered

Does Ghost have a built-in contact form?

No. Ghost's only inbound form is member signup, which captures an email address to create a subscriber. There is no field for a message, and nothing in Ghost admin stores one. Every contact page on a Ghost site is either a published email address or an embedded third-party form.

Do I need to edit my theme?

No. The HTML card in the editor is enough: create a page, insert the card, paste the markup, publish. Editing page-contact.hbs is only worth it if you want the form to appear on several pages or to be styled by your theme's own CSS classes.

Can I use this on Ghost(Pro)?

Yes. The HTML card route needs no file access, so it works identically on Ghost(Pro) and self-hosted. Even on Ghost(Pro), where theme uploads are allowed, the card is the simpler path for a single contact page.

Can I style it with my theme's classes?

Yes. It is plain markup inside your page, so add whatever class names your theme uses on its own inputs and buttons and it inherits the same styling. mailcontact only reads the name attributes: email and message are required, name and subject are optional; company_website must also be present and empty.

related

Also works with

One inbox for every Ghost project you ship.

Forms and a real email address, together, with notifications where you live. Start with a free account.

Create your free form

No credit card needed. Free includes one project and 50 form messages per month.