【自動化】GASを使ってGoogleフォームによる予約管理の仕組みを実装
はじめに
Googleフォームで予約を受け付けて、Googleカレンダーへの自動登録と確認メールの送信をGASで実装しました。実装にあたって以下の点を意識しました。
- フォーム送信と同時にすべての処理が自動で完結する
- メールの文面はコードを触らずにスプレッドシートで管理できる
- 予約の所要時間を設定値で管理してカスタマイズしやすくする
完成イメージ
予約フォームイメージ

予約管理画面イメージ

確認メールイメージ

カレンダー登録イメージ

全体の流れ
【予約者側(一般ユーザー)】
Googleフォームで希望日時・名前・メールを入力して送信
↓
【自動処理(GAS)】
Googleカレンダーに予定を自動登録
予約者に確認メールを自動送信
↓
【管理側(スプレッドシート)】
予約一覧が自動で記録される
G列にカレンダー登録済みフラグが入る
スプレッドシートのシート構成
| シート名 | 用途 |
|---|---|
| フォームの回答 1 | フォームの回答一覧・登録管理 |
| メールテンプレート | 件名・本文のテンプレート管理 |
回答一覧シートの列構成
| 列 | 項目 | 入力者 |
|---|---|---|
| A列 | タイムスタンプ | フォーム自動 |
| B列 | メールアドレス | フォーム自動 |
| C列 | お名前 | フォーム自動 |
| D列 | 予約希望日 | フォーム自動 |
| E列 | 予約希望時間 | フォーム自動 |
| F列 | ご用件 | フォーム自動 |
| G列 | カレンダー登録済み | GASが自動記入 |
実装手順
1. Googleフォームの作成
以下の項目でフォームを作成します。
- メールアドレス(記述式・必須)
- お名前(記述式・必須)
- 予約希望日(日付・必須)
- 予約希望時間(プルダウン・必須)例:10:00、11:00、13:00…
- ご用件(段落・任意)
フォームの回答先スプレッドシートを作成し、回答が自動記録されるよう紐づけます。
2. スプレッドシートの準備
フォームと紐づいたスプレッドシートを開き、G列のヘッダーに「カレンダー登録済み」と手動で追加します。
G列はチェックボックス形式にしておくと、GASでsetValue(true)を設定した際に視覚的にわかりやすくなります。チェックボックスの設定は「挿入」→「チェックボックス」から行えます。
3. メールテンプレートシートの作成
新しいシートを作成してシート名を「メールテンプレート」にします。
以下のようにB1・B2セルに入力します。
| セル | 項目 | 入力例 |
|---|---|---|
| A1 | 件名 | 件名 |
| B1 | (件名の内容) | 【予約確認】{{name}} 様のご予約を承りました |
| A2 | 本文 | 本文 |
| B2 | (本文の内容) | 下記参照 |
B2セルの本文はAlt+Enterで改行しながら以下のように入力します。
{{name}} 様
この度はご予約いただきありがとうございます。
以下の内容でご予約を承りました。
─────────────────
■ 予約内容
─────────────────
予約日:{{date}}
予約時間:{{time}}
ご用件:{{note}}
─────────────────
ご不明な点がございましたらお気軽にお問い合わせください。
引き続きよろしくお願いいたします。
使用できるプレースホルダーは以下の通りです。
| プレースホルダー | 置き換わる内容 |
|---|---|
{{name}} |
お名前 |
{{date}} |
予約日 |
{{time}} |
予約時間 |
{{note}} |
ご用件 |
4. GASスクリプトの実装
スプレッドシートのメニューから「拡張機能」→「Apps Script」を開き、以下のコードを貼り付けます。
// =====================
// 設定値
// =====================
const SHEET_NAME = "フォームの回答 1";
const TEMPLATE_SHEET_NAME = "メールテンプレート";
const CALENDAR_ID = "primary"; // 使用するカレンダーID
const DURATION = 60; // 予約の所要時間(分)
const COL_EMAIL = 2; // B列:メールアドレス
const COL_NAME = 3; // C列:お名前
const COL_DATE = 4; // D列:予約希望日
const COL_TIME = 5; // E列:予約希望時間
const COL_NOTE = 6; // F列:ご用件
const COL_DONE = 7; // G列:カレンダー登録済み
// =====================
// テンプレート読み込み関数
// =====================
function getTemplate() {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(TEMPLATE_SHEET_NAME);
if (!sheet) {
// トリガー実行時はgetUi()が使えないためログに記録する
console.error("⚠️ 「" + TEMPLATE_SHEET_NAME + "」シートが見つかりません。");
return null;
}
return {
subject: sheet.getRange("B1").getValue(),
body : sheet.getRange("B2").getValue()
};
}
// =====================
// プレースホルダー置換関数
// =====================
function applyTemplate(template, name, date, time, note) {
const subject = template.subject
.replace(/{{name}}/g, name)
.replace(/{{date}}/g, date)
.replace(/{{time}}/g, time)
.replace(/{{note}}/g, note);
const body = template.body
.replace(/{{name}}/g, name)
.replace(/{{date}}/g, date)
.replace(/{{time}}/g, time)
.replace(/{{note}}/g, note);
return { subject, body };
}
// =====================
// 日付・時間の結合関数
// =====================
function buildDateTime(date, timeStr) {
const [hours, minutes] = timeStr.split(":").map(Number);
const start = new Date(date);
start.setHours(hours, minutes, 0, 0);
const end = new Date(start);
end.setMinutes(end.getMinutes() + DURATION);
return { start, end };
}
// =====================
// フォーム送信時に自動実行される関数
// =====================
function onFormSubmit(e) {
try {
const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName(SHEET_NAME);
// ① 送信された行番号を取得
const row = e.range.getRow();
const email = sheet.getRange(row, COL_EMAIL).getValue();
const name = sheet.getRange(row, COL_NAME).getValue();
const date = sheet.getRange(row, COL_DATE).getValue();
const timeStr = sheet.getRange(row, COL_TIME).getValue();
const note = sheet.getRange(row, COL_NOTE).getValue();
// ② 日付・時間の結合
const { start, end } = buildDateTime(date, timeStr);
// ③ 日付フォーマット(メール用)
const formattedDate = Utilities.formatDate(start, "Asia/Tokyo", "yyyy年MM月dd日");
const formattedTime = Utilities.formatDate(start, "Asia/Tokyo", "HH:mm");
// ④ カレンダーに予定を登録
const calendar = CalendarApp.getCalendarById(CALENDAR_ID);
const title = `【予約】${name} 様`;
const options = {
description: `予約者:${name}\nメール:${email}\nご用件:${note}`
};
calendar.createEvent(title, start, end, options);
// ⑤ テンプレート読み込み・置換
const template = getTemplate();
if (!template) return;
const mail = applyTemplate(template, name, formattedDate, formattedTime, note || "なし");
// ⑥ 確認メールを送信
GmailApp.sendEmail(email, mail.subject, mail.body);
// ⑦ カレンダー登録済みフラグを記入
sheet.getRange(row, COL_DONE).setValue(true);
} catch (error) {
// トリガー実行時はgetUi()が使えないためログに記録する
console.error("エラーが発生しました:" + error.message);
}
}
5. トリガーの設定
フォーム送信時にスクリプトが自動実行されるようトリガーを設定します。
- GASエディタのメニューから「トリガー」を選択
- 「トリガーを追加」をクリック
- 以下のように設定する
| 項目 | 設定値 |
|---|---|
| 実行する関数 | onFormSubmit |
| イベントのソース | スプレッドシートから |
| イベントの種類 | フォーム送信時 |
6. 動作確認
- フォームからテスト用の予約を送信する
- スプレッドシートのA〜F列に自動記録されることを確認する
- Googleカレンダーに予定が登録されることを確認する
- 予約時のメールアドレスに確認メールが届くことを確認する
- G列にチェックが入ることを確認する
工夫した点・詰まった点
フォーム送信と同時に全処理が自動完結する
フォーム送信トリガーを使うことで操作なしに全処理が自動実行されます。
日付と時間を別々に取得して結合した
フォームの日付入力と時間のプルダウンは別項目のため、buildDateTime関数で両者を結合してDateオブジェクトを生成しています。
const [hours, minutes] = timeStr.split(":").map(Number);
split(":")で時間文字列を分割し、map(Number)で数値に変換しています。数値に変換しないとsetHours()に渡した際に意図しない動作になる場合があるため、この処理を入れています。
日付を日本語表記に変換した
Utilities.formatDate()を使うことでDateオブジェクトを日本語表記に変換してメールに差し込んでいます。
Utilities.formatDate(start, "Asia/Tokyo", "yyyy年MM月dd日")
// → "2026年03月21日"
テンプレートをシートで管理するようにした
メールの文面をスプレッドシートで管理しています。コードを触らずに文面変更ができるため、非エンジニアでも運用しやすい設計になっています。
まとめ
GASを使ってGoogleフォームの予約管理システムを実装しました。今回の実装で以下が実現できました。
- フォーム送信と同時にカレンダーへ自動登録
- テンプレートシートを使った柔軟なメール文面管理
- 日付・時間の結合処理による正確なカレンダー登録
- 予約者への確認メール自動送信
DURATIONの値を変更するだけで所要時間を調整できるなど、カスタマイズしやすい構成になっています。
このように、簡単に予約管理ができる仕組みを導入したいというご依頼があれば、一度、ご相談ください。
Discussion