【GAS】googleフォームの内容をメールで送る方法比較【フォームからとスプレッドシートから】

めも

皆さんはGoogleフォームから送られた内容(回答)をメールで送信(返信)するGAS(Google Apps Script)のサンプルを探していて、違和感を感じたことはないですか?

コピペして動かそうとしてもうまく動かない、とか。

なんか使っている関数が違うぞ?とか。

実はフォームの内容をメールで送る場合、「フォーム側で処理する方法」と「スプレッドシート側で処理する方法」の2種類が存在します。

私は最初それに気が付かづ混乱したので、この記事で整理しておこうと思います。

ちなみに、Googleフォーム側とスプレッドシート側、どちらで処理する方が良いの?と思うかもしれませんが、個人的にはスプレッドシート側での処理をお勧めします。

スプレッドシート側の処理方法だけを知りたい方は、前半は飛ばして「GoogleスプレッドシートのGASでメールを送る方法」から読んで頂いても大丈夫です。

なおこの記事は、前提としてフォームから送信された回答はスプレッドシートに書き込まれる設定がされているものとします。

フォームとスプレッドシートの関連付けは他のサイトを参考にして下さい。

テスト用フォームのデザイン

テスト用フォームはこんな感じ

フォーム側とスプレッドシート側で何が違うのか?

Googleフォーム側とスプレッドシート側では、操作や仕様に以下のような違いがあります。

  • スクリプトエディタを開く場所が違う
  • トリガの設定項目が違う
  • スクリプトに渡されるイベントオブジェクトが違う
  • イベントオブジェクトからのデータの取り出し方が違う

それでは個別に見ていきましょう。

Googleフォーム側のGASでメールを送る方法

スクリプトエディタの立ち上げ方法

フォーム側でスクリプトを動かす場合は、フォームエディタ画面の右上(三点リーダ)から「スクリプトエディタ」を起動します。

Googleフォーム用メール送信サンプルスクリプト

フォームの回答送信時にメールを送るフォーム側で動くサンプルスクリプトです。

function onFormSubmit(e) {
  var recipient = '※送信先メールアドレスを記述※';
  var subject = 'お問い合わせがありました';

  //フォームの回答データ部分を取得
  var itemResponses = e.response.getItemResponses();

  //メール本文生成
  var body = '以下の内容でフォームが送信されました。\n\n';
  body += '【メールアドレス】\n' + e.response.getRespondentEmail() + '\n\n';
  reTimeStmp = e.response.getTimestamp();
  body += '【タイムスタンプ】\n' + Utilities.formatDate(reTimeStmp, "Asia/Tokyo", "yyyy/MM/dd HH:mm:ss") + '\n\n';
  for (var i = 0; i < itemResponses.length; i++) {
    var itemResponse = itemResponses[i];
    var question = itemResponse.getItem().getTitle();
    var answer = itemResponse.getResponse();
    body += '【' + question + '】\n' + answer + '\n\n';
  }
  var ssId = FormApp.getActiveForm().getDestinationId();
  body += '【スプレッドシートURL】\n' + SpreadsheetApp.openById(ssId).getUrl() + '\n\n';

  MailApp.sendEmail(recipient, subject, body);
}
スクリプトの実行方法
  1. フォーム側のスクリプトエディタにサンプルスクリプトをコピペする。
  2. 送信先メールアドレスを設定する。
  3. スクリプトを保存する。
  4. 一度「実行」をして、メール送信の承認を行う。
  5. トリガーを設定する。
  6. フォームを記入し「送信」ボタンを押す。

フォーム側のトリガの設定

フォーム側のスクリプトエディタからトリガの設定をします。

イベントソースが「フォームから」になります。

フォーム側のスクリプトが呼び出されるタイミング

Googleフォームで送信ボタンが押された後に実行されます。

ただし、スプレッドシート側のGASよりも早く実行されるとは限りません

何回か試したところ、フォーム側とスプレッドシート側のどちらが先に実行されるかは完全にランダムです。

順番としては、

  1. フォームの回答を送信する
  2. スプレッドシートに回答が書きこまれる
  3. フォーム側・スプレッドシート側のGASが非同期で呼ばれる

のようです。

注意

これらの順番はちゃんと仕様を確認したものではありません。
数回スクリプトを実行した結果から想定したものです。
スクリプトを組む際は、期待通りの順番で動かない事も想定して組むことをお勧めします。

フォーム側のスクリプトに渡されるイベントオブジェクトの中身

ちまたにあふれるサンプルプログラムでは、フォーム側のサンプルもスプレッドシート側のサンプルも、同じ「e」という引数名が使われています。

が、実はこのeというオブジェクト、フォーム側とスプレッドシート側で中身が全然違います

このせいで、スプレッドシート用のGASをフォーム側で動かしても動かないという状況が発生します。

紛らわしいわ!!

フォーム側のイベントオブジェクトからのデータの取り出し方

ソースの解説(ソース、解説の順で記述します)

function onFormSubmit(e) {
  var recipient = '※送信先メールアドレスを記述※';
  var subject = 'お問い合わせがありました';

送信先メールアドレスや件名を設定しています。(スプレッドシート側と共通)

  //フォームの回答データ部分を取得
  var itemResponses = e.response.getItemResponses();

フォーム側に渡される回答データは、イベントオブジェクトの中の、フォームレスポンスオブジェクトの中に、アイテムレスポンスオブジェクトの配列として格納されています。

  //メール本文生成
  var body = '以下の内容でフォームが送信されました。\n\n';
  body += '【メールアドレス】\n' + e.response.getRespondentEmail() + '\n\n';
  reTimeStmp = e.response.getTimestamp();
  body += '【タイムスタンプ】\n' + Utilities.formatDate(reTimeStmp, "Asia/Tokyo", "yyyy/MM/dd HH:mm:ss") + '\n\n';
  for (var i = 0; i < itemResponses.length; i++) {
    var itemResponse = itemResponses[i];
    var question = itemResponse.getItem().getTitle();
    var answer = itemResponse.getResponse();
    body += '【' + question + '】\n' + answer + '\n\n';
  }
  var ssId = FormApp.getActiveForm().getDestinationId();
  body += '【スプレッドシートURL】\n' + SpreadsheetApp.openById(ssId).getUrl() + '\n\n';

デフォルトでメールアドレスを収集する場合、収集したメールアドレスはレスポンスオブジェクトのメソッドで取得します。

タイムスタンプもレスポンスオブジェクトのメソッドで取得します。

回答のリストは、アイテムレスポンスオブジェクトの配列から一つずつ取り出して、タイトルと回答をメール本文に追記しています。

最後にフォームと連携しているスプレッドシートのURLを取得してメール本文に追記しています。

  MailApp.sendEmail(recipient, subject, body);
}

メールを送っています。(スプレッドシート側と共通)

実際に送られるメールの内容

件名:お問い合わせがありました

以下の内容でフォームが送信されました。

【メールアドレス】
****@******.***

【タイムスタンプ】
2022/02/28 23:56:19

【質問】

オプション 1

【一行】
てすとだよ

【長文】
てすとだってば

【スプレッドシートURL】
https://docs.google.com/spreadsheets/d/****************************/edit

GoogleスプレッドシートのGASでメールを送る方法

スクリプトエディタの立ち上げ方法

スプレッドシート側でスクリプトを動かす場合は、機能拡張メニューの「Apps Script」を起動します。

Googleスプレッドシート用メール送信サンプルスクリプト

フォームの回答送信時にメールを送るスプレッドシート側で動くサンプルスクリプトです。

function onFormSubmit(e) {
  var recipient = '※送信先メールアドレスを記述※';
  var subject = 'お問い合わせがありました@seet';

  //スプレッドシートの項目名のリスト
  var items = ['メールアドレス', 'タイムスタンプ', '質問', '一行', '長文'];

  //メール本文生成
  var body = '以下の内容でフォームが送信されました。\n\n';
  for (var i = 0, len = items.length, name; i < len; i++) {
    name = items[i];
    body += '【' + name + '】\n' + e.namedValues[name] + '\n\n';
  }
  body += '【スプレッドシートURL】\n' + e.source.getUrl() + '\n\n';

  //メール送信
  MailApp.sendEmail(recipient, subject, body);
}
スクリプトの実行方法
  1. Googleフォームとスプレッドシートを連携させる。
  2. スプレッドシート側のスクリプトエディタにサンプルスクリプトをコピペする。
  3. 送信先メールアドレスを設定する。
  4. スクリプトを保存する。
  5. 一度「実行」をして、メール送信の承認を行う。
  6. トリガーを設定する。
  7. フォームを記入し「送信」ボタンを押す。

スプレッドシート側のトリガの設定

スプレッドシート側のスクリプトエディタからトリガの設定を行います。

イベントのソースが「スプレッドシートから」になります。

スプレッドシート側のスクリプトが呼び出されるタイミング

スプレッドシートにデータが書きこまれた後に実行されます。

ただし、フォーム側のGASの後で実行されるとは限りません

何回か試したところ、フォーム側とスプレッドシート側のどちらが先に実行されるかは完全にランダムです。

順番としては、

  1. フォームの回答を送信する
  2. スプレッドシートに回答が書きこまれる
  3. フォーム側・スプレッドシート側のGASが非同期で呼ばれる

のようです。

注意

これらの順番はちゃんと仕様を確認したものではありません。
数回スクリプトを実行した結果から想定したものです。
スクリプトを組む際は、期待通りの順番で動かない事も想定して組むことをお勧めします。

スプレッドシート側のスクリプトに渡されるイベントオブジェクトの中身

フォーム側の説明でも書きましたが、フォーム側とスプレッドシート側では、引数「e」の中身が全然違います

このせいで、フォーム用のGASをスプレッドシートで動かしても動かないという状況が発生します。

スプレッドシート側のイベントオブジェクトからのデータの取り出し方

ソースの解説(ソース、解説の順で記述します)

function onFormSubmit(e) {
  var recipient = '※送信先メールアドレスを記述※';
  var subject = 'お問い合わせがありました';

送信先メールアドレスや件名を設定しています。(フォーム側と共通)

  //スプレッドシートの項目名のリスト
  var items = ['メールアドレス', 'タイムスタンプ', '質問', '一行', '長文'];

スプレッドシート側に渡されるイベントオブジェクトでは、回答データは連想配列で渡され、各項目の順番が前後してしまいます。

正しい順番で取得するために、項目名の配列を作成します。

項目名は回答が書きこまれるシートの項目名と同じものを指定します。

  //メール本文生成
  var body = '以下の内容でフォームが送信されました。\n\n';
  for (var i = 0, len = items.length, name; i < len; i++) {
    name = items[i];
    body += '【' + name + '】\n' + e.namedValues[name] + '\n\n';
  }
  body += '【スプレッドシートURL】\n' + e.source.getUrl() + '\n\n';

回答は連想配列で渡されるため、上で作成した項目名の配列を元にforループで情報を取得しています。

フォーム側のスクリプトと比べるととてもシンプルです。

最後にイベントオブジェクト内のソースオブジェクトのメソッドからスプレッドシートのURLを取得しています。

  MailApp.sendEmail(recipient, subject, body);
}

メールを送っています。(フォーム側と共通)

実際に送られるメールの内容

件名:お問い合わせがありました

以下の内容でフォームが送信されました。

【メールアドレス】
****@******.***

【タイムスタンプ】
2022/02/28 23:56:20

【質問】
オプション 1

【一行】
てすとだよ

【長文】
てすとだってば

【スプレッドシートURL】
https://docs.google.com/spreadsheets/d/****************************/edit

【余談】メールを送る関数(メソッド)について

GASでメールを送るサンプルを見ていると、送る関数が違ったり引数が違ったりするものがあります。
このあたりも混乱の原因になるので、ここで整理しておきます。

よく使われる関数は2種類

MailAppクラスのsendEmail()と GmailAppクラスのsendEmail()です。

MailAppクラス

MailAppクラスはメール送信に特化したクラスで、機能がシンプルです。

GmailAppクラス

GmailAppクラスはGmail全般をコントロールできる多機能なクラスです。

メール送信にはMailAppクラスがお勧め

一見多機能の方が便利なのではと思われるかもしれませんが、GmailAppクラスは利用する際に送信以外の機能の承認も必要となるので、セキュリティー上は好ましくありません。(使わない機能の承認はなるべく行わない)

よって、シンプルで使いやすいMailAppクラスがお勧めです。

MailAppクラスのsendEmail()の使い方

MailAppクラスを使っているサンプルでも、よく見ると使い方が違うものがあります。

渡している引数が違います。

個人的には、通常のメール送信からイメージしやすい「送り先アドレス」「タイトル」「本文」を引数とて指定できるタイプが良いと思います。

MailApp.sendEmail(recipient, subject, body);

まとめ

色々グダグダ書きましたが、まとめると、

  • フォーム側で作る場合とスプレッドシート側で作る場合と作り方が違うよ
  • トリガで動くプログラムは実行される順序を期待しちゃだめだよ
  • 個人的にはスプレッドシート側で作るのがお勧めだよ
  • メールを送る部分はMailAppクラスがお勧めだよ
  • まあ、最終的に目的が果たせればどっちでも良いんだけどね

こんな感じです。

もしこの記事が参考になったら、下の「参考になった」ボタンを押してもらえると嬉しいです。

では良いGASライフを~

めも

Posted by ikaken