Googleフォームで申込を受けたら、申込者にはすぐに「受け付けました」と返したいものです。方法は、フォームの標準機能「回答のコピーを回答者に送信」と、Google Apps Script(GAS)で自分の文面のメールを送る方法の2つです。この記事では、料理教室「サンプル料理教室」の体験レッスン申込に、希望日時と持ち物を入れた確認メールを info@ から返すまでを順に書きます。読み終わると、標準機能で足りるかGASが要るかを判断でき、GASを選んだ場合は貼り付けて動くコードで自動返信を始められます。体験申込のフォームがスプレッドシートにつながっていて、Google Workspaceの会社のアカウントで編集できることが前提です。フォームとスプレッドシートのつなぎ方は「Googleフォームの作り方:申込・予約・アンケートを受ける」に書いています。画面の名前と上限の数字は2026年10月時点のものです。
この記事の内容
先に決めること
標準機能で足りるか
まず、送りたいメールに何が必要かを書き出します。「回答内容が本人の手元に残ればよい」なら標準機能で足ります。次のどれか1つでも当てはまるならGASにします。
- 件名や本文を教室の言葉で書きたい
- 希望のコースに合わせて、持ち物や注意事項を変えたい
- 差出人を info@ にしたい、差出人名を「サンプル料理教室」にしたい
- 返信されたメールを受付の共同トレイで受けたい
- 送ったかどうかの記録を残したい
サンプル料理教室では、持ち物がコースで違い、返信を info@ で受けたいので、GASで送っています。
誰のアカウントでGASを動かすか
GASの自動返信は、トリガーを作った人のアカウントで動きます。送るメールもその人のGmailから出ます。受付担当が個人のアカウントで作ると、その人が退職してアカウントを止めた日に自動返信も止まります。
教室では、受付用の共通アカウント uketsuke@sample-cooking.example を作り、そのアカウントでフォームとスプレッドシートを編集し、GASのトリガーも作っています。個人ではなく役割のアカウントに持たせておくと、人が入れ替わっても止まりません。共通アカウントにもライセンスが1つ要るので、その費用と、退職のたびに止まる手間とを比べて決めます。
送信元のアドレスと返信先
申込者から見て、差出人が uketsuke@ より info@ のほうが自然です。info@ がGoogleグループなら、GASを動かすアカウントのGmailに info@ を「送信元のアドレス」として追加しておく必要があります。追加できない場合でも、返信先(Reply-To)を info@ にすれば、申込者が「返信」を押したメールは info@ に届きます。どこまでやるかを先に決めます。
何をメールに書き、何を書かないか
確認メールには、申込者が当日までに見返す情報を入れます。体験レッスンなら、受け付けた内容、日程が確定する時期、持ち物、場所、キャンセルの連絡先です。逆に、アレルギーの詳細や電話番号のような、申込者がすでに知っている個人情報は本文に繰り返しません。メールは転送されることがあり、書かなくて済むものは書かないのが安全です。
標準機能とGASの違い
| 項目 | 回答のコピーを回答者に送信 | GASで送る |
|---|---|---|
| 設定の手間 | 「設定」で選ぶだけ | コードとトリガーを入れる |
| 件名・本文の文面 | 変えられない(回答内容が並ぶ) | 自由に書ける |
| 回答内容を差し込む | 全部の回答がそのまま出る | 必要な項目だけ差し込める |
| 回答に応じて内容を変える | できない | コースごとに持ち物を変えられる |
| 差出人名 | 変えられない | name で「サンプル料理教室」にできる |
| 送信元アドレス | 選べない | Gmailに追加した送信元アドレスにできる |
| 返信先 | 選べない | replyTo で info@ にできる |
| 送信の記録 | 残らない | シートに残せる |
| 前提 | メールアドレスの収集がオン | メールアドレスを収集するか質問で聞く |
| 止まる原因 | 迷惑メールフィルタなど | 承認の取り消し、上限、作った人のアカウント停止 |
標準機能は、仕組みが単純で壊れにくいのが長所です。GASは何でもできる代わりに、動かしているアカウントとコードを誰かが面倒を見る必要があります。社内向けの報告フォームのように相手が身内なら、標準機能で十分です。
標準の「回答のコピーを回答者に送信」を使う手順
- フォームを開き、上部の「設定」タブをクリックします。
- 「回答」の右の下矢印をクリックします。
- 「メールアドレスを収集する」で「回答者からの入力」を選びます。
- 「回答のコピーを回答者に送信」で「常に表示」を選びます。
- 右上のプレビューから、自分のアドレスで1件送ってみます。
「リクエストされた場合」を選ぶと、回答者が送信前にコピーを受け取るかどうかを選べます。申込の確認として使うなら「常に表示」にします。「メールアドレスを収集する」を「確認済み」にすると、Googleアカウントでのログインが必要になり、一般の申込者は答えにくくなります。
届くメールは、フォームの回答内容をそのまま並べたものです。件名や本文に教室の案内を足す設定はありません。ヘルプにも、迷惑メールフィルタなどの不正利用対策で届かない場合があると書かれています。「届いていない」と言われたときに、送り直す手段もありません。
そこで、標準機能を使う場合でも、フォームの「確認メッセージ」に次の連絡の目安を書いておきます。「設定」の「プレゼンテーション」で「確認メッセージ」の「編集」から変えられます。メールが届かなくても、送信直後の画面で何が起きるかが伝わります。

GASで確認メールを送る手順
できあがりのメール
GASで送るのは、次のようなメールです。
件名: 【サンプル料理教室】体験レッスンのお申込みを受け付けました
山田 花子 様
サンプル料理教室です。体験レッスンのお申込みを受け付けました。
受付から2営業日以内に、日程確定のご連絡をします。
ご希望のコース:和食の基本コース
ご希望の日時:11/8(土)10:30〜12:30
当日の持ち物:エプロン、ハンドタオル、筆記用具
場所:サンプル料理教室(東京都〇〇区〇〇 1-2-3 サンプルビル2階)
日程の変更・キャンセルは、このメールにご返信いただくか、
03-0000-0000(受付 10:00〜18:00)までご連絡ください。
フォームとシートを確認する
体験申込のフォームと、回答を貯めているスプレッドシートで、次の点を確かめます。
| 確認すること | このコードでの前提 |
|---|---|
| メールアドレスの集め方 | 「メールアドレスを収集する」で「回答者からの入力」。列の見出しは「メールアドレス」 |
| 名前の質問のタイトル | 「お名前」 |
| コースの質問のタイトル | 「希望のコース」(ラジオボタン) |
| 日時の質問のタイトル | 「希望日時」(プルダウン) |
| 回答の保存先 | スプレッドシートの「フォームの回答 1」 |
コードは質問のタイトルで回答を取り出します。フォームのタイトルと1文字でも違うと、その項目が空のメールが届きます。
コードを貼る
- 回答を貯めているスプレッドシートを開きます。
- 「拡張機能」から「Apps Script」を選びます。
- エディタに最初からある
function myFunction() {}を消します。 - 次のコードを貼ります。
- 上の保存のアイコンを押します。
// 体験レッスン申込の確認メールを送る(スプレッドシートの「フォーム送信時」トリガーで動かす)
const CONFIG = {
fromAlias: 'info@sample-cooking.example', // Gmailに追加した送信元アドレス(無ければ自分のアドレスから送る)
senderName: 'サンプル料理教室',
replyTo: 'info@sample-cooking.example',
logSheetName: '送信ログ',
};
// コースごとの持ち物
const BELONGINGS = {
'和食の基本コース': 'エプロン、ハンドタオル、筆記用具',
'パンとお菓子のコース': 'エプロン、ハンドタオル、持ち帰り用の袋',
'週末のおもてなしコース': 'エプロン、ハンドタオル、保冷バッグ',
};
const DEFAULT_BELONGINGS = 'エプロン、ハンドタオル';
function sendConfirmation(e) {
const v = e.namedValues;
const get = function (key) {
return v[key] && v[key][0] ? String(v[key][0]).trim() : '';
};
const to = get('メールアドレス');
if (!to) return; // メールアドレスが無ければ送らない
const name = get('お名前');
const course = get('希望のコース');
const slot = get('希望日時');
const key = get('タイムスタンプ') + '|' + to; // 二重送信を防ぐための目印
const lock = LockService.getScriptLock();
lock.waitLock(30000);
try {
const ss = SpreadsheetApp.getActive();
const log = ss.getSheetByName(CONFIG.logSheetName) || ss.insertSheet(CONFIG.logSheetName);
const sent = log.getLastRow() > 0
? log.getRange(1, 1, log.getLastRow(), 1).getValues().some(function (r) { return r[0] === key; })
: false;
if (sent) return; // 同じ回答にはもう送っている
const subject = '【サンプル料理教室】体験レッスンのお申込みを受け付けました';
const body = [
name + ' 様',
'',
'サンプル料理教室です。体験レッスンのお申込みを受け付けました。',
'受付から2営業日以内に、日程確定のご連絡をします。',
'',
'ご希望のコース:' + course,
'ご希望の日時:' + slot,
'',
'当日の持ち物:' + (BELONGINGS[course] || DEFAULT_BELONGINGS),
'場所:サンプル料理教室(東京都〇〇区〇〇 1-2-3 サンプルビル2階)',
'',
'日程の変更・キャンセルは、このメールにご返信いただくか、',
'03-0000-0000(受付 10:00〜18:00)までご連絡ください。',
].join('\n');
const options = { name: CONFIG.senderName, replyTo: CONFIG.replyTo };
if (GmailApp.getAliases().indexOf(CONFIG.fromAlias) !== -1) {
options.from = CONFIG.fromAlias;
}
GmailApp.sendEmail(to, subject, body, options);
log.appendRow([key, new Date(), to, course, slot]);
} finally {
lock.releaseLock();
}
}
// トリガーを入れ直す(重複して作らないよう、同じ関数のトリガーを消してから作る)
function installTrigger() {
const ss = SpreadsheetApp.getActive();
ScriptApp.getProjectTriggers().forEach(function (t) {
if (t.getHandlerFunction() === 'sendConfirmation') ScriptApp.deleteTrigger(t);
});
ScriptApp.newTrigger('sendConfirmation').forSpreadsheet(ss).onFormSubmit().create();
}
// エディタから試すための関数(自分のアドレスに1通送る)
function testSend() {
sendConfirmation({
namedValues: {
'タイムスタンプ': [String(new Date())],
'メールアドレス': [Session.getActiveUser().getEmail()],
'お名前': ['テスト 太郎'],
'希望のコース': ['和食の基本コース'],
'希望日時': ['11/8(土)10:30〜12:30'],
},
});
}
コードの中で回答を取り出しているのは e.namedValues です。スプレッドシートのフォーム送信のイベントでは、質問のタイトルをキーにして、回答の値が配列で入っています。そのため v['お名前'][0] のように1つ目の値を取っています。チェックボックスの質問は、選んだ項目がカンマ区切りの1つの文字列で入ります。
BELONGINGS のコース名は、フォームの選択肢と1文字も違わないように書きます。違うと DEFAULT_BELONGINGS の持ち物になります。

試しに送って承認する
- エディタ上部の関数の選択で
testSendを選びます。 - 「実行」をクリックします。
- 「承認が必要です」と出たら「権限を確認」をクリックします。
- 受付用のアカウントを選びます。
- 「Google にアクセスを許可」の画面で、許可する内容を読み、「許可」をクリックします。
- 受付用のアカウントのGmailに、テストのメールが届いたことを確かめます。
承認の画面には、スプレッドシートの読み書きと、Gmailでのメールの送信などの許可が並びます。GmailAppを使うと、Gmailのメールの閲覧や削除まで含む広い許可を求められます。送るだけで十分なら、後で書くMailAppに替えると、求められる許可が「メールの送信」に絞られます。
組織の設定によっては、承認の画面に「このアプリは Google で確認されていません」と出ます。社内で自分が書いたスクリプトなら、「詳細」から先に進んで構いません。管理者が外部のアプリへの許可を制限している場合は、管理コンソールの設定を見直す必要があります。

フォーム送信時のトリガーを入れる
トリガーの入れ方は2通りあります。どちらか一方だけにします。
コードで入れる場合は、関数の選択で installTrigger を選んで「実行」します。同じ関数のトリガーを消してから作るので、何度実行してもトリガーは1つです。
画面で入れる場合は、次の手順です。
- エディタの左側の「トリガー」(時計のアイコン)をクリックします。
- 右下の「トリガーを追加」をクリックします。
- 「実行する関数を選択」で
sendConfirmationを選びます。 - 「イベントのソースを選択」で「スプレッドシートから」を選びます。
- 「イベントの種類を選択」で「フォーム送信時」を選びます。
- 「保存」をクリックします。
トリガーを入れたら、フォームのプレビューから自分のアドレスで1件申し込みます。確認メールが届き、スプレッドシートに「送信ログ」のシートができて1行入っていれば完成です。

トリガーの種類と使い分けは「GASのトリガー:定期実行・フォーム送信時・編集時」に書いています。

送信元・差出人名・返信先の設定
確認メールの差出人の見え方は、3つの値で決まります。
| 値 | コードでの指定 | 何も指定しないと | サンプル料理教室の設定 |
|---|---|---|---|
| 差出人名 | name | トリガーを作った人の名前 | サンプル料理教室 |
| 送信元アドレス | from(GmailAppのみ) | トリガーを作った人のアドレス | info@sample-cooking.example |
| 返信先 | replyTo | トリガーを作った人のアドレス | info@sample-cooking.example |
送信元のアドレスを追加する
from に指定できるのは、Gmailに追加済みの送信元アドレスだけです。GASでは GmailApp.getAliases() が返すアドレスのどれかである必要があります。受付用のアカウントのGmailで、info@ を追加します。
- 受付用のアカウントでGmailを開きます。
- 右上の設定のアイコンから「すべての設定を表示」をクリックします。
- 「アカウント」タブを開きます。
- 「名前」の欄の「他のメール アドレスを追加」をクリックします。
- 名前に「サンプル料理教室」、アドレスに
info@sample-cooking.exampleを入れて「次のステップ」をクリックします。 - 確認メールが info@ に届くので、共同トレイで開き、確認のリンクを押します。

info@ がGoogleグループの場合、グループのアドレスから送るには、そのグループへの委任のアクセス権と、グループの投稿の権限が要ります。グループの設定によっては確認メールが届かないので、そのときは管理者がグループとエイリアスの設定を見直します。info@ の作り方は「Gmailを複数人で回す:Googleグループ・共有アドレス・振り分け・署名」を見てください。
上のコードは、info@ が送信元のアドレスに追加されていなければ from を付けずに送ります。追加の手続きが終わる前でも、差出人名と返信先だけは info@ の形で動きます。
返信をどこで受けるか
replyTo を info@ にしておくと、申込者が「返信」を押したメールは info@ に届きます。受付の2人が共同トレイで見ている受信箱に返信が入るので、「キャンセルしたい」という返事を見落としません。送信元を info@ にできなくても、返信先だけは必ず info@ にしておきます。
MailAppで送る場合
送信元のアドレスを変えなくてよいなら、GmailAppの代わりにMailAppを使えます。MailAppには from がない代わりに、求められる許可が「メールの送信」だけで済みます。上のコードの GmailApp.sendEmail(...) の行と、その上の options の4行を、次に置き換えます。
MailApp.sendEmail({
to: to,
subject: subject,
body: body,
name: CONFIG.senderName,
replyTo: CONFIG.replyTo,
});
MailAppのリファレンスには、送ったメールがGmailの「送信済み」に残るかどうかの記載がありません。送った記録は、Gmailではなく、コードが書く「送信ログ」のシートで確かめます。
1日の送信上限と、迷惑メールに入らないための注意
1日に送れる数
GASのメール送信には、1日あたりの上限があります(2026年10月時点)。
| 項目 | 一般のGoogleアカウント | Google Workspace |
|---|---|---|
| メールの受信者数(1日) | 100 | 1,500 |
| ドメイン内のメールの受信者数(1日) | 100 | 2,000 |
| 1通あたりの受信者数 | 50 | 50 |
| 本文のサイズ | 200KB | 400KB |
| 添付の合計サイズ | 25MB | 25MB |
| トリガーの合計実行時間(1日) | 90分 | 6時間 |
上限はアカウントごとで、最初の送信から24時間でリセットされます。体験申込の確認メールなら1日に数件なので、この上限に届くことはありません。気をつけるのは、同じアカウントで月末の請求書の一斉送信やお知らせの配信もしている場合です。上限は合計で数えるので、配信で使い切った日は確認メールも送れなくなります。残りの数は MailApp.getRemainingDailyQuota() で確かめられます。
もう1つ、Google Workspaceを試用期間で使っているあいだは、上限が低くなります。有料に切り替えて、請求額の累計が100米ドル相当に達してから60日以上たつと、自動で引き上げられます。導入直後に「確認メールが途中から送られなくなった」というときは、ここを疑います。
迷惑メールに入らないために
確認メールが迷惑メールに入ると、申込者は「申し込めていない」と思って電話をかけてくるか、別の教室に申し込みます。次の点を整えておきます。
- 独自ドメインのDKIMを有効にする: 管理コンソールの「アプリ」から「Google Workspace」「Gmail」「メールの認証」で鍵を作り、DNSにTXTレコードを足して「認証を開始」を押します。Gmailあてに送る送信者は、SPFかDKIMのどちらかが必須です
- SPFを設定する: 独自ドメインのDNSに、Googleから送ることを示すSPFのレコードを入れます。導入時に済ませているはずなので、入っているかだけ確かめます
- 差出人名に送り主だけを書く: 「サンプル料理教室」はよく、「【体験受付中】サンプル料理教室」のように件名めいた言葉や絵文字を入れるのは避けます
- 確認メールに宣伝を混ぜない: 申込の確認と、キャンペーンの案内を同じメールに入れないようにします
- 申込者が入れたアドレスにだけ送る: フォームの入力をそのまま宛先にしているので、打ち間違いのアドレスには届きません。宛先不明で戻ったメールは受付用のアカウントに返ってくるので、週に1回は見て、電話で連絡します

DKIMとSPFの設定は「Google Workspaceの導入手順:独自ドメイン・メールの切り替え・最初のユーザー」に書いています。
応用
受付に通知する
確認メールと同時に、受付の info@ にも「新しい申込があります」と送れます。GmailApp.sendEmail(...) の次の行に、宛先を CONFIG.replyTo にした通知を1通足します。ただしGoogleグループあての通知は、申込者への確認メールと同じ件名だと共同トレイで区別しにくいので、件名を「【体験申込】山田 花子 様 11/8 10:30」のように変えます。ChatのスペースやLINEに流したいときは、n8nかGASのWebhookでつなぎます。
日程が確定したら2通目を送る
受付が予約一覧で「連絡済み」を付け、確定日時を入れたら、確定のメールを送る、という2通目も作れます。こちらはフォーム送信時ではなく、シートの値をもとに1通ずつ送る作りになります。宛先の一覧に差し込んで送るやり方は「GASでメールを自動送信する:スプレッドシートの宛先に1通ずつ差し込む」に書いています。
HTMLのメールにする
options に htmlBody を足すと、HTMLのメールになります。教室のロゴを入れたくなりますが、確認メールは文字だけのほうが迷惑メールに入りにくく、スマホでも崩れません。サンプル料理教室では文字だけで送っています。
できないことと、その代わり
| やりたいこと | 標準機能 | GAS | 代わりの手 |
|---|---|---|---|
| 確認メールの文面を変える | できない | できる | GASにする |
| 送信元を info@ にする | できない | 送信元のアドレスを追加すればできる | 返信先だけ info@ にする |
| 返信不可のアドレスから送る | できない | Google Workspaceなら noReply で可 | 返信先を info@ にするほうが申込者に親切 |
| 1日数千通の配信 | 対象外 | 上限に当たる | メール配信サービスを使う |
| 開封されたか知る | できない | できない | 確定の連絡を電話やLINEでも行う |
| 申込の直後にLINEで返す | できない | LINEのAPIを呼べば可 | LINEの公式アカウントの応答やn8nでつなぐ |
| 送信に失敗した申込者を自動で拾う | できない | 失敗の通知メールで分かる | 送信ログと回答シートを週に1回見比べる |
お知らせやキャンペーンの一斉配信は、確認メールとは別物です。1日の上限や配信停止の仕組みが必要になるので、GASではなくメール配信のサービスやLINEの公式アカウントを使います。
よく詰まるところ
| 症状 | 原因 | 直し方 |
|---|---|---|
| 「承認が必要です」が出て進まない | 初回の実行で許可がまだない | 「権限を確認」から受付用のアカウントで「許可」する |
| 「このアプリは Google で確認されていません」と出る | 自分で書いたスクリプトの承認画面 | 「詳細」から先に進む。管理者が制限していれば設定を見直す |
エディタで実行すると Cannot read properties of undefined と出る | sendConfirmation を直接実行し、e が空 | testSend を実行するか、フォームから送って試す |
| フォームから送ってもメールが来ない | トリガーが入っていない、または「フォーム送信時」でない | 「トリガー」の画面で、関数と種類を確かめる |
| 同じメールが2通、3通届く | 同じトリガーを複数作った | 「トリガー」の画面で重複を消す。installTrigger で作り直す |
| 名前や日時が空のメールが届く | 質問のタイトルとコードのキーが違う | フォームの質問のタイトルを、コードと1文字ずつ見比べる |
| 持ち物がいつも共通のものになる | コース名の書き方が選択肢と違う | BELONGINGS の名前を選択肢と同じにする |
from を付けたらエラーになる | info@ が送信元のアドレスに追加されていない | Gmailで送信元のアドレスを追加する。上のコードなら自動で外して送る |
| 途中から送られなくなった | 1日の上限、試用期間の制限、作った人のアカウントの停止や承認の取り消し | 失敗の通知メールと実行数の画面で原因を見る |
| 迷惑メールに入ると言われる | DKIMが未設定、差出人名や件名が宣伝っぽい | DKIMを有効にし、差出人名を教室名だけにする |
| 確認メールの日時が「1899/12/30」のようになる | 日付や時刻の質問をシートの値から読んでいる | namedValues の文字を使う。シートから読むなら Utilities.formatDate で整える |
失敗したときは、noreply-apps-scripts-notifications@google.com からトリガーを作った人あてに失敗のまとめのメールが届きます。受付用のアカウントのメールを誰も見ていないと、このメールに気づけません。受付用のアカウントのメールは info@ に転送しておくか、週に1回はログインして見ます。止まったときの見方は「GASが止まったとき:エラー・実行時間・上限の見方」に書いています。
次にやること
確認メールが動いたら、トリガーと送信の仕組みを広げます。
- Googleフォームの作り方:申込・予約・アンケートを受ける
- GASのトリガー:定期実行・フォーム送信時・編集時
- GASでメールを自動送信する:スプレッドシートの宛先に1通ずつ差し込む
- GASが止まったとき:エラー・実行時間・上限の見方