This guide sets up a contact form with reCAPTCHA which submits to Google Forms and through Google Sheets and Google Apps Scripts, e-mails the contents of the form to a specified e-mail address. No backend code is necessary; works on Github Pages, Google Sites, etc.

This process is used in production on

Step 1: Register site with reCAPTCHA

Go to

Create reCAPTCHA v3 keys for your domain, accepting the Terms of Service.

Make note of your Keys and the instructions in Step 1: Client side integration.

Step 2: Create a new Google Form

Go to

Create a new form with Name, E-mail Address, and Captcha duplicated as Short Answer and Details as Long Answer.

From the vertical ... menu on the very top right, click Get pre-filled link. Fill out the form with test data, click Get Link, then Copy Link on the notification tooltip.

Paste (Ctrl+v) into a text editor should reveal:

Make note of the form id 1FAIpQLSedjbJpryT29PkE6WHU1d2YAEopnYLFlYzoWTLwjoq30k-TdQ as well as each entry.* which matches up with Name, E-mail Address, Captcha and Details defined above.

In Google Forms Responses tab, click the green spreadsheet icon in the upper right. Select Create a new spreadsheet, give it a name, and click Create.

A new browser tab to should open.

Go to Tools menu, then Script editor.

A new browser tab to should open.

Step 3: Setup Google Apps Script

Go to File menu, New, then New HTML file.

Name the file GoogleSheetsEmailer, then click OK.

In GoogleSheetsEmailer.html, replace the entire contents with:

<?= details ?>
<?= name ?>
<a href="mailto:<?= email ?>"><?= email ?></a>

In, replace the entire contents with:

// adjust these to your needs
var EMAIL_TO = '';
var FORM_NAME = 'Online Contact Form';
var NO_REPLY = '';

function respondToFormSubmit(e) {
  if (!verifyCaptcha(e.namedValues['Captcha'])) {
    // if reCAPTCHA fails, do not send e-mail

  // set e-mail subject & replyTo
  var subject = FORM_NAME;

  var em = e.namedValues['E-mail Address'];
  var replyTo = em && em != '' ? em : NO_REPLY;

  var fn = e.namedValues['Name'];
  if (fn && fn != '') {
    replyTo = fn + ' <' + replyTo + '>';
    subject = fn + ' : ' + subject;

  // build e-mail template & assign template variables
  var template = HtmlService.createTemplateFromFile('GoogleSheetsEmailer'); = fn; = em;
  template.details = e.namedValues['Details'];

  var message = template.evaluate();

  // send e-mail using MailApp
    to: EMAIL_TO,
    subject: subject,
    replyTo: replyTo,
    htmlBody: message.getContent()

// verify reCAPTCHA using UrlFetchApp
function verifyCaptcha(captcha){
  var resp = UrlFetchApp.fetch('' +
    RECAPTCHA_SECRET_KEY + '&response=' + captcha).getContentText();
  return JSON.parse(resp).success;

Adjust the variables EMAIL_TO, FORM_NAME, NO_REPLY to meet your needs and set RECAPTCHA_SECRET_KEY to the key created in Step 1: Register site with reCAPTCHA.

Save both and GoogleSheetsEmailer.html.

Step 4: Create Google Apps Script Trigger

Go to Edit menu, then Current project's triggers, then No triggers set up. Click here to add one now.

Run: respondToFormSubmit.

Events: From spreadsheet => On form submit.

Click Save.

A small browser window should open asking to allow this script access to your Google account. This account will be the one which e-mails the form to the desired EMAIL_TO address. Be sure to complete this process.

Step 5: Create HTML Form

The following HTML form code uses for styling, but can be adapted to fit your needs.

Make note that the form submits to and includes your form id.

Also note that each input is named entry.* and matches up with pre-filled link results taken from Step 2: Create a new Google Form.

The form target="hiddenIf" and corresponding iframe prevents the form submission from redirecting the browser to

<iframe name="hiddenIf" id="hiddenIf" style="display:none;"></iframe>

<form id="contact-form" target="hiddenIf" onsubmit="submitForm(event);" class="pure-form pure-form-stacked"

    <label for="entry.629821244">Name</label>
    <input type="text" name="entry.629821244" class="pure-input-1"
      placeholder="Enter your name..." value="" required />

  <div class="mar-t1">
    <label for="entry.2054212185">E-mail Address</label>
    <input type="email" name="entry.2054212185" class="pure-input-1"
      placeholder="Enter your email address..." value="" />

  <div class="mar-t1">
    <label for="entry.692430337">Details</label>
    <textarea name="entry.692430337" rows="5" class="pure-input-1"
      placeholder="Start the conversation here..."></textarea>

  <input id="google-recaptcha" type="hidden" name="entry.1654889841" value="" />

  <div class="mar-t1">
    <input id="button-submit" class="pure-button pure-button-primary" type="submit" value="Submit" disabled />


<div id="contact-success"></div>

<script type="text/javascript">
  grecaptcha.ready(function() {
    grecaptcha.execute('6LewlHcUAAAAANs39m7L77fI8e-QYNREAeSY78fX', {action: 'contact_form'})
    .then(function(token) {
      // copy recaptcha response to hidden input
      document.getElementById('google-recaptcha').value = token;
      // enable form submit
      document.getElementById('button-submit').disabled = false;

  function submitForm(e) {
    var msg = 'Thank you for contacting us. We will get back to you shortly.';

    // simulate feel of connection with timeout
    setTimeout(function() {
      document.getElementById('contact-form').style.display = "none";
      document.getElementById('contact-success').innerHTML = msg;
    }, 300);