📧

[Tips]Google フォーム→メール送信時の Cannot read properties of undefined エラーを解消した

に公開

おはこんばんちは(挨拶)
もっさんです。

この記事はヌーラボブログリレー2025 冬 Tech の16日目として投稿しています。

Googleフォームの回答が送信されたことをトリガーに Backlog の課題を自動起票できれば、業務効率化がグッと進みますよね。

実は、Google Apps Script(GAS) を利用すると、 Backlog 課題の自動起票がスムーズに行えます。
私も自動化を狙ってGASを書き、実行したのですが、下記のエラーで失敗してしまいました。

TypeError: Cannot read properties of undefined (reading 'getResponse')

現在は解消できましたが、しばらく躓いたので、自分の備忘録も兼ねたトラブルシューティングとして記録を残しておきます。

前提 / 環境

実現したいこと(前提)

目的

Google フォームの回答が記録(送信)されたときに、フォームに入力された内容をもとに、Backlog で新しい課題を作成する。

方法

Backlog の『課題登録用メールアドレス』を用いて、Google フォームの回答を自動起票します。
手順の概要は以下のとおりです。

  1. Backlog の『課題登録用メールアドレス』を作成する
  2. Google フォームに GAS を設定し、フォームの回答が記録された時にメールを送信するようにスクリプトを記述する
  3. GAS 実行のトリガーを『フォーム送信時』に設定する

詳しい手順は、下記のドキュメントに記載されています。
Googleフォームに送信された内容をBacklogに登録しよう – Backlog ヘルプセンター

環境

スクリプト : Google Apps Script
エディタ : Google Apps Script のブラウザエディタから直接編集
Google フォーム : 最初の設問の回答内容に応じて、次の設問が分岐するよう設定されたフォーム

結論

結論を先に述べます。

TypeError: Cannot read properties of undefined (reading 'getResponse')

上記のエラーは、 Google フォームで回答によって次の設問が分岐する設定をしていた影響で、存在しない回答データを取得しようとしていたことに起因 していました。

回答データを1つずつ取り出して処理するロジックに変更することで、本エラーは解消できます。

トラブルシューティングの詳細

以降、エラーを生じた時のコードと原因、修正箇所を具体的に示します。

元々のコード

Google フォームには以下のGASを設定しています。
Googleフォーム上では、最初の設問でカテゴリーを選択し、「Aに関する相談」か「Bに関する相談」かで、その後の設問が変化するように設定しています。

sendTasksEmail
function sendTasksEmail(e) {

  // 送信された各回答と対応する質問名を格納する
  const itemResponses = e.response.getItemResponses(); 

  /*
  * メール本文
  * Googleフォームに設定した質問項目と対応させてください
  */

  // 相談のカテゴリー
  const ContentOfCategory = itemResponses[0].getResponse();
  // Aに関すること
  // Aに関する相談の概要
  const AContentOfOverview = itemResponses[1].getResponse();
  // Aの相談者の名前
  const AContentOfName = itemResponses[2].getResponse();
  // Aの希望対応日
  const ServisesStartOfdate = itemResponses[3].getResponse();
  // 相談意図、その他背景
  const AContentOfBackground = itemResponses[4].getResponse();
  // 想定している影響規模
  const AContentOfScale = itemResponses[5].getResponse();
  
  // Bに関すること
  // Bに関する相談の概要
  const BContentOfOverview = itemResponses[6].getResponse();
  // Bの希望対応日
  const BStartOfdate = itemResponses[7].getResponse();
    
  /*
  * 質問項目
  */
  const CATEGORY = "相談の分類";
  const A_OVERVIEW = "Aの相談の概要";
  const A_DEADLINE_DATE = "Aの希望対応日(締切)";
  const A_NAME = "Aの相談者の名前";
  const A_SCALE = "Aの想定している影響規模";
  const A_INTENTION = "Aの相談の意図、その他背景";

  const B_OVERVIEW = "Bの概要";
  const B_DEADLINE_DATE = "Bの希望対応日(締切)";


  /* 
  * メール送信先アドレス
  * Backlogの課題登録用メールアドレスを使用します。
  */ 
  const TO = "《課題登録用メールアドレス》";
  
  // メール件名
  const SUBJECT = ContentOfCategory + "に関する相談";
  
  //メールの内容(backlogの課題詳細に表示される)
  //設問と回答内容を両方転記する
  var body = "【" + CATEGORY + "】" + "\n" + ContentOfCategory + "\n\n" +
    "【" + A_OVERVIEW + "】" + "\n"  + AContentOfOverview + "\n\n" +
    "【" + A_NAME + "】" + "\n"  + AContentOfName + "\n\n" +
    "【" + A_DEADLINE_DATE + "】" + "\n"  + AStartOfdate + "\n\n" +
    "【" + A_INTENTION + "】" + "\n"  + AContentOfBackground + "\n\n" +
    "【" + A_SCALE + "】" + "\n"  + AContentOfScale + "\n\n" +
    "【" + B_OVERVIEW + "】" + "\n"  + BContentOfOverview + "\n\n" +
    "【" + B_DEADLINE_DATE + "】" + "\n"  + BStartOfdate + "\n\n" ;
  /*
  * メール送信実行
  */
  MailApp.sendEmail(
    TO,
    SUBJECT,
    body
  );
}

具体的な原因

結論部分でも記載しましたが、エラーは Google フォームで回答によって次の設問が分岐する設定をしていた影響で、存在しないデータを取得しようとしていたことに起因 していました。

設問が分岐することを文章で示すと、最初の設問で

  • 「Aに関すること」を選ぶ → Aに関する質問だけが表示される
  • 「Bに関すること」を選ぶ → Bに関する質問だけが表示される
    という設定を Google フォーム側で行っていました。
    つまり、Aに関する相談が投稿された場合、Bに関する質問への回答データは存在しません。
    しかし、現在のコードは、どんな場合でも全ての質問に対する回答が必ず存在することを前提にしています。

具体的に、該当するコードの部分を示します。

// Aを選んだ場合、itemResponses[6]と[7]は存在しない
const BContentOfOverview = itemResponses[6].getResponse(); // ここでエラー
const BStartOfdate = itemResponses[7].getResponse();       // ここでエラー

itemResponses[6] が存在しない(= undefined)ため、undefined.getResponse() を実行しようとしてエラーが発生しているようです。

具体的な修正箇所

フォームそのものを「Aに関すること」「Bに関すること」で分けることもできますが、Googleフォームを複数作成する手間がかかります。
そのため、回答データを1つずつ取り出し、回答が空でなければメールの本文に追加するロジックに変更して対応します。

sendTasksEmail
function sendTasksEmail(e) {
  // フォームの回答を取得
  const itemResponses = e.response.getItemResponses();

  // メール本文と件名を組み立てるための変数
  let body = "";
  let subjectCategory = "未設定"; // 件名用のカテゴリーを保存する変数

  // 回答を一つずつ取り出して処理する
  itemResponses.forEach(function(itemResponse, index) {
    const question = itemResponse.getItem().getTitle(); // 質問のタイトルを取得
    const answer = itemResponse.getResponse();         // 回答内容を取得

    // 回答が空でなければ本文に追加
    if (answer) {
      body += "【" + question + "】\n" + answer + "\n\n";
    }
    
    // 最初の質問(相談の分類)の答えを件名用に保存しておく
    if (index === 0) {
      subjectCategory = answer;
    }
  });

  /* * メール送信先アドレス
   * Backlogの課題登録用メールアドレスを使用します。
   */
  const TO = "《課題登録用メールアドレス》";

  // メール件名
  const SUBJECT = "「" + subjectCategory + "」に関する新規相談";

  /*
   * メール送信実行
   */
  MailApp.sendEmail(
    TO,
    SUBJECT,
    body
  );
}

変更後の方が定数の定義も少なく済み、読みやすいコードになりました。

おわりに

コードベースで確認すればわかりやすいのですが、Googleフォームの画面遷移の印象にとらわれて、分岐しなかった方の設問への回答が空になっていると気が付くのに時間がかかってしまいました。

この記事が、どなたかのトラブルシューティングのお役に立てることを願っています。

Discussion