どうも。Kenny(tsujikenzo)です。今日は単発で自分用メモです。 「【無料】WEBサイトのお問い合わせフォームをGASとスプレッドシートで実装!ハマりポイントも解説」 をお送りします。
はじめに
この記事を書く背景
最近、LP(ペライチ、かんたんなWEBサイトなど)を作成する機会が多くなりました。AIによるコーディング技術がかなり高度になっておりますが、問い合わせフォームはまだまだ実装がむずかしいです。
そして、フォームの送信を受け取ったら、リダイレクト処理をすればいいだけだと思ったら、ハマるポイントがあったので、メモしておきます。
やりたいこと
LPやWEBサイトに、以下のようなシンプルなお問い合わせフォームを実装したいです。 
送信ボタンを押すと、スプレッドシートにデータが書き込まれます。

確認メールも、自動で送信されます。

ユーザーには、サンクスページを表示します。(リダイレクト処理) 
※このリダイレクト処理がハマりポイントでした💦
何にハマったのか
GASには、HTMLを返すサービスが提供されています。なので、送信ボタンが押されたら、サンクスページを表示させればいいはずです。
以下は、meta http-equiv=”refresh” タグを使って、0秒後に thankYouPageUrlへリダイレクトするようブラウザに指示するHTMLを返しています。
function doPost(e) {
// --- 1. リダイレクト先のURLを指定 ---
const thankYouPageUrl = "https://example.com/thanks.html";
// --- 2. リダイレクト指示を含むHTMLを生成して返す ---
const htmlOutput = HtmlService.createHtmlOutput(
`<html>
<head>
<title>処理中...</title>
<meta http-equiv="refresh" content="0; url=${thankYouPageUrl}">
</head>
<body>
<p>送信完了しました。ページを移動します...</p>
</body>
</html>`
);
// ブラウザにHTMLを返す(これがリダイレクト指示となる)
return htmlOutput;
}
しかし、うまくリダイレクトされません。ブラウザは真っ白な画面のままです。これはGAS側でセキュリティ制約があるのだと思います。(とAIが言ってました)
そこで、次に試したのが、HTML側のJavaScriptを使ってリダイレクトを制御する方法です。
- GAS側は処理成功を示すシンプルなテキスト(例: “success”)を返すだけにする。
- リダイレクト自体はフォームを送信したページのJavaScriptで行う。
この方法で、最終的にリダイレクト処理を実現できました。具体的なコードは、次のセクションで解説します。
このブログで作成するもの
- スプレッドシート
- WEBアプリとしてデプロイしたURL
- index.html
- thanks.html
- script.js
対象読者
ウェブサイトに問い合わせフォームを設置したい個人事業主、中小企業担当者、プログラミング中級者など。FTPサーバーにファイルをアップロードできるスキルが必要です。
スプレッドシートの用意
まず、スプレッドシートを用意します。
目的
フォームから送信されたデータを記録・管理するためのデータベースとして使用します。
手順
Googleドライブで新規スプレッドシートを作成。シート名を分かりやすく変更しておきます。(手順は省略します)
スプレッドシートの1行目にヘッダー行を作成します。現時点では、「送信日時」「お名前」など、仮の値を設定しておきましょう。(後で変更するのでなんでもOKです) 
このヘッダー行は、お問い合わせフォームの見出しと、一致させます(後でやります)。 
ウェブアプリの用意 (GAS: Google Apps Script)
次にGASを書きます。
目的
WEBサイトから送信されたデータを受け取り、スプレッドシートに書き込み、メール通知を行い、処理結果を返すため。
手順1.doPost(e)関数の作成
スプレッドシートのコンテナバインドスクリプトを開きます。
doPost(e) 関数を作成します。おおまかな流れは以下のとおりです。
- フォームデータの受け取り
- かんたんなバリデーション
- スプレッドシートへの書き込み
- メール通知
- 成功応答(今回のキモ★★★)
/**
* HTMLフォームからPOSTリクエストを受け取ったときに実行される関数
* @param {Object} e - イベントオブジェクト。フォームデータは e.parameter に格納される
* @return {ContentService.TextOutput} - 処理結果を示すテキスト ("success" またはエラーメッセージ)
*/
function doPost(e) {
// --- [1] フォームデータの受け取り ---
// e.parameter オブジェクトから、HTMLフォームの name 属性に対応する値を取得
// || '' は、もしフォームにその項目がなくてもエラーにならないようにするための記述
const inquiryType = e.parameter.inquiry_type || '未選択'; // お問い合わせ種別 (例)
const companyName = e.parameter.company_name || ''; // 会社名 (例)
const contactName = e.parameter.contact_name || ''; // 担当者名 (例)
const email = e.parameter.email || ''; // メールアドレス (例)
const message = e.parameter.message || ''; // お問い合わせ内容 (例)
const privacyPolicy = e.parameter.privacy_policy || ''; // 同意チェック (例)
// --- [2] かんたんなバリデーション ---
// 最低限、メールアドレスと同意があるかチェック
if (!email || privacyPolicy !== 'agreed') {
Logger.log("エラー: 必須項目が不足しているか、同意がありません。");
// エラーを示すテキストを返す
return ContentService.createTextOutput("error: Missing required fields or privacy not agreed.");
}
// --- [3] スプレッドシートへの書き込み ---
try {
const sheetName = "シート1"; // ★書き込みたいシート名を指定
const ss = SpreadsheetApp.getActiveSpreadsheet();
const sheet = ss.getSheetByName(sheetName);
if (sheet) {
// appendRow() で新しい行にデータを追記
// 配列の順番は、スプレッドシートの列の順番に合わせる
sheet.appendRow([
new Date(), // A列: タイムスタンプ
inquiryType, // B列: お問い合わせ種別
companyName, // C列: 会社名
contactName, // D列: 担当者名
email, // E列: メールアドレス
message // F列: お問い合わせ内容
]);
Logger.log(`データをシート「${sheetName}」に書き込みました。`);
} else {
Logger.log(`エラー: シート「${sheetName}」が見つかりません。`);
throw new Error(`Sheet "${sheetName}" not found.`); // エラーを発生させてcatchへ
}
} catch (error) {
Logger.log("スプレッドシート書き込みエラー: " + error);
return ContentService.createTextOutput("error: Failed to record data."); // エラー応答
}
// --- [4] メール通知 ---
try {
const subjectUser = "【株式会社はじめ】お問い合わせありがとうございます"; // ユーザー向け件名
const subjectAdmin = `【はじめてLP】お問い合わせがありました (${contactName}様)`; // 管理者向け件名
const adminEmail = "kenny@yahoo.co.jp"; // ★管理者メールアドレス
// メール本文(共通部分)
const body = `以下の内容でお問い合わせを受け付けました。\n\n` +
`--------------------\n` +
`お問い合わせ種別: ${inquiryType}\n` +
`会社名: ${companyName}\n` +
`お名前: ${contactName}\n` +
`メールアドレス: ${email}\n` +
`内容:\n${message}\n` +
`--------------------\n\n` +
`※このメールは自動送信です。\n\n` +
`株式会社はじめ \nhttps://hajime.com/`;
// ユーザーへ自動返信
if (email) { // メールアドレスがあれば送信
GmailApp.sendEmail(email, subjectUser, body);
Logger.log(`自動返信メールを ${email} へ送信しました。`);
}
// 管理者へ通知
GmailApp.sendEmail(adminEmail, subjectAdmin, body);
Logger.log(`管理者通知メールを ${adminEmail} へ送信しました。`);
} catch (error) {
Logger.log("メール送信エラー: " + error);
}
// --- [5] 成功応答 ---
// ★★★ 今回のキモ! ★★★
// 処理が正常に完了した場合、"success" というテキストを返す。
Logger.log("全ての処理が正常に完了。'success'を返します。");
return ContentService.createTextOutput("success");
} // doPost 関数の終わり10~15行目のフォームの見出し(スプレッドシートのヘッダー行)は、増やしたり減らしたり自由に設定できます。こちらを適宜変更しましょう。
const inquiryType = e.parameter.inquiry_type || '未選択'; // お問い合わせ種別 (例)
const companyName = e.parameter.company_name || ''; // 会社名 (例)
const contactName = e.parameter.contact_name || ''; // 担当者名 (例)
const email = e.parameter.email || ''; // メールアドレス (例)
const message = e.parameter.message || ''; // お問い合わせ内容 (例)
const privacyPolicy = e.parameter.privacy_policy || ''; // 同意チェック (例)同様に、スプレッドシートへ書き込む値や、メール送信する値も、変更可能です。
sheet.appendRow([
new Date(), // A列: タイムスタンプ
inquiryType, // B列: お問い合わせ種別
companyName, // C列: 会社名
contactName, // D列: 担当者名
email, // E列: メールアドレス
message // F列: お問い合わせ内容
]);変数が一致するように、気をつけてください。
// メール本文(共通部分)
const body = `以下の内容でお問い合わせを受け付けました。\n\n` +
`--------------------\n` +
`お問い合わせ種別: ${inquiryType}\n` +
`会社名: ${companyName}\n` +
`お名前: ${contactName}\n` +
`メールアドレス: ${email}\n` +
`内容:\n${message}\n` +
`--------------------\n\n` +
`※このメールは自動送信です。\n\n` +
`株式会社はじめ \nhttps://hajime.com/`;手順2.WEBアプリとしてデプロイ
「デプロイ」から「新しいデプロイ」を選択します。種類は「ウェブアプリ」です。
「実行するユーザー:自分」「アクセスできるユーザー:全員」を選択します。
この設定を間違えると、ただしく動作しませんので、お間違えないように。 
デプロイすると、ウェブアプリURLが発行されるので、コピーしておきます。

index.htmlの用意
次は、htmlです。
目的
ユーザーがフォームを入力するための、WEBサイトの骨組みです。
ポイント
- action属性に、GASをデプロイして取得したウェブアプリURLを設定します。
- name属性の値を、GASのe.parameterで受け取るキーと正確に一致させます。 (例: name=”company_name”)
- 必須項目には required属性を追加しています。
具体的なコード
ポイントはいくつかありますが、コーディングはAIに任せてしまいましょう。
以下のプロンプトを生成AIにぶち込んで、index.htmlを出力してもらいます。プロンプトを作成するときに、フォームの見出しを必要な項目に変更するとラクです。
## 指示:
Google Apps Script (GAS) のWebアプリケーション(doPost)でデータを受け取ることを想定した、株式会社はじめのお問い合わせフォームを主要コンテンツとする、シンプルなランディングページ(LP)の完全なHTMLコード (`index.html`) を生成してください。フォーム送信はJavaScript (`assets/js/script.js`) を使用して非同期で行い、GASからの応答に基づいてサンクスページへリダイレクトします。
## 目的:
GASと連携するHTMLフォーム(JavaScriptによる非同期送信とリダイレクト)の基本的な実装例を作成する。
## 技術仕様:
* HTML: HTML5、セマンティックタグ使用。
* CSS: `assets/css/style.css`, `assets/css/reset.css`, `assets/css/responsive.css` を参照する前提で基本的なクラス名を付与。モバイルファースト考慮。
* JavaScript: 使用する (`assets/js/script.js` を読み込む)。 Vanilla JS (ES6+) で、フォーム送信の `preventDefault()`、`fetch` APIによる非同期POST、GAS応答に基づく `window.location.href` によるリダイレクト、送信中/エラーステータス表示を行う。
* フレームワーク/ライブラリ: 使用しない。
## LP構成(アウトライン):
1. ヘッダー: 企業ロゴ (ダミーパス: `assets/images/logo/logo.png`)。
2. ダミーコンテンツセクション:
* 見出し (`h2 class="section-title"`) と簡単な説明文 (`p class="section-text"`) を1つだけ配置(内容はダミーで良い)。
3. お問い合わせフォームセクション (ID: `section-contact`):
* 見出し (`h2 class="section-title"`): 「お問い合わせフォーム」
* リード文 (`p class="section-text"`): 簡単な説明。
* `<form>` タグ:
* `id="contact-form"`
* `method="post"`
* `action="YOUR_GAS_WEB_APP_URL"` ← **この部分は変更しないでください**
* フォーム項目(すべて `<div class="form-group">` で囲む):
* 会社名 (`label for="company_name"`, `input type="text" id="company_name" name="company_name" required`)
* 担当者名 (`label for="contact_name"`, `input type="text" id="contact_name" name="contact_name" required`)
* メールアドレス (`label for="email"`, `input type="email" id="email" name="email" required`)
* 電話番号 (`label for="phone"`, `input type="tel" id="phone" name="phone"`)
* お問い合わせ種別 (`label for="inquiry_type"`, `select id="inquiry_type" name="inquiry_type" required` 内に `option` を複数設定、初期値は `disabled selected`)
* お問い合わせ内容 (`label for="message"`, `textarea id="message" name="message" rows="5" required`)
* プライバシーポリシー同意 (`div class="form-group privacy-policy-agreement"`)
* チェックボックス (`input type="checkbox" id="privacy_policy" name="privacy_policy" value="agreed" required`)
* ラベル (`label for="privacy_policy"`) 内にポリシーページへの仮リンク (`a href="#"`) を含むテキスト。
* 送信ボタン (`div class="form-submit"`, `button type="submit" class="button button-primary"`)
* 送信ステータス表示用 (`p id="form-status" class="form-status"`) ← これが重要
4. フッター:
* コピーライト(年号部分は `id="copyright-year"` を付与)。
## HTML生成時の注意点:
* 完全な `index.html` ファイルとして、`<!DOCTYPE html>`, `<html>`, `<head>`, `<body>` タグを含めてください。
* `<head>` 内には基本的なメタタグ(charset, viewport, title, description)、faviconリンク、CSSリンク (`reset.css`, `style.css`, `responsive.css`) を含めてください。
* 本文は `<main>` タグで囲み、各セクションは `<section>` タグを使用してください。
* クラス名は、CSSでのスタイリングを想定して適切に付与してください(例: `.container`, `.section-title`, `.form-group`, `.button` など)。
* フォームの `action` 属性は `"YOUR_GAS_WEB_APP_URL"` のままにしてください。
* `</body>` タグの直前に `<script src="assets/js/script.js"></script>` を含めてください。
* ヒーローセクション等の他のコンテンツは不要です。
以下は、実装予定であるGASのWebアプリケーションです。
###ここから
~GASを貼り付ける~
###ここまで
わたしの環境では、以下のようなhtmlを出力しました。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>お問い合わせフォーム - 株式会社はじめ</title>
<meta name="description" content="株式会社はじめへのお問い合わせはこちらのフォームからお願いいたします。">
</head>
<body>
<header class="header">
</header>
<main>
<!-- 1. ダミーコンテンツセクション -->
<section class="section">
<div class="container">
<h2 class="section-title">ダミーセクション</h2>
<p class="section-text">
このランディングページは、お問い合わせフォームの動作を確認するためのものです。以下のフォームより、お気軽にお問い合わせください。
</p>
</div>
</section>
<!-- 2. お問い合わせフォームセクション -->
<section class="section section-contact section-light-gray" id="section-contact">
<div class="container">
<h2 class="section-title">お問い合わせフォーム</h2>
<p class="section-text">ご質問、資料請求、その他お問い合わせはこちらからお願いいたします。</p>
<!-- ▼▼▼ フォーム ▼▼▼ --> <!-- ★★★ 必ず最新のGASデプロイURLに差し替え ★★★ -->
<form id="contact-form"
action="YOUR_GAS_WEB_APP_URL"
method="post">
<!-- 会社名 (必須) -->
<div class="form-group">
<label for="company_name">会社名*</label>
<input type="text" id="company_name" name="company_name" required>
</div>
<!-- ご担当者名 (必須) -->
<div class="form-group">
<label for="contact_name">ご担当者名*</label>
<input type="text" id="contact_name" name="contact_name" required>
</div>
<!-- メールアドレス (必須) -->
<div class="form-group">
<label for="email">メールアドレス*</label>
<input type="email" id="email" name="email" required>
</div>
<!-- 電話番号 (任意) -->
<div class="form-group">
<label for="phone">電話番号</label>
<input type="tel" id="phone" name="phone">
</div>
<!-- お問い合わせ種別 (必須) -->
<div class="form-group">
<label for="inquiry_type">お問い合わせ種別*</label>
<select id="inquiry_type" name="inquiry_type" required>
<option value="" disabled selected>選択してください</option>
<option value="資料請求">資料請求</option>
<option value="商品について">商品について</option>
<option value="お見積り依頼">お見積り依頼</option>
<option value="その他">その他</option>
</select>
</div>
<!-- お問い合わせ内容 (必須) -->
<div class="form-group">
<label for="message">お問い合わせ内容*</label>
<textarea id="message" name="message" rows="5" required></textarea>
</div>
<!-- プライバシーポリシー同意 (必須) -->
<div class="form-group privacy-policy-agreement">
<input type="checkbox" id="privacy_policy" name="privacy_policy" value="agreed" required>
<label for="privacy_policy">
<a href="#" target="_blank" rel="noopener noreferrer">プライバシーポリシー</a>に同意する*
<!-- ★ aタグの href に実際のポリシーページのURLを設定してください -->
</label>
</div>
<!-- 送信ボタン -->
<div class="form-submit">
<button type="submit" class="button button-primary">送信 / Submit</button>
<!-- 送信ステータス表示用の p タグ -->
<p id="form-status" class="form-status"></p>
</div>
</form>
<!-- ▲▲▲ フォーム ▲▲▲ -->
</div>
</section>
</main>
<footer class="footer">
<div class="container">
<p class="copyright" id="copyright-year">©はじめ. All Rights Reserved.</p>
<!-- フッターナビ等、必要なら追加 -->
</div>
</footer>
<!-- ▼▼▼ JavaScript ファイルを読み込む ▼▼▼ -->
<script src="script.js"></script>
<!-- ▲▲▲ JavaScript ファイルを読み込む ▲▲▲ -->
ody>
</html>
メモ帳などにコピペしてindex.htmlとして保存しましょう。
28行目の”YOUR_GAS_WEB_APP_URL”に、先ほどメモしたデプロイURLを貼り付けましょう。
<!-- ▼▼▼ フォーム ▼▼▼ --> <!-- ★★★ 必ず最新のGASデプロイURLに差し替え ★★★ -->
<form id="contact-form"
action="YOUR_GAS_WEB_APP_URL"
method="post">Thanksページ
フォームを送信してもらったら、「ありがとうございました。」というページを表示させます。
以下が、シンプルなthanks.htmlページです。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>お問い合わせありがとうございます</title>
<meta name="robots" content="noindex,nofollow">
</head>
<body>
<h1>ありがとうございました</h1>
<p>お問い合わせを受け付けました。担当者からの返信をお待ちください。</p>
<p><a href="戻りたいページのURLを入力する">TOPページに戻る</a></p>
</body>
</html>
メモ帳などにコピペして、thanks.htmlとして保存しましょう。
script.jsの用意 (フォーム送信&リダイレクト処理)
最後に、フォーム送信の挙動を制御するJavaScriptを用意します。
JavaScriptは、以下の2つを担当します。
- 「送信ありがとうございます。」をブラウザに表示する
- 上記を表示するために、ブラウザを制御する
目的
- フォーム送信時のブラウザ標準動作をキャンセルする (preventDefault)。
- 入力データを非同期 (fetch) でGASに送信。
- GASからの応答 (“success”) を受け取って、サンクスページへリダイレクト (window.location.href)。
- 送信中やエラー時のメッセージ表示。
コードを出力するためのプロンプト
上記の目的を達成するための、プロンプトはこちらです。やはりAIにコーディングしてもらいましょう。
## 指示:
以下の仕様に基づき、HTMLフォームの送信を処理し、Google Apps Script (GAS) と連携してサンクスページへリダイレクトさせるための、完全なJavaScriptコード (`script.js`) を生成してください。
## 前提:
* HTML (`index.html`) には、以下のIDを持つ要素が存在します:
* フォーム: `id="contact-form"`
* 送信ステータス表示用: `id="form-status"` (例: `<p>`)
* 送信ボタン: `id="contact-form"` 内の `button[type="submit"]`
* プライバシーポリシー同意チェックボックス: `id="privacy_policy"`
* フォームの `action` 属性には、GASのWebアプリURLが設定されています。
* GASの `doPost` 関数は、処理が成功した場合に `"success"` という**テキスト**を返し、失敗した場合はエラーを示すテキストを返します。
* サンクスページのURLは `'あなたが表示させる予定のURL。例)http://www.hajime.com/thanks.html'` です。
* jQueryなどの外部ライブラリは使用せず、Vanilla JavaScript (ES6+) で記述してください。
## 実装する機能:
1. DOM読み込み完了後に処理を開始 (`DOMContentLoaded`)。
2. フォーム送信イベントの捕捉: `contact-form` の `submit` イベントを監視する。
3. デフォルト送信のキャンセル: `event.preventDefault()` を使用する。
4. クライアントサイドバリデーション: プライバシーポリシー (`privacy_policy`) がチェックされているか確認し、チェックされていない場合は `form-status` にエラーメッセージを表示して送信を中止する。
5. 送信中ステータス表示: 送信ボタンを無効化し、`form-status` に「送信中...」と表示する。
6. 非同期データ送信: `fetch` API を使用して、フォームデータを `FormData` オブジェクトとしてGASのURL (`action` 属性の値) へ `POST` メソッドで送信する。
* `mode: 'cors'` を試行する(必要に応じてコメントで `'no-cors'` の可能性に言及)。
7. GAS応答の処理:
* `fetch` の応答をテキストとして取得 (`response.text()`)。
* 応答テキストが `"success"` (前後の空白を除去し小文字比較) と一致する場合:
* コンソールに成功ログを出力する。
* `window.location.href` を使用して指定のサンクスページURLへリダイレクトさせる。
* 応答テキストが `"success"` 以外の場合:
* コンソールにエラーログを出力する。
* `form-status` にエラーメッセージ(例: 「送信エラーが発生しました...」)を表示する。
* 送信ボタンを再度有効化する。
8. 通信エラー処理: `fetch` 自体が失敗した場合(ネットワークエラー等)の `catch` ブロックを設け、コンソールにエラーログを出力し、`form-status` に通信エラーメッセージを表示し、送信ボタンを再度有効化する。
9. 要素存在チェック: スクリプトの冒頭で、必要なHTML要素 (`contactForm`, `formStatus`, `submitButton`) が存在するか確認し、見つからない場合にコンソールエラーを出力する。
## 出力形式:
* 完全な `script.js` ファイルのコードとして出力してください。
* 主要な処理ブロックや重要な箇所には、日本語で分かりやすいコメントを追加してください。
具体的なコード
わたしの環境では、以下を出力しました。
/**
* DOMContentLoadedイベントリスナー
* HTMLの読み込みと解析が完了した時点で実行される
*/
document.addEventListener('DOMContentLoaded', () => {
// 開発コンソールにメッセージを出力して、スクリプトが読み込まれたか確認
console.log('DOM fully loaded and parsed for Expo LP form');
// --- お問い合わせフォーム処理 ---
const contactForm = document.getElementById('contact-form'); // フォーム要素
const formStatus = document.getElementById('form-status'); // 送信状態を表示するp要素
const submitButton = contactForm ? contactForm.querySelector('button[type="submit"]') : null; // 送信ボタン
// 必要な要素がすべて存在するか確認してからイベントリスナーを設定
if (contactForm && formStatus && submitButton) {
// フォームの 'submit' イベント(送信ボタンクリック時など)を監視
contactForm.addEventListener('submit', async (e) => {
// ★★★ 1. ブラウザ標準のフォーム送信動作をキャンセル ★★★
e.preventDefault();
// --- 2. クライアントサイドでの簡単な入力チェック ---
const privacyCheckbox = document.getElementById('privacy_policy');
if (!privacyCheckbox || !privacyCheckbox.checked) {
formStatus.textContent = 'プライバシーポリシーに同意してください。'; // エラーメッセージ表示
formStatus.className = 'form-status error'; // エラースタイル適用 (CSSで定義)
return; // ここで処理を中断し、送信しない
}
// 他の必須項目チェックが必要であればここに追加
// --- 3. 送信処理開始の準備 ---
submitButton.disabled = true; // 送信中にボタンを連打できないように無効化
formStatus.textContent = '送信中...'; // ユーザーに処理中であることを表示
formStatus.className = 'form-status'; // エラースタイルをリセット
// --- 4. フォームデータの準備とGASへの非同期送信 ---
const formData = new FormData(contactForm); // フォーム内の全入力データを取得
const actionUrl = contactForm.action; // formタグのaction属性からGASのURLを取得
try {
// fetch API を使って、指定したURL(actionUrl)にフォームデータをPOST送信
const response = await fetch(actionUrl, {
method: 'POST',
body: formData,
mode: 'cors' // CORSモード推奨 (GAS側は通常対応不要)
// もしこれでエラーが出る場合は 'no-cors' を試す
});
// --- 5. GASからの応答を処理 ---
let responseText = '';
try {
responseText = await response.text(); // GASから返されたテキストを取得
console.log("Response from GAS:", responseText); // デバッグ用ログ
} catch (readError) {
console.warn("Could not read response body (likely CORS or no-cors issue, proceeding as potentially successful):", readError);
if (response.ok || response.type === 'opaque') {
responseText = "success"; // 暫定的に success とする
} else {
throw new Error("Fetch failed or could not read response");
}
}
// ★★★ 6. 応答内容に基づきリダイレクトまたはエラー表示 ★★★
if (responseText.trim().toLowerCase() === "success") {
console.log('Form submission successful. Redirecting...');
// ★★★ サンクスページへリダイレクト! ★★★
window.location.href = 'あなたのサンクスページURL'; // ★サンクスページURL確認
} else {
console.error('サーバーからのエラー応答または予期せぬ応答:', responseText);
formStatus.textContent = '送信エラーが発生しました。内容をご確認の上、再試行ください。';
formStatus.classList.add('error');
submitButton.disabled = false; // ボタンを有効化
}
} catch (error) {
// --- 7. fetch 自体が失敗した場合 (ネットワーク接続がないなど) のエラー処理 ---
console.error('フォーム送信の fetch エラー:', error);
formStatus.textContent = '通信エラーが発生しました。ネットワーク環境をご確認の上、再試行してください。';
formStatus.classList.add('error');
submitButton.disabled = false; // ボタンを有効化
}
});
} else {
// HTMLに必要な要素が見つからない場合のエラー (開発用)
if (!contactForm) console.error('フォーム要素 (#contact-form) が見つかりません。');
if (!formStatus) console.error('ステータス表示要素 (#form-status) が見つかりません。');
if (!submitButton) console.error('送信ボタン (button[type="submit"]) が見つかりません。');
}
}); // End of DOMContentLoaded
メモ帳などにコピペして、script.jsとして保存しましょう。
66行目のあなたのサンクスページURLを、正しく書き換えておきましょう。
// ★★★ 6. 応答内容に基づきリダイレクトまたはエラー表示 ★★★
if (responseText.trim().toLowerCase() === "success") {
console.log('Form submission successful. Redirecting...');
// ★★★ サンクスページへリダイレクト! ★★★
window.location.href = 'あなたのサンクスページURL'; // ★サンクスページURL確認
} else {
console.error('サーバーからのエラー応答または予期せぬ応答:', responseText);
formStatus.textContent = '送信エラーが発生しました。内容をご確認の上、再試行ください。';
formStatus.classList.add('error');
submitButton.disabled = false; // ボタンを有効化この、JavaScriptによるwindow.location.href = ‘あなたのサンクスページURL’;というのが、今回のキモでした。リダイレクト処理を、GASのHTMLサービスではなく、JavaScriptから行う処理です。
アップロード
作成した、以下のファイルをサーバーにアップロードします。
- index.html
- script.js
無事に表示されましたでしょうか。


うまく表示されないばあいは、リダイレクトURLや、WEBアプリとしてデプロイしたURLなどを再確認しましょう。
まとめ
以上で、「WEBサイトのお問い合わせフォームはGASとスプレッドシートで実装しよう」をお送りしました。
AIによるコーディングが活発になってきました。誰でもLPが量産できる時代です。
みなさんの夢が叶えられますように


