Googleフォーム自動返信をGASで実装|つまずく4点も解説

GoogleフォームとGASで回答者に自動返信メールを送る記事のアイキャッチ AI自動化

Googleフォームの標準機能にも自動返信はあります。ただ、送られるのは「回答のコピー」だけ。お礼の言葉も、次のご案内も、自分の言葉では一文字も書けません。

この記事では、GAS(Google Apps Script)でGoogleフォームの回答者に自分の文面の自動返信メールを送る方法を、コピペで動くコードまで載せて解説します。メールアドレスの収集設定からトリガー登録まで、順番どおりに進めれば動きます。

そして後半では、実際に手を動かして踏んだつまずき4点と、自動返信が届かないときの切り分け手順を載せます。ここが本題です。手順どおりに書いたのに動かないとき、原因はだいたい記事に書かれていない場所にあります。

なお、フォームの回答を管理者である自分に通知する方法は別記事で解説しています。この記事は逆に、回答者に返す側の話です。

標準機能の自動返信では何ができないのか

Googleフォームには「回答のコピーを回答者に送信」という設定があります。まずはこれで足りるかを確認しましょう。

3つの方法を比べます。

方法 文面のカスタマイズ 条件分岐 費用
標準機能(回答のコピー) できない(回答内容がそのまま届く) できない 無料
アドオン(Email Notifications 等) ある程度できる 限定的 無料枠あり
GAS 自由(件名・本文・署名すべて) できる 無料

標準機能で困るのは、件名も本文も編集できない点です。「お問い合わせありがとうございます」の一言も、「3営業日以内にご返信します」という案内も入れられません。回答内容の控えが届くだけです。

アドオンを入れれば文面は書けますが、無料枠やカスタマイズ範囲に制限があります。

GASなら文面は完全に自由で、費用もかかりません。書くコードも10行ほどです。この記事ではGASで進めます。

準備:メールアドレスの収集とApps Scriptを開く

1. 「メールアドレスを収集する」をONにする

フォームの設定タブ → 回答 → メールアドレスを収集するをONにします。

これがないと返信先が取れません。自動返信が動かないとき、まず見直したい設定です。

収集方法は「回答者からの入力」と「確認済み」の2つから選べます。どちらを選んでも構いません。

実際に両方の設定で送信してログを確認しましたが、後述の e.namedValues の中身に違いはありませんでした。 キー名も値の形も同じです。どちらでも同じコードで動きます。

なお、フォームの設定に保存ボタンはありません。自動保存です。

2. 回答をスプレッドシートに連携する

回答タブ → スプレッドシートにリンクで新規作成します。

3. Apps Scriptを開く

作成されたスプレッドシートで拡張機能 → Apps Scriptを開きます。ここにコードを書きます。

💡 動作確認はプレビューではできません。 フォーム編集画面のプレビュー(👁アイコン)から開いた画面では、送信ボタンがグレーアウトして「プレビューモードではフォームを送信できません」と表示されます。テストするときは「送信」ボタン → 🔗リンクタブのURLを開いてください。実際に回答者が見る画面です。

GASで自動返信メールを送る

コードの全文

Apps Scriptのエディタに、これをそのまま貼ります。

function onFormSubmit(e) {
  // e.namedValues の値は「配列」で返る。[0] を付けないと宛先が壊れる
  var to   = e.namedValues['メールアドレス'][0];
  var name = e.namedValues['お名前'][0];
  var text = e.namedValues['お問い合わせ内容'][0];

  var subject = '【自動返信】お問い合わせありがとうございます';
  var body = name + ' 様\n\n'
           + 'お問い合わせありがとうございます。\n以下の内容で承りました。\n\n'
           + text + '\n\n--\nkverza';

  GmailApp.sendEmail(to, subject, body);
}

'お名前' 'お問い合わせ内容' の部分は、自分のフォームの質問文にそのまま置き換えてください。キー名は質問文と完全に一致している必要があります。

メール送信は GmailApp.sendEmail(宛先, 件名, 本文) の1行だけです。管理者へのメール通知と同じ関数なので、そちらを読んでいる方はすぐ分かるはずです。

フォーム回答からonFormSubmit・e.namedValues・GmailApp.sendEmailを経て回答者へ自動返信が届くまでの流れ図
フォーム回答から自動返信メールが届くまでの流れ

回答の中身を取り出す

e.namedValues に何が入っているかを、実際のログで見てみます。以下は「お名前・お問い合わせ内容」の2問だけのフォームに1回答したときの実物です。

=== namedValues ===
{
  "タイムスタンプ": ["2026/07/20 7:11:05"],
  "お名前": ["向山陸"],
  "メールアドレス": ["xxxxx@example.com"],
  "お問い合わせ内容": ["test1"]
}

ポイントが2つあります。

1つ目:値はすべて配列です。 "お名前": ["向山陸"] のように角括弧が付いています。だから e.namedValues['お名前'] だけでは配列そのものを取ってしまい、[0] を付けて初めて中身の文字列になります。

2つ目:「メールアドレス」というキーが自動で増えています。 これは質問として作ったものではなく、「メールアドレスを収集する」をONにしたことでフォームが自動で付けたものです。

onFormSubmitトリガーを手動で登録する

コードを書いて保存しただけでは動きません。 トリガーの登録が必要です。

Apps Scriptの左メニューから時計アイコン(トリガー)→ トリガーを追加を選び、以下を設定します。

  • 実行する関数:onFormSubmit
  • イベントのソース:スプレッドシートから
  • イベントの種類:フォーム送信時

保存すると、権限の承認を求められます。「このアプリはGoogleで確認されていません」という警告画面が出ますが、これは自分で書いたスクリプトなので正常な流れです。「詳細」→「安全ではないページに移動」と進んで承認してください。ここで引き返すとトリガーは登録されません。

ここまでできたら、リンクからフォームを送信してみてください。自動返信が届きます。

つまずいた点:4つ

ここからが本題です。実際に手を動かして踏んだものだけを書きます。

① e.namedValues は配列なので [0] が要る

先ほど触れたとおりです。[0] を付け忘れると、宛先や本文に配列がそのまま入って壊れます。

これは他の記事のコードを流用したときに踏みやすい罠です。動いているコードを見ても、[0] は目立たないので写し漏らします。

② e.values の並びは質問の順番と一致しない

e.namedValues の代わりに e.values(配列)を使う書き方もあります。ですがこちらは危険です。同じ回答の e.values を見てください。

=== values ===
["2026/07/20 7:11:05","xxxxx@example.com","向山陸","test1"]

フォームの質問順は「お名前 → お問い合わせ内容」なのに、2番目にメールアドレスが割り込んでいます。メールアドレスは質問として作っていないのに、列としては先に入るからです。

つまり e.values[1] を「お名前」だと思って書くと、メールアドレスが名前として本文に差し込まれます。しかもエラーは出ません。「◯◯@gmail.com 様」という自動返信が、静かに送られ続けます。

e.namedValues を使ってください。 質問文をキーにして取り出せるので、列の順番に影響されません。

③ コードに機能を足したら、権限を承認し直す必要がある

これが一番はまりました。

トリガー登録のときに権限を承認済みでも、あとからコードに新しい機能を足すと、その分の権限が足りなくなります。今回は最初ログ出力だけのコードで動かしていて、そこに GmailApp.sendEmail を足したところ、実行が失敗しました。

Exception: The script does not have permission to perform that action.
Required permissions: (https://mail.google.com/ || .../auth/gmail.send || ...)
    at onFormSubmit(コード:7:22)

厄介なのはここからです。トリガー経由の実行はバックグラウンドで動くので、承認ダイアログが出ません。 画面には何も起きず、回答者からは「フォームに答えたのにメールが来ない」としか見えません。自分で実行ログを見に行かないと、原因にたどり着けないのです。

対処法:エディタ上部の関数選択から手動で関数を実行します。手動実行なら承認ダイアログが出るので、そこで承認すればトリガー経由の実行も通るようになります。実際に承認後にフォームを送信し直したら、正常に届きました。

④ トリガーが2件あると、2通届く

別のプロジェクトを使い回したときに起きます。前のトリガーが残ったまま新しいトリガーを追加すると、1回の送信で2回実行されます。

実際にトリガーを2件登録して確認しました。フォームを1回送信して、届いたメールは2通、実行数の記録も2行でした。

なお、この「使い回しで古いトリガーが残る」パターンは、Slack/Discord通知の記事を書いたときに実際に踏んでいます。通知が2通来て、原因が前のプロジェクトのトリガーだと気づくまで少し時間がかかりました。

確認方法:時計アイコンのトリガー一覧を開いて、同じ関数のトリガーが複数ないか見てください。余分なものは削除すれば1通に戻ります。

自動返信が届かないときの確認手順

「動かない」ときは、上から順に見てください。この順番には理由があります。

1. まず実行ログを見る

Apps Scriptの左メニュー「実行数」を開きます。フォーム送信のタイミングで実行の記録があるか、ステータスは何かを確認します。

迷惑メールフォルダから確認し始める解説をよく見かけますが、GASで組んだ場合、原因はもっと手前にあることが多いです

技術的な理由もあります。GmailApp.sendEmail成功したかどうかを表す値を返しません(戻り値は GmailApp オブジェクトです)。外部サービスへの通知なら応答コードで成否を判定できますが、GmailAppではそれができません。確認手段が実行ログとトリガー履歴しかないのです。

2. ログが空でも「動いていない」と決めつけない

実行の行はあるのに「この実行に関するログはありません/遅延が発生している可能性があります」と表示されることがあります。これは実際に起きました。

このとき確認すべきは次の2つです。

  • 実行のステータスが「完了」になっているか
  • スプレッドシートに回答の行が増えているか

どちらも問題なければ、処理は動いています。ログの表示が数分遅れているだけです。実際、数分後に見たらログは出ていました。

3. 権限が承認されているか

前章の③です。コードに機能を足したあとは特に疑ってください。トリガー経由では無言で失敗するため、実行ログのエラー文が唯一の手がかりになります。

4. トリガーが登録されているか、重複していないか

そもそも登録し忘れていないか。逆に2件登録されていないか(前章の④)。

5. 宛先が正しく取れているか

Logger.log(e.namedValues) を仕込んで、実物を見てください。[0] の付け忘れや、キー名(質問文)の書き間違いがすぐ分かります。

6. 送信枠を超えていないか

MailApp.getRemainingDailyQuota() で残り枠を確認できます。

⚠️ この数字は「あと何通送れるか」ではありません。 筆者の環境では、1通送るごとに一貫して2ずつ減りました(1通で-2、2通で-4)。何を数えているのかは分かりませんが、通数と読み替えて設計しないほうが安全です

7. 迷惑メールフォルダ

ここまで見て問題なければ、最後に確認します。

応用:回答内容で文面を変える/通知と併用する

問い合わせ種別で返信文を出し分ける

フォームに「お問い合わせ種別」のようなプルダウンがあれば、if で分岐するだけです。

var kind = e.namedValues['お問い合わせ種別'][0];
var body = (kind === '見積り依頼')
  ? '見積りのご依頼ありがとうございます。3営業日以内にご返信します。'
  : 'お問い合わせありがとうございます。';

管理者への通知と回答者への返信を同時に動かす

onFormSubmit は1つの関数の中で両方できます。自分宛の通知と回答者への返信を、同じトリガーで送れます。

function onFormSubmit(e) {
  sendReply(e);   // 回答者へ自動返信
  sendNotify(e);  // 自分へ通知
}

関数を分けておくと、あとから通知先を増やすときにも楽です。実際、Slack/Discordへの通知も、送信部分を差し替えるだけで組めます。フォーム回答をきっかけに動かす部分は共通だからです。

関連記事:管理者へのメール通知LINEへの通知

まとめ

Googleフォームの回答者に、自分の文面で自動返信を送る手順をまとめます。

  1. 「メールアドレスを収集する」をONにする(収集方法はどちらでもよい)
  2. GmailApp.sendEmail(宛先, 件名, 本文) で送る。宛先は e.namedValues['メールアドレス'][0] から取る([0] を忘れない
  3. onFormSubmitトリガーを手動で登録する。コードを書くだけでは動かない
  4. 届かないときは実行ログから見る。迷惑メールフォルダは最後

まずは自分のフォームで1通送ってみてください。届いた瞬間に、この仕組みが自分のものになります。

この記事の仕組みを「頼みたい」「自分で全部そろえたい」方へ

🛠️ 作ってほしい:あなたのフォームに合わせて、自動返信の仕組みをまるごと構築します。ココナラで相談する

📦 自分でやる:フォーム自動化のコードをまとめたテンプレ集です。note「GAS自動化テンプレ集」を見る

最後までお読みいただきありがとうございました。

コメント

タイトルとURLをコピーしました