【自動化】GASを使ってGoogleフォームによる問合せ管理の仕組みを実装
はじめに
Googleフォームでお問い合わせを受け付けて、スプレッドシートから返信メールを送れる仕組みをGASで実装しました。実装にあたって以下の点を意識しました。
- メールの文面はコードを触らずにスプレッドシートで管理できる
- 誤送信を防ぐためのチェック処理を複数入れる
- 非エンジニアでも使いやすい操作感にする
完成イメージ
お問い合わせフォームイメージ

お問い合わせ管理画面イメージ

メールテンプレート管理画面イメージ

全体の流れ
【問い合わせ側(一般ユーザー)】
Googleフォームで問い合わせを送信
↓
【管理側(スプレッドシート)】
回答一覧シートに自動記録される
↓
担当者がE列「回答内容」に返信文を入力
対象の行を選択して「返信」ボタンを押す
↓
問い合わせ者のメールアドレスに回答メールが送信される
F列「返信済み」にチェックが入る
スプレッドシートのシート構成
| シート名 | 用途 |
|---|---|
| フォームの回答 1 | フォームの回答一覧・返信管理 |
| メールテンプレート | 件名・本文のテンプレート管理 |
回答一覧シートの列構成
| 列 | 項目 | 入力者 |
|---|---|---|
| A列 | タイムスタンプ | フォーム自動 |
| B列 | メールアドレス | フォーム自動 |
| C列 | お名前 | フォーム自動 |
| D列 | 本文 | フォーム自動 |
| E列 | 回答内容 | 担当者が手入力 |
| F列 | 返信済み | GASが自動記入 |
実装手順
1. Googleフォームの作成
以下の項目でフォームを作成します。
- メールアドレス(記述式・必須)
- お名前(記述式・必須)
- 本文(段落・必須)
フォームの回答先スプレッドシートを作成し、回答が自動記録されるよう紐づけます。
2. スプレッドシートの準備
フォームと紐づいたスプレッドシートを開き、以下を手動で追加します。
- E列のヘッダーに「回答内容」と入力
- F列のヘッダーに「返信済み」と入力
3. メールテンプレートシートの作成
新しいシートを作成してシート名を「メールテンプレート」にします。
以下のようにB1・B2セルに入力します。
| セル | 項目 | 入力例 |
|---|---|---|
| A1 | 件名 | 件名 |
| B1 | (件名の内容) | 【回答】{{name}} 様へ |
| A2 | 本文 | 本文 |
| B2 | (本文の内容) | 下記参照 |
B2セルの本文はAlt+Enterで改行しながら以下のように入力します。
{{name}} 様
お問い合わせいただきありがとうございます。
以下の通りご回答いたします。
─────────────────
■ お問い合わせ内容
─────────────────
{{question}}
─────────────────
■ 回答
─────────────────
{{answer}}
引き続きよろしくお願いいたします。
使用できるプレースホルダーは以下の通りです。
| プレースホルダー | 置き換わる内容 |
|---|---|
{{name}} |
お名前 |
{{question}} |
本文 |
{{answer}} |
回答内容 |
4. GASスクリプトの実装
スプレッドシートのメニューから「拡張機能」→「Apps Script」を開き、以下のコードを貼り付けます。
// =====================
// 設定値
// =====================
const SHEET_NAME = "フォームの回答 1";
const TEMPLATE_SHEET_NAME = "メールテンプレート";
const COL_EMAIL = 2; // B列:メールアドレス
const COL_NAME = 3; // C列:お名前
const COL_QUESTION = 4; // D列:本文
const COL_ANSWER = 5; // E列:回答内容
const COL_DONE = 6; // F列:返信済み
// =====================
// テンプレート読み込み関数
// =====================
function getTemplate() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(TEMPLATE_SHEET_NAME);
if (!sheet) {
SpreadsheetApp.getUi().alert(
"⚠️ 「" + TEMPLATE_SHEET_NAME + "」シートが見つかりません。"
);
return null;
}
return {
subject: sheet.getRange("B1").getValue(),
body : sheet.getRange("B2").getValue()
};
}
// =====================
// プレースホルダー置換関数
// =====================
function applyTemplate(template, name, answer, question) {
const subject = template.subject
.replace(/{{name}}/g, name)
.replace(/{{answer}}/g, answer)
.replace(/{{question}}/g, question);
const body = template.body
.replace(/{{name}}/g, name)
.replace(/{{answer}}/g, answer)
.replace(/{{question}}/g, question);
return { subject, body };
}
// =====================
// 返信ボタンから呼び出す関数
// =====================
function sendReply() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_NAME);
const activeRange = SpreadsheetApp.getActiveRange();
// ① 複数行選択チェック
if (activeRange.getNumRows() > 1) {
SpreadsheetApp.getUi().alert(
"⚠️ 1行だけ選択してから返信ボタンを押してください。"
);
return;
}
// ② 選択行のデータ取得
const row = activeRange.getRow();
const name = sheet.getRange(row, COL_NAME).getValue();
const email = sheet.getRange(row, COL_EMAIL).getValue();
const answer = sheet.getRange(row, COL_ANSWER).getValue();
const question = sheet.getRange(row, COL_QUESTION).getValue();
const done = sheet.getRange(row, COL_DONE).getValue();
// ③ ヘッダー行の選択チェック
if (row === 1) {
SpreadsheetApp.getUi().alert(
"⚠️ ヘッダー行が選択されています。回答行を選択してください。"
);
return;
}
// ④ 返信済みチェック
if (done === true) {
SpreadsheetApp.getUi().alert(
"⚠️ この行はすでに返信済みです。"
);
return;
}
// ⑤ 回答内容の空欄チェック
if (!answer) {
SpreadsheetApp.getUi().alert(
"⚠️ E列に回答内容を入力してから返信ボタンを押してください。"
);
return;
}
// ⑥ メールアドレスの形式チェック
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
SpreadsheetApp.getUi().alert(
"⚠️ メールアドレスの形式が正しくありません。\n確認してください:" + email
);
return;
}
// ⑦ テンプレート読み込み・置換
const template = getTemplate();
if (!template) return;
const mail = applyTemplate(template, name, answer, question);
// ⑧ 送信確認ポップアップ
const ui = SpreadsheetApp.getUi();
const confirm = ui.alert(
"送信確認",
`以下の内容でメールを送信します。\n\n宛先:${name} 様(${email})\n\n件名:${mail.subject}\n\n本文:\n${mail.body}\n\nよろしいですか?`,
ui.ButtonSet.OK_CANCEL
);
if (confirm !== ui.Button.OK) return;
// ⑨ メール送信
GmailApp.sendEmail(email, mail.subject, mail.body);
// ⑩ 返信済みフラグを記入
sheet.getRange(row, COL_DONE).setValue(true);
// ⑪ 完了通知
ui.alert("✅ " + name + " 様へ送信が完了しました。");
}
5. 返信ボタンの設置
スプレッドシートに戻り、以下の手順でボタンを設置します。
- メニューから「挿入」→「図形描画」を選択
- 図形を描いてテキストに「返信」と入力
- 「保存して閉じる」を押す
- 設置された図形の右上の「︙」→「スクリプトを割り当て」を選択
-
sendReplyと入力してOKを押す
6. 動作確認
- フォームからテスト用の問い合わせを送信する
- スプレッドシートのA〜D列に自動記録されることを確認する
- E列に回答内容を入力する
- 対象の行のどこかのセルを選択する
- 「返信」ボタンを押す
- 送信確認ポップアップで内容を確認してOKを押す
- 問い合わせ時のメールアドレスに返信メールが届くことを確認する
- F列に
TRUEが入ることを確認する
工夫した点・詰まった点
誤送信防止のチェックを複数入れた
送信前に以下のチェックを順番に実行しています。
- 複数行選択時はエラーで中断
- ヘッダー行選択時はエラーで中断
- 返信済みの行はエラーで中断
- 回答内容が空の場合はエラーで中断
- メールアドレスの形式チェック
- 送信確認ポップアップで最終確認
テンプレートをシートで管理するようにした
メールの文面をコード内にハードコードすると、文面を変えるたびにコードを修正する必要があります。テンプレートをスプレッドシートのシートで管理することで、コードを触らずに文面変更ができるようになりました。
セル内の改行をそのまま使える
テンプレートのセルをAlt+Enterで改行すると、getValue()でそのまま改行が取得できます。\nなどの特殊文字を使わずに普通の文章として入力できる点が使いやすいです。
返信済みフラグをチェックボックスにした
F列をチェックボックス形式にしておくと、GASでsetValue(true)を設定した際に視覚的にわかりやすくなります。チェックボックスの設定は「挿入」→「チェックボックス」から行えます。
まとめ
GASを使ってGoogleフォームのお問い合わせ管理システムを実装しました。今回の実装で以下が実現できました。
- フォームの回答をスプレッドシートに自動記録
- テンプレートシートを使った柔軟なメール文面管理
- 誤送信を防ぐ複数のチェック処理
- 選択行へのワンクリック返信
プレースホルダーを追加するだけで差し込む内容を増やせるので、用途に合わせてカスタマイズしやすい構成になっています。
このように、簡単に問合せ管理ができる仕組みを導入したいというご依頼があれば、一度、ご相談ください。
Discussion