Templates

HTML contact form templates that actually send.

Every template below posts to Heartdove, so it works the moment you paste in your access key. No PHP file, no mail library, no server. Pick one, keep your own styling, and every submission is saved to your inbox and emailed to you with delivery tracking.

Updated 20 October 2026

Make any template live in three steps

  • Create a form in your Heartdove workspace and register the website address the form will live on. Registering www.yourdomain.com covers yourdomain.com too.
  • Copy the access key into the hidden access_key field. The key is public; it identifies the form and nothing else.
  • Paste the form into your page and publish. Send yourself a test message and watch it arrive in the inbox with its delivery timeline.

Keep the hidden botcheck field in every template. People never see it, bots tick it, and anything that ticks it is quarantined instead of alerting you.

Simple contact form (name, email, message)

Unstyled and accessible: every input has a label, the browser validates required fields, and autocomplete attributes help visitors fill it in.

contact.html
<form action="https://submit.heartdove.com/v1/submit" method="POST">
  <input type="hidden" name="access_key" value="YOUR_ACCESS_KEY" />

  <label for="name">Name</label>
  <input id="name" type="text" name="name" autocomplete="name" required />

  <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></textarea>

  <!-- Hidden spam trap: people never see it, bots tick it -->
  <input type="checkbox" name="botcheck" tabindex="-1" autocomplete="off" style="display:none" />

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

Contact form with a subject dropdown

Let visitors pick a topic so you can sort enquiries at a glance. Because the dropdown is named subject, the choice becomes the subject line of the message in your inbox and of the email alert.

Preview
contact.html
<form action="https://submit.heartdove.com/v1/submit" method="POST">
  <input type="hidden" name="access_key" value="YOUR_ACCESS_KEY" />

  <label for="name">Name</label>
  <input id="name" type="text" name="name" autocomplete="name" required />

  <label for="email">Email</label>
  <input id="email" type="email" name="email" autocomplete="email" required />

  <!-- Named "subject", so the choice becomes the subject line in your inbox and alert email -->
  <label for="subject">What is it about?</label>
  <select id="subject" name="subject" required>
    <option value="" disabled selected>Choose a topic</option>
    <option>Sales question</option>
    <option>Support</option>
    <option>Billing</option>
    <option>Something else</option>
  </select>

  <label for="message">Message</label>
  <textarea id="message" name="message" rows="5" required></textarea>

  <input type="checkbox" name="botcheck" tabindex="-1" autocomplete="off" style="display:none" />
  <button type="submit">Send message</button>
</form>

Quote request form (phone, dropdown, radio buttons, checkboxes)

For service businesses: a phone number, a service dropdown, a budget choice, optional extras and a consent box. Each answer appears as its own labelled field in the inbox and the alert, and a hidden subject marks every message as a quote request.

Preview

With the boxes ticked as shown, the message arrives with Budget: $5k to $15k and Extras: Hosting, SEO.

quote.html
<form action="https://submit.heartdove.com/v1/submit" method="POST">
  <input type="hidden" name="access_key" value="YOUR_ACCESS_KEY" />
  <input type="hidden" name="subject" value="Quote request" />

  <label for="name">Name</label>
  <input id="name" type="text" name="name" autocomplete="name" required />

  <label for="email">Email</label>
  <input id="email" type="email" name="email" autocomplete="email" required />

  <label for="phone">Phone (optional)</label>
  <input id="phone" type="tel" name="phone" autocomplete="tel" />

  <label for="service">Service</label>
  <select id="service" name="service" required>
    <option value="" disabled selected>Choose a service</option>
    <option>New website</option>
    <option>Redesign</option>
    <option>Ongoing support</option>
  </select>

  <fieldset>
    <legend>Budget</legend>
    <label><input type="radio" name="budget" value="Under $5k" required /> Under $5k</label>
    <label><input type="radio" name="budget" value="$5k to $15k" /> $5k to $15k</label>
    <label><input type="radio" name="budget" value="Over $15k" /> Over $15k</label>
  </fieldset>

  <!-- A checkbox group shares one name; the ticked boxes arrive as "Hosting, SEO" -->
  <fieldset>
    <legend>Also interested in</legend>
    <label><input type="checkbox" name="extras[]" value="Hosting" /> Hosting</label>
    <label><input type="checkbox" name="extras[]" value="Copywriting" /> Copywriting</label>
    <label><input type="checkbox" name="extras[]" value="SEO" /> SEO</label>
  </fieldset>

  <label for="message">Project details</label>
  <textarea id="message" name="message" rows="5" required></textarea>

  <label><input type="checkbox" name="consent" value="yes" required /> You can contact me about this request</label>

  <input type="checkbox" name="botcheck" tabindex="-1" autocomplete="off" style="display:none" />
  <button type="submit">Request a quote</button>
</form>

Contact form with a thank-you page

Add a hidden _redirect field and the visitor lands on your own page after sending. The address must be on a website registered for the form; redirects elsewhere are refused.

contact.html
<form action="https://submit.heartdove.com/v1/submit" method="POST">
  <input type="hidden" name="access_key" value="YOUR_ACCESS_KEY" />
  <!-- A page on one of the websites registered for this form -->
  <input type="hidden" name="_redirect" value="https://www.yourdomain.com/thanks" />

  <label for="email">Email</label>
  <input id="email" type="email" name="email" required />

  <label for="message">Message</label>
  <textarea id="message" name="message" rows="5" required></textarea>

  <input type="checkbox" name="botcheck" tabindex="-1" autocomplete="off" style="display:none" />
  <button type="submit">Send message</button>
</form>

Bootstrap 5 contact form

Uses the Bootstrap grid and form classes. Name and email sit side by side on wider screens.

contact.html
<form action="https://submit.heartdove.com/v1/submit" method="POST" class="row g-3">
  <input type="hidden" name="access_key" value="YOUR_ACCESS_KEY" />
  <div class="col-md-6">
    <label for="name" class="form-label">Name</label>
    <input type="text" class="form-control" id="name" name="name" required />
  </div>
  <div class="col-md-6">
    <label for="email" class="form-label">Email</label>
    <input type="email" class="form-control" id="email" name="email" required />
  </div>
  <div class="col-12">
    <label for="message" class="form-label">Message</label>
    <textarea class="form-control" id="message" name="message" rows="5" required></textarea>
  </div>
  <input type="checkbox" name="botcheck" tabindex="-1" autocomplete="off" class="d-none" />
  <div class="col-12">
    <button type="submit" class="btn btn-primary">Send message</button>
  </div>
</form>

Tailwind CSS contact form

Utility classes for a card-style form. Swap the colours for your palette.

contact.html
<form action="https://submit.heartdove.com/v1/submit" method="POST" class="mx-auto max-w-md space-y-4">
  <input type="hidden" name="access_key" value="YOUR_ACCESS_KEY" />
  <label class="block text-sm font-medium text-slate-700">Email
    <input type="email" name="email" required class="mt-1 w-full rounded-lg border border-slate-300 px-3 py-2 focus:border-indigo-500 focus:outline-none" />
  </label>
  <label class="block text-sm font-medium text-slate-700">Message
    <textarea name="message" rows="5" required class="mt-1 w-full rounded-lg border border-slate-300 px-3 py-2 focus:border-indigo-500 focus:outline-none"></textarea>
  </label>
  <input type="checkbox" name="botcheck" tabindex="-1" autocomplete="off" class="hidden" />
  <button type="submit" class="w-full rounded-lg bg-indigo-600 px-4 py-2.5 font-semibold text-white hover:bg-indigo-700">Send message</button>
</form>

AJAX contact form (no page reload)

Posts the form with fetch as a regular form submission, so the hidden spam trap and checkbox groups behave exactly as in plain HTML, and shows the result in place. The Idempotency-Key makes a retry safe; reuse the same key if you add retry logic.

contact.html
<form id="contact">
  <label for="email">Email</label>
  <input id="email" type="email" name="email" required />
  <label for="message">Message</label>
  <textarea id="message" name="message" rows="5" required></textarea>
  <input type="checkbox" name="botcheck" tabindex="-1" autocomplete="off" style="display:none" />
  <button type="submit">Send message</button>
  <p id="status" role="status"></p>
</form>

<script>
  const form = document.getElementById('contact');
  const status = document.getElementById('status');
  form.addEventListener('submit', async event => {
    event.preventDefault();
    status.textContent = 'Sending…';
    const response = await fetch('https://submit.heartdove.com/v1/submit', {
      method: 'POST',
      headers: { Accept: 'application/json', 'Idempotency-Key': crypto.randomUUID() },
      // Sent as a regular form post, so the spam trap and checkbox groups work exactly as in plain HTML.
      body: (() => { const data = new URLSearchParams(new FormData(form)); data.set('access_key', 'YOUR_ACCESS_KEY'); return data; })(),
    });
    status.textContent = response.ok ? 'Thanks, your message is in.' : 'Something went wrong. Please try again.';
  });
</script>

Add your own fields

Any input with a name is stored, up to 50 fields of 10,000 characters each: phone numbers, select menus, radio groups and checkboxes. Each field appears in the inbox and in the email alert under the name you gave it. A checkbox group or multi-select can share one name, written extras or extras[]; the ticked values arrive together as “Hosting, SEO”. Name a field subject and it becomes the message’s subject line. Uploads are not accepted, so leave file inputs out.

Questions

Do these templates work on WordPress, Squarespace, Webflow or Shopify?

Yes. Paste the form into a Custom HTML block, a Code block, an Embed element or a Custom Liquid section. The form posts to Heartdove instead of relying on the host to send mail.

Why not use a mailto: form?

A mailto: action opens the visitor’s email program and depends on them finishing the job. You get no record and no way to know whether anything was sent.

Can I style the form however I want?

Yes. Heartdove is an endpoint, not a widget. Nothing is injected into your page, so your markup, classes and components stay exactly as they are.

What stops spam without a CAPTCHA?

Every form gets an exact origin check, a per-visitor rate limit, the hidden trap and spam scoring with quarantine. Cloudflare Turnstile is optional for forms that want a human check.

Never lose another enquiry.

Connect your first form in a few minutes. Your existing design stays exactly as it is.