GAS×Googleフォーム連携|回答の自動集計・通知・転記を完全解説

しんたろ。

Googleフォームの回答を自動で集計・通知・転記したい!GASを使えば、フォーム送信をトリガーにあらゆる自動処理が実現できます。この記事でコピペ実装しましょう!

この記事でわかること
  • GAS×Googleフォーム連携の初期設定とonFormSubmitトリガーの使い方
  • フォーム送信時の管理者通知・自動返信メールの実装方法
  • 回答内容に応じた条件分岐通知(メール・Slack・LINE)
  • 回答データの別シート自動転記と集計ダッシュボードの作り方
  • トリガーが動かないときのデバッグ方法とベストプラクティス
  • Excel VBA UserFormとの比較で理解するGASの優位性
フォーム連携スクリプトの実行を体験してみよう!

「実行」ボタンを押すと、Googleフォームの回答を受け取って自動通知・返信メールを送信するGASの動作をシミュレーション体験できます。

📋 お問い合わせフォーム(送信済みデータ)
お名前
田中太郎
メールアドレス
tanaka@example.com
お問い合わせ内容
GASの使い方について質問があります。初心者ですが始められますか?
</> onFormSubmit.gs
1function onFormSubmit(e) { 2 const responses = e.namedValues; 3 const email = responses[‘メールアドレス’][0]; 4 const name = responses[‘お名前’][0]; 5 6 // 管理者に通知 7 MailApp.sendEmail(‘admin@example.com’, 8 ‘新しい回答が届きました’, body); 9 10 // 回答者に自動返信 11 MailApp.sendEmail(email, 12 ‘お問い合わせを受け付けました’, reply); 13}
実行ログ ─ onFormSubmit (トリガー: フォーム送信時)
10:15:01[TRIGGER] フォーム送信イベントを検知
10:15:01[INFO] e.namedValues を解析中… 3項目を取得
10:15:02[OK] 管理者通知メール送信: admin@example.com
10:15:03[OK] 自動返信メール送信: tanaka@example.com
10:15:03[OK] スプレッドシートに回答を記録完了
10:15:03[DONE] 全処理が正常に完了しました
📩 管理者通知メール
To: admin@example.com
件名: 新しい回答が届きました

■ お名前: 田中太郎
■ メールアドレス: tanaka@…
■ お問い合わせ内容: GASの使い方について…
✉ 自動返信メール
To: tanaka@example.com
件名: お問い合わせを受け付けました

田中太郎 様
お問い合わせありがとうございます。
2営業日以内にご連絡いたします。
この記事の目次
  1. GAS×Googleフォーム連携でできること
  2. 準備編|フォームとスクリプトの初期設定
  3. 基本編|フォーム送信時の自動メール通知
  4. 応用編|条件分岐による自動処理
  5. 実践編|フォーム回答の自動集計ダッシュボード
  6. エラー対処とベストプラクティス
  7. VBAとGASのフォーム連携比較
  8. よくある質問(FAQ)
  9. まとめ
  10. LINEでExcelを気軽に学べる

GAS×Googleフォーム連携でできること

Googleフォームは、アンケートや問い合わせフォームとして広く使われていますが、回答の確認や集計は手作業で行っている方も多いのではないでしょうか。Google Apps Script(GAS)を使えば、フォーム送信を「きっかけ」にしてさまざまな処理を自動化できます。

GASの基本的な使い方についてはGAS入門ガイドで解説していますので、初めての方はそちらも参考にしてください。

フォーム回答の自動処理フロー

GAS×Googleフォーム連携の基本的な処理フローは以下の通りです。

  1. ユーザーがGoogleフォームに回答を送信
  2. 回答がスプレッドシートに自動記録(Googleフォーム標準機能)
  3. onFormSubmitトリガーが発火し、GASスクリプトが実行される
  4. GASが自動処理を実行(メール通知・データ転記・集計更新など)

このフローにより、フォーム送信から数秒〜30秒で自動処理が完了します。管理者が回答を確認しに行く必要がなくなり、大幅な業務効率化が実現できます。

手動 vs GAS自動化の比較

フォーム回答の処理を手動で行う場合とGASで自動化する場合を比較してみましょう。

項目 手動対応 GAS自動化
通知タイミング定期的にシートを確認送信直後に即通知
返信メール1件ずつ手動送信自動返信
データ集計手動でピボット/関数リアルタイム自動集計
条件分岐対応目視で確認して振り分け自動で通知先振り分け
対応漏れリスク高いほぼゼロ

準備編|フォームとスクリプトの初期設定

GASでフォーム連携を始めるには、まずGoogleフォームの作成とスクリプトエディタの設定が必要です。ここでは初期設定の手順を解説します。

Googleフォームの作成と回答スプレッドシートの連携

Googleフォームの回答をGASで処理するには、まず回答をスプレッドシートに連携させます。

  1. Googleフォームを開いて新しいフォームを作成
  2. 必要な質問項目(名前・メールアドレス・問い合わせ内容など)を追加
  3. 「回答」タブ →「スプレッドシートにリンク」をクリック
  4. 「新しいスプレッドシートを作成」を選択して「作成」

これで、フォームに回答が送信されるたびにスプレッドシートに1行ずつデータが追記されます。このスプレッドシートがGASの処理対象になります。

スクリプトエディタの開き方(フォーム側 vs スプシ側)

GASのスクリプトエディタは、フォーム側スプレッドシート側の2箇所から開けます。それぞれ特徴が異なります。

開き方 操作 用途
フォーム側フォーム編集画面 →「︙」→「スクリプトエディタ」FormAppでフォーム自体を操作したい場合
スプレッドシート側スプレッドシート →「拡張機能」→「Apps Script」回答データの加工・集計がメインの場合(推奨)

本記事ではスプレッドシート側からスクリプトエディタを開く方法を推奨します。回答データへのアクセスが簡単で、スプレッドシートの操作関数もそのまま使えるためです。

onFormSubmitトリガーの設定

フォーム送信時にGASを自動実行するには、onFormSubmitトリガーを設定します。設定手順は以下の通りです。

  1. スクリプトエディタを開く
  2. 左メニューの「トリガー」(時計アイコン)をクリック
  3. 右下の「+トリガーを追加」をクリック
  4. 以下のように設定する:
    • 実行する関数:onFormSubmit(これから作成する関数名)
    • イベントのソース:「スプレッドシートから」
    • イベントの種類:「フォーム送信時」
  5. 「保存」をクリック → Googleアカウントの認証を許可
初回の認証について

トリガー保存時にGoogleアカウントの認証画面が表示されます。「詳細」→「(プロジェクト名)に移動」→「許可」の順にクリックしてください。この認証はGASがGmail送信やスプレッドシート操作を行うために必要です。

基本編|フォーム送信時の自動メール通知

まずは最も需要の高い「フォーム送信時にメール通知を送る」機能を実装します。GASのメール自動送信の基本についてはこちらの記事もご覧ください。

管理者への通知メール送信

フォームに回答が送信されたら、管理者にメールで通知するスクリプトです。回答の内容をメール本文に含めるので、スプレッドシートを開かずに内容を確認できます。

/**
 * フォーム送信時に管理者へ通知メールを送信する
 * トリガー設定: スプレッドシートの「フォーム送信時」
 */
function onFormSubmit(e) {
  // 管理者のメールアドレス(自分のアドレスに変更してください)
  const adminEmail = 'admin@example.com';

  // イベントオブジェクトから回答データを取得
  const responses = e.namedValues;

  // メール本文を組み立てる
  let body = '【Googleフォーム】新しい回答がありました。\n\n';
  for (const key in responses) {
    body += `■ ${key}\n${responses[key]}\n\n`;
  }

  // タイムスタンプを追加
  body += `送信日時: ${new Date().toLocaleString('ja-JP')}`;

  // メール送信
  MailApp.sendEmail({
    to: adminEmail,
    subject: '【フォーム通知】新しい回答が届きました',
    body: body
  });
}

e.namedValuesはフォームの質問名をキー、回答を値としたオブジェクトです。これをループすることで、フォームの質問項目が増えてもコードを変更する必要がありません。

回答者への自動返信メール

問い合わせフォームなどでは、回答者に「受付完了」の自動返信メールを送りたいケースがあります。フォームの質問に「メールアドレス」を含めていれば、以下のコードで自動返信が実現できます。

/**
 * フォーム回答者へ自動返信メールを送信する
 * 前提: フォームに「メールアドレス」という質問がある
 */
function onFormSubmitAutoReply(e) {
  const responses = e.namedValues;

  // 回答者のメールアドレスを取得
  const userEmail = responses['メールアドレス'][0];
  const userName = responses['お名前'][0] || 'お客様';

  // 返信メール本文
  const body = `${userName} 様

お問い合わせいただきありがとうございます。
以下の内容で受け付けました。

──────────────────
お名前: ${userName}
メールアドレス: ${userEmail}
お問い合わせ内容:
${responses['お問い合わせ内容'][0]}
──────────────────

担当者より2営業日以内にご連絡いたします。
しばらくお待ちください。

※このメールは自動送信です。`;

  // 自動返信メール送信
  MailApp.sendEmail({
    to: userEmail,
    subject: '【自動返信】お問い合わせを受け付けました',
    body: body,
    name: 'お問い合わせ窓口'  // 送信者名を設定
  });
}

responses['メールアドレス'][0][0]は、namedValuesの値が配列で返されるためです。単一回答の場合でも[0]でアクセスする必要があります。

回答内容をメール本文に含める方法

管理者通知と自動返信を1つの関数にまとめ、すべての回答内容をメール本文に含める実用的なパターンです。

/**
 * 管理者通知 + 自動返信を1関数で処理する統合版
 */
function onFormSubmitIntegrated(e) {
  const responses = e.namedValues;
  const userEmail = responses['メールアドレス'][0];
  const userName = responses['お名前'][0] || 'お客様';
  const adminEmail = 'admin@example.com';
  const timestamp = new Date().toLocaleString('ja-JP');

  // 全回答をフォーマットする関数
  function formatResponses(responses) {
    let text = '';
    for (const key in responses) {
      if (key === 'タイムスタンプ') continue;  // タイムスタンプはスキップ
      text += `【${key}】\n${responses[key][0]}\n\n`;
    }
    return text;
  }

  const responseText = formatResponses(responses);

  // 1. 管理者への通知メール
  MailApp.sendEmail({
    to: adminEmail,
    subject: `【新規問い合わせ】${userName}様より`,
    body: `新しい問い合わせがありました。\n\n${responseText}受信日時: ${timestamp}`
  });

  // 2. 回答者への自動返信メール
  MailApp.sendEmail({
    to: userEmail,
    subject: '【自動返信】お問い合わせありがとうございます',
    body: `${userName} 様\n\nお問い合わせありがとうございます。\n以下の内容で受け付けました。\n\n${responseText}2営業日以内にご連絡いたします。\n\n※このメールは自動送信です。`,
    name: 'お問い合わせ窓口'
  });
}
この操作でよくある疑問

Q: onFormSubmitトリガーが二重に発火してメールが2通届くことはありますか?

A: まれにGoogleのサーバー側で再試行が発生し、トリガーが複数回実行されることがあります。対策として、スプレッドシートに「処理済みフラグ」列を作り、回答のタイムスタンプが処理済みなら早期リターンするガード処理を入れておくと安全です。

筆者の実務Tips

社内の問い合わせフォームをGAS連携にしたところ、管理者への通知が即時になり、平均対応時間が4時間→30分に短縮されました。特に自動返信メールの効果が大きく、「問い合わせしたのに返事が来ない」というクレームがゼロになりました。回答者への自動返信は内容のオウム返し+対応目安時間の明記がポイントです。

応用編|条件分岐による自動処理

基本的なメール通知ができたら、次は回答内容に応じた条件分岐処理を実装しましょう。「問い合わせ種別」によって通知先を変えたり、特定のキーワードが含まれる場合にSlackへ通知したりできます。

回答内容に応じた通知先の振り分け

フォームに「問い合わせ種別」(例:営業・技術サポート・その他)という選択肢がある場合、種別ごとに通知先を切り替えるコードです。

/**
 * 問い合わせ種別に応じて通知先を自動振り分け
 */
function onFormSubmitRouting(e) {
  const responses = e.namedValues;
  const category = responses['問い合わせ種別'][0];
  const userName = responses['お名前'][0];

  // 種別ごとの通知先マッピング
  const routingMap = {
    '営業に関するお問い合わせ': 'sales@example.com',
    '技術サポート':           'support@example.com',
    '採用について':           'hr@example.com',
    'その他':                'info@example.com'
  };

  // 通知先を決定(マッピングにない場合はデフォルト)
  const toEmail = routingMap[category] || 'info@example.com';

  // 回答内容を組み立て
  let body = `【${category}】の問い合わせがありました。\n\n`;
  for (const key in responses) {
    if (key === 'タイムスタンプ') continue;
    body += `■ ${key}: ${responses[key][0]}\n`;
  }

  // 振り分け先にメール送信
  MailApp.sendEmail({
    to: toEmail,
    subject: `【${category}】${userName}様からの問い合わせ`,
    body: body
  });

  // ログに記録(デバッグ用)
  console.log(`通知先: ${toEmail} / 種別: ${category}`);
}

特定条件でSlack/LINEに通知

緊急の問い合わせが来たときにSlackやLINE Notifyへ通知を飛ばすパターンです。Webhook URLを使って外部サービスに連携します。

/**
 * 緊急度が高い回答をSlack/LINEに即時通知
 */
function onFormSubmitWithSlack(e) {
  const responses = e.namedValues;
  const urgency = responses['緊急度'][0];
  const content = responses['お問い合わせ内容'][0];
  const userName = responses['お名前'][0];

  // 通常のメール通知(全件)
  MailApp.sendEmail({
    to: 'admin@example.com',
    subject: `【フォーム通知】${userName}様`,
    body: `緊急度: ${urgency}\n内容: ${content}`
  });

  // 緊急度が「高」の場合のみSlackに通知
  if (urgency === '高') {
    sendToSlack(`🚨 *緊急の問い合わせ*\n>名前: ${userName}\n>内容: ${content}`);
  }

  // LINE Notifyに通知する場合
  if (urgency === '高') {
    sendToLine(`【緊急】${userName}様: ${content}`);
  }
}

/**
 * Slack Incoming Webhookで通知を送信
 */
function sendToSlack(message) {
  const webhookUrl = 'https://hooks.slack.com/services/YOUR/WEBHOOK/URL';

  UrlFetchApp.fetch(webhookUrl, {
    method: 'post',
    contentType: 'application/json',
    payload: JSON.stringify({ text: message })
  });
}

/**
 * LINE Notifyで通知を送信
 */
function sendToLine(message) {
  const token = 'YOUR_LINE_NOTIFY_TOKEN';

  UrlFetchApp.fetch('https://notify-api.line.me/api/notify', {
    method: 'post',
    headers: { 'Authorization': 'Bearer ' + token },
    payload: { message: message }
  });
}
Webhook URLの取得方法
  • Slack:Slack App設定 → Incoming Webhooks → Webhook URLをコピー
  • LINE NotifyLINE Notifyでトークンを発行

回答データの別シートへの自動転記

フォーム回答を条件別に別のシートへ自動転記するスクリプトです。例えば、部署別にシートを分けて管理したい場合に便利です。

/**
 * フォーム回答を部署別のシートへ自動転記
 */
function onFormSubmitTransfer(e) {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const responses = e.namedValues;
  const department = responses['部署'][0];
  const timestamp = new Date();

  // 部署名のシートを取得(なければ新規作成)
  let targetSheet = ss.getSheetByName(department);
  if (!targetSheet) {
    targetSheet = ss.insertSheet(department);
    // ヘッダー行を追加
    const headers = Object.keys(responses);
    targetSheet.getRange(1, 1, 1, headers.length).setValues([headers]);
    targetSheet.getRange(1, 1, 1, headers.length)
      .setBackground('#4285f4')
      .setFontColor('#ffffff')
      .setFontWeight('bold');
  }

  // 回答データを配列に変換
  const headers = Object.keys(responses);
  const rowData = headers.map(key => responses[key][0]);

  // シートの最終行に追記
  const lastRow = targetSheet.getLastRow();
  targetSheet.getRange(lastRow + 1, 1, 1, rowData.length).setValues([rowData]);

  // 転記完了をログ出力
  console.log(`${department}シートに転記完了(行${lastRow + 1})`);
}

このスクリプトは、部署名のシートが存在しない場合に自動で新規作成し、ヘッダー付きのシートを生成します。回答が増えても自動的にシートが整理されます。

この操作でよくある疑問

Q: フォームの回答が多い場合、GASの実行時間制限(6分)に引っかかりませんか?

A: onFormSubmitトリガーは1回の回答ごとに発火するため、通常は数秒で処理が完了し6分制限の心配はありません。ただし、1回の処理で大量のシートコピーやAPI呼び出しを行う場合は注意が必要です。処理を分割するか、非同期トリガーで後続処理をキューイングする設計にしましょう。

筆者の実務Tips

条件分岐で通知先を振り分ける場合、部署名やカテゴリのマスタをスプレッドシートの別シートで管理するのがおすすめです。スクリプトにハードコードすると変更のたびにコード修正が必要になりますが、マスタシート方式なら非エンジニアでもメンテできます。実際に30部署への振り分けをこの方式で運用し、半年間コード修正ゼロで回せました。

実践編|フォーム回答の自動集計ダッシュボード

フォーム回答の集計を自動化し、ダッシュボードとして可視化する方法を解説します。回答数の推移や選択肢ごとの割合を自動で計算・グラフ化できます。

回答数・割合の自動計算

フォーム回答の選択肢ごとにカウント・割合を自動計算し、「集計」シートに出力するスクリプトです。

/**
 * フォーム回答の集計を「集計」シートに自動出力
 */
function aggregateResponses() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const dataSheet = ss.getSheetByName('フォームの回答 1');
  const data = dataSheet.getDataRange().getValues();

  // 集計シートを取得(なければ作成)
  let summarySheet = ss.getSheetByName('集計');
  if (!summarySheet) {
    summarySheet = ss.insertSheet('集計');
  }
  summarySheet.clear();

  const headers = data[0];
  const responses = data.slice(1);  // ヘッダーを除外

  // 全体の回答数
  const totalCount = responses.length;

  // 各質問ごとの集計を出力
  let outputRow = 1;
  summarySheet.getRange(outputRow, 1).setValue('回答集計レポート');
  summarySheet.getRange(outputRow, 1).setFontSize(14).setFontWeight('bold');
  outputRow += 1;
  summarySheet.getRange(outputRow, 1).setValue(`総回答数: ${totalCount}件`);
  summarySheet.getRange(outputRow, 2).setValue(`最終更新: ${new Date().toLocaleString('ja-JP')}`);
  outputRow += 2;

  // タイムスタンプ以外の各列を集計
  for (let col = 1; col < headers.length; col++) {
    const question = headers[col];
    const counts = {};

    // 各回答をカウント
    responses.forEach(row => {
      const answer = String(row[col]).trim();
      if (answer) {
        counts[answer] = (counts[answer] || 0) + 1;
      }
    });

    // 質問名を出力
    summarySheet.getRange(outputRow, 1).setValue(`■ ${question}`);
    summarySheet.getRange(outputRow, 1).setFontWeight('bold').setBackground('#e8f0fe');
    summarySheet.getRange(outputRow, 1, 1, 3).setBackground('#e8f0fe');
    outputRow++;

    // ヘッダー
    summarySheet.getRange(outputRow, 1, 1, 3).setValues([['回答', '件数', '割合']]);
    summarySheet.getRange(outputRow, 1, 1, 3).setFontWeight('bold');
    outputRow++;

    // 各回答の件数と割合
    for (const answer in counts) {
      const count = counts[answer];
      const percentage = ((count / totalCount) * 100).toFixed(1) + '%';
      summarySheet.getRange(outputRow, 1, 1, 3).setValues([[answer, count, percentage]]);
      outputRow++;
    }
    outputRow++;  // 質問間のスペース
  }

  // 列幅を自動調整
  summarySheet.autoResizeColumns(1, 3);
}

グラフの自動更新設定

集計結果をグラフで可視化すると、データの傾向が直感的に把握できます。スプレッドシートのCOUNTIF関数とグラフ機能を組み合わせれば、フォーム回答が追加されるたびにグラフも自動更新されます。

GASでグラフをプログラム的に作成することも可能ですが、最も簡単な方法はスプレッドシートのCOUNTIF関数で集計セルを作り、標準のグラフ挿入機能を使うことです。回答データの範囲が増えてもグラフが自動で更新されます。

具体的な手順は以下の通りです。

  1. 「集計」シートにCOUNTIF関数で選択肢ごとのカウントセルを作成
  2. カウントセルの範囲を選択 →「挿入」→「グラフ」
  3. グラフの種類(円グラフ・棒グラフなど)を選択
  4. フォーム回答が追加されるたびにCOUNTIFの値が更新され、グラフも連動

定期レポートのメール自動送信

集計結果を毎週月曜日にメールで自動送信するスクリプトです。時間主導型トリガーと組み合わせて使います。

/**
 * 集計レポートをメールで自動送信
 * トリガー設定: 時間主導型 → 週タイマー → 毎週月曜9:00
 */
function sendWeeklyReport() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const dataSheet = ss.getSheetByName('フォームの回答 1');
  const data = dataSheet.getDataRange().getValues();
  const totalCount = data.length - 1;  // ヘッダーを除く

  // 直近1週間の回答数を計算
  const oneWeekAgo = new Date();
  oneWeekAgo.setDate(oneWeekAgo.getDate() - 7);

  let weeklyCount = 0;
  for (let i = 1; i < data.length; i++) {
    const timestamp = new Date(data[i][0]);
    if (timestamp >= oneWeekAgo) {
      weeklyCount++;
    }
  }

  // レポート本文
  const report = `
【週次レポート】フォーム回答集計
━━━━━━━━━━━━━━━━━
集計期間: ${oneWeekAgo.toLocaleDateString('ja-JP')} 〜 ${new Date().toLocaleDateString('ja-JP')}

■ 総回答数: ${totalCount}件
■ 今週の回答数: ${weeklyCount}件

スプレッドシート:
${ss.getUrl()}

※このレポートは毎週月曜日に自動送信されます。
  `.trim();

  // レポート送信
  MailApp.sendEmail({
    to: 'admin@example.com',
    subject: `【週次レポート】フォーム回答 ${weeklyCount}件(${new Date().toLocaleDateString('ja-JP')})`,
    body: report
  });
}

このスクリプトに時間主導型トリガーを設定するには、スクリプトエディタの「トリガー」→「トリガーを追加」→ イベントのソースを「時間主導型」→「週ベースのタイマー」→「毎週月曜日」→「午前9時〜10時」に設定します。

エラー対処とベストプラクティス

GAS×フォーム連携で起こりやすいエラーと、その対処法をまとめます。

「トリガーが実行されない」場合の確認ポイント

トリガーを設定したのにフォーム送信時にスクリプトが実行されない場合、以下を順番に確認してください。

  1. トリガーの設定内容:「実行する関数名」がスクリプト内の関数名と完全一致しているか確認。大文字・小文字の違いに注意
  2. 認証の許可:トリガー作成時のGoogleアカウント認証を完了しているか確認。「承認が必要です」エラーが出ていないか
  3. 実行ログの確認:スクリプトエディタ左メニュー「実行数」をクリックし、エラーが発生していないか確認
  4. スクリプトの紐付け先:フォーム側とスプレッドシート側でスクリプトを混在させていないか確認。トリガーのイベントソースが正しいか
  5. クォータ制限:1日のトリガー実行回数(無料アカウントで90分/日)を超えていないか確認

イベントオブジェクト(e)のundefinedエラー

最も多いエラーが「TypeError: Cannot read properties of undefined (reading 'namedValues')」です。これはスクリプトエディタから直接「実行」ボタンで関数を手動実行した場合に発生します。

イベントオブジェクトeは、トリガー経由で実行されたときのみ自動で渡されます。手動実行ではeが存在しないため、undefinedエラーになります。

デバッグ用のテスト方法

手動テストしたい場合は、以下のようにダミーのイベントオブジェクトを作成して渡します。

function testOnFormSubmit() {
  // ダミーのイベントオブジェクト
  const e = {
    namedValues: {
      'お名前': ['テスト太郎'],
      'メールアドレス': ['test@example.com'],
      'お問い合わせ内容': ['テスト送信です']
    }
  };
  onFormSubmit(e);
}

フォーム回答のタイムスタンプずれ対策

フォーム回答のタイムスタンプがずれる場合は、スクリプトのタイムゾーン設定を確認してください。

  1. スクリプトエディタ →「プロジェクトの設定」(歯車アイコン)
  2. 「タイムゾーン」が「(GMT+09:00) 東京」になっているか確認
  3. スプレッドシートのタイムゾーンも確認:「ファイル」→「設定」→ タイムゾーン

GASコード内でタイムスタンプを取得する場合は、Utilities.formatDate(new Date(), 'Asia/Tokyo', 'yyyy/MM/dd HH:mm:ss')のようにタイムゾーンを明示的に指定すると確実です。

VBAとGASのフォーム連携比較

Excelユーザーにとって、VBAのUserFormとGASのGoogleフォーム連携は似た目的で使われます。ここでは両者のコードと特徴を比較します。

Excel VBA + UserFormのコード例

VBAでフォームから入力データをシートに書き込む基本的なコードです。

' VBA: UserFormの送信ボタンクリック時の処理
Private Sub btnSubmit_Click()
    Dim ws As Worksheet
    Set ws = ThisWorkbook.Sheets("回答データ")

    ' 最終行を取得
    Dim lastRow As Long
    lastRow = ws.Cells(ws.Rows.Count, 1).End(xlUp).Row + 1

    ' フォームの入力値をシートに書き込み
    ws.Cells(lastRow, 1).Value = Now()              ' タイムスタンプ
    ws.Cells(lastRow, 2).Value = txtName.Value       ' 名前
    ws.Cells(lastRow, 3).Value = txtEmail.Value      ' メール
    ws.Cells(lastRow, 4).Value = txtContent.Value    ' 内容

    ' メール通知(Outlookが必要)
    Dim olApp As Object
    Set olApp = CreateObject("Outlook.Application")
    Dim olMail As Object
    Set olMail = olApp.CreateItem(0)

    With olMail
        .To = "admin@example.com"
        .Subject = "【フォーム通知】" & txtName.Value & "様"
        .Body = "名前: " & txtName.Value & vbCrLf & _
                "メール: " & txtEmail.Value & vbCrLf & _
                "内容: " & txtContent.Value
        .Send
    End With

    MsgBox "送信が完了しました。", vbInformation

    ' フォームをクリア
    txtName.Value = ""
    txtEmail.Value = ""
    txtContent.Value = ""
End Sub

GASとVBAのフォーム処理比較表

比較項目 GAS + Googleフォーム VBA + UserForm
フォーム作成GUI(ノーコード)VBAエディタで設計
回答方法URL共有(スマホ対応)Excelファイルを配布
自動トリガーonFormSubmit(サーバー側)なし(ボタン実行)
メール送信MailApp(Gmail直結)Outlook連携が必要
外部連携Slack/LINE/API連携が容易API連携は複雑
同時回答複数人が同時回答可能ファイル共有に制限
オフライン不可(ネット必須)可能
費用無料Microsoft 365が必要

アンケートや問い合わせフォームのように多人数から回答を集める用途ではGAS + Googleフォームが圧倒的に有利です。一方、社内の業務用入力フォームでExcel上での操作が必要な場合はVBA + UserFormが適しています。

よくある質問(FAQ)

Q. フォーム送信後の自動処理にタイムラグはありますか?

通常1〜30秒程度で実行されます。トリガーの実行ログ(スクリプトエディタ → 左メニュー「実行数」)で実行時刻と所要時間を確認できます。処理が重い場合(大量のメール送信や外部API呼び出し)は数分かかることもあります。

Q. 1つのフォームに複数のGASトリガーを設定できますか?

はい、可能です。ただし同じイベント(onFormSubmit)に複数トリガーを設定すると実行順序は保証されません。順序が重要な場合は、1つのトリガー関数内で順番に処理を呼び出す設計にしましょう。

Q. フォーム回答の自動削除はGASでできますか?

はい、FormApp.openById()でフォームにアクセスし、deleteAllResponses()で全回答削除が可能です。個別削除はフォームAPIでは直接サポートされていないため、スプレッドシート側の行削除で対応します。

Q. Googleフォーム以外のフォームサービスとGASは連携できますか?

WebhookやUrlFetchAppを使えば、他のフォームサービス(Typeform、JotFormなど)からのデータ受信も可能です。GASをWebアプリとしてデプロイし、外部サービスのWebhook送信先にGASのURLを設定する方法が一般的です。

Q. GASのフォーム連携にプログラミング経験は必要ですか?

基本的な連携ならこの記事のコードをコピペで実装できます。カスタマイズ(条件分岐の追加・メール文面の変更など)にはJavaScriptの基礎知識があると便利です。GAS入門ガイドで基礎を学ぶことをおすすめします。

まとめ

この記事では、GAS×Googleフォーム連携による回答の自動集計・通知・転記の方法を解説しました。

この記事のポイント
  • onFormSubmitトリガーでフォーム送信を検知し、自動処理を実行できる
  • 管理者通知・自動返信メールはコピペで実装可能
  • 条件分岐で通知先の振り分け、Slack/LINE連携も簡単
  • 回答データの別シート転記と集計ダッシュボードで可視化
  • イベントオブジェクト(e)のundefinedエラーはダミーデータで回避

まずは「管理者への通知メール」から始めて、慣れてきたら条件分岐や集計ダッシュボードに挑戦してみてください。フォーム回答の処理を自動化するだけで、日常業務の手間が大幅に削減されます。

GAS開発・自動化のご相談はこちら

「自分でGASを書くのは大変…」「もっと本格的な自動化をしたい」という方へ。GAS開発代行・自動化コンサルティングを承っています。

自動化コンサルティングの詳細はこちら →

期間限定でChatGPT✖︎Googleスプレットシートのコンテンツ配布中!

LINEでExcelを気軽に学べる

しんたろ。
しんたろ。
Excel歴10年以上 → アプリ開発者
Profile
大手メーカーに15年以上勤務。製造部門で海外拠点の立ち上げ支援や、現場責任者として採算管理・納期管理・設備オペレートを経験。 2023年にDX人材育成プログラム第1期生として活動後、現在は製造現場のスケジュール運用を支えるアプリの企画・開発をメインに活動中。工程表示表作成の内製化SaaSを構築し、年間1,300万円のコスト改善を実現。 Excelによる業務改善で年間240時間の残業削減を達成した経験を活かし、ブログやSNSでも情報発信しています。
プロフィールを読む

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

ABOUT ME
しんたろ。
しんたろ。
Excel歴10年以上 → アプリ開発者
大手メーカーに15年以上勤務。製造部門で海外拠点の立ち上げ支援や、現場責任者として採算管理・納期管理・設備オペレートを経験。 2023年にDX人材育成プログラム第1期生として活動後、現在は製造現場のスケジュール運用を支えるアプリの企画・開発をメインに活動中。工程表示表作成の内製化SaaSを構築し、年間1,300万円のコスト改善を実現。 Excelによる業務改善で年間240時間の残業削減を達成した経験を活かし、ブログやSNSでも情報発信しています。
記事URLをコピーしました