GatsbyJS限定というわけでもないのですが、 問い合わせフォームをスプレッドシートに送信する仕組みを実装しました。 JavascriptからfetchでスプレッドシートのGAS(GoogleAppsScript)へ投げます。
問い合わせページHTML部
ChatGPTに聞いておおまかなパーツを作ってもらいます。

スタイルとボタン処理を加えて、HTML部分は以下のようになりました。 ハニーポットなどbot対策は問題が発生してから対応します。YAGNI(ヤグニ)の精神です(# 覚えられない)。
“You ain’t gonna need it”、縮めて YAGNI とは、機能は実際に必要となるまでは追加しないのがよいとする、エクストリーム・プログラミングにおける原則である。
wiki
<form method="POST" onSubmit={doSubmit}>
<div className="main-heading">お問い合わせ</div>
<label htmlFor="name">名前:</label>
<input type="text" id="name" name="name"
placeholder="お名前"
maxLength="30"
minLength="2"
autoComplete="name"
required/>
<label htmlFor="email">メールアドレス:</label>
<input type="text" id="email" name="email"
placeholder="メールアドレス"
autoComplete="email"
required/>
<label htmlFor="message">メッセージ:</label>
<textarea id="message" name="message"
rows="8"
placeholder="お問い合わせ内容"
required></textarea>
<div id="controls">
<input type="button" id="btn_cancel" onClick={doCancel} value="修正する" style={{display:`none`}}/>
<input type="submit" id="btn_submit" value="確認する"/>
</div>
</form>
問い合わせページJavascript部
「doSubmit」と「doCancel」の処理を以下のようにしました。 送信前に一旦コントロールをdisabledにして確認するフェーズをはさみます。 ゴリゴリのjsゴリラなのでjsでゴリ押ししてます(# もっと最新のスマートな方法募集)。
async function doSubmit(e) {
if(!e) return;
e.preventDefault();
const doms = document.querySelectorAll("input[type='text'],textarea");
if (document.body.classList.contains("confirm")) {
// 見た目
document.querySelector("#controls").innerHTML = `<input type="button" value="送信中..."/>`;
document.body.classList.remove("confirm");
// 送信処理
const forms = {};
doms.forEach(dom => {forms[dom.name] = dom.value;});
const URL = `${process.env.GATSBY_MAILFORM_URL}`;
const postparam = {
"method" : "POST",
"mode" : "no-cors",
"Content-Type" : "application/x-www-form-urlencoded",
"body" : JSON.stringify(forms)
};
await fetch(URL, postparam);
// 見た目
document.querySelector("#controls").innerHTML = `<input type="button" value="送信しました"/>`;
}
else {
// 見た目
doms.forEach((dom)=>{dom.setAttribute("disabled","");})
document.body.classList.add("confirm");
document.querySelector("#btn_cancel").style.display = "";
document.querySelector("#btn_submit").value = "送信する";
}
return false;
}
function doCancel(e) {
// 見た目
const doms = document.querySelectorAll("input[type='text'],textarea");
doms.forEach((dom)=>{dom.removeAttribute("disabled");});
document.body.classList.remove("confirm");
document.querySelector("#btn_cancel").style.display = "none";
document.querySelector("#btn_submit").value = "確認する";
}
${process.env.GATSBY_MAILFORM_URL}
のところは環境変数です。
.env
ファイルに変数を入れて外部で管理します。
デプロイ先の環境変数にも同じ名前で登録しておくと実際のページでも参照されます。
仕組みが理解できていませんが、直にページに書かないようにできるので利用します。
参考:(https://qiita.com/xrxoxcxox/items/4e337b96fc9017b3771c)
require("dotenv").config();
module.exports = {
GATSBY_MAILFORM_URL = "https://script.google.com/macros/s/XXXXXX/exec"
GATSBY_MAILFORM_URLはこのあと作るスプレッドシートのデプロイURLです。 スプレッドシートがデプロイ出来たら編集します。
スプレッドシートの作成
フォームデータを受け取るGoogleSpreadSheetを作成し、
シート1の名前を「form」にします。(# ファイルもシートと言うしファイル内の「シート」もシートというので分けた言い方募集)
1行目をラベル行として日付、名前、アドレス、内容など書いておきます。
メニュー → 拡張機能 → Apps Script
でGASを起動します。
Googleアカウントを複数使役している人は「デフォルト」のアカウントで起動しないといけないので注意してください。
参考:(https://pkunallnet.com/pcinfo/google/gasnoopen/)

doPost関数を作りWebアプリとしてデプロイし、できたURLをGATSBY_MAILFORM_URLに適用します。
function doPost(e){
if (!e) return;
if (typeof(e["postData"]) === 'undefined') return;
if (typeof(e.postData["contents"]) === 'undefined') return;
const data = JSON.parse(e.postData.contents);
const text_date = Utilities.formatDate(new Date(), "JST","yyyy-MM-dd HH:mm:ss");
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('form');
sheet.insertRowBefore(2);
sheet.getRange(2, 1, 1, 4).setValues([[text_date, data["name"], data["email"], data["message"]]]);
}
おわりに
環境変数でJavascript内の固有値を隠ぺい(?)できるので、
クライアント処理だけで各種サービスを往来できるのは便利な世の中です。
実際にはGASで受け取ったらLINE NotifyでLINEに通知するようにしました。