Google フォームで受付番号を採番してメールする申込みページを作る

## この記事の目的
イベントの申込み受付を電子化するときには、無料にもかかわらず広告などの出ない Google フォームが便利です。フォームの作成などノーコードでできるので、誰でも簡単に受付フォームが作成できます。
しかし、少し特殊なことをしようとすると Google App Script でのコーディングが必要となります。今回の要件は 

1. Gmail をもたない人でも申込みできるようにしたい。
1. 申込んだ人にその内容をメールで送信したい。
1. そのメールに受付番号を挿入したい。

というものでした。その実装方法を説明します。

## この記事の背景
小学校のおやじの会で夏休みの工作教室を行うのですが、指導員の数に制限があるので、最大40組（家族）の制限をすることになりました。Google フォームで申込みフォームを作るにあたり、どのように制限をかけるかが悩みどころでした。
申込数の上限に達したときに自動的に受付を止めるには、同じ人の重複した申込みを制限する必要があります。Gmail アカウントでのログインを強制することもできますが、両親や祖父母が別々に申込んでしまう可能性もあり、また Gmail を持っていない人への考慮も必要でした。そこで [「この記事の目的」](##この記事の目的)に記載した開発要件を決めました。
あらかじめ「参加できるのは40組まで」と周知した上で、確認メールで受付番号を通知します。締切り後に目視で受付内容を確認して受付の可否を通知するのが良かろうと考えました。受付番号が見えているので、例えば50番とかなら「たぶんハズレだろうな…」と判り無駄な期待をさせることは少なくなります。

## 作成手順

### Google フォームで申込みフォームを作る

[Google フォーム](https://www.google.com/intl/ja_jp/forms/about/)は、Gmail アカウントがあれば誰でも簡単にアンケートや申込みなどのフォームを作ることができるクラウド・アプリケーションです。その使い方の解説はネット上にたくさんあるのでここでは省略します。たとえば [こちらのページ](https://www.g-workspace.jp/googleworkspace-reference/forms/create-form/) が参考になります。

今回は以下のような質問をフォームに配置しました。
| 質問 | 種類 | 
|:--- |:--- |
| 保護者のお名前 | 記述式テキスト(短文回答) |
| 保護者のメールアドレス | 記述式テキスト(短文回答) |
| 参加する子どもは何人ですか | ラジオボタン |
| 作品を選んでください | ラジオボタン |
| (1人め)子どもの学年とクラス | プルダウン |
| (1人め)子どもの名前 | 記述式テキスト(短文回答) |
| (2人め)子どもの学年とクラス | プルダウン |
| (2人め)子どもの名前 | 記述式テキスト(短文回答) |
| (3人め)子どもの学年とクラス | プルダウン |
| (3人め)子どもの名前 | 記述式テキスト(短文回答) |
| 質問やコメントがあれば | 記述式テキスト(長文回答) |

フォームを作成したら「回答」タブで「スプレッドシートにリンク」をクリックしてフォームへの回答を保存するスプレッドシートを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530785/53dd8044-eae9-715b-2a63-7ee44f642727.png)

フォームへの回答は Google フォーム自身に保存されますが、スプレッドシートを関連付けることで回答データがスプレッドシートにも出力されるようになります。

### スプレッドシートでの準備

作成されたスプレッドシートにはあらかじめ「フォームの回答 1」シートが用意されています。ここにはフォームへの回答データが自動的に挿入されるのでいじらないようにします。「受付番号」という名前で新しいシートを追加します。この「受付番号」シートにフォームへの回答データのコピーが、受付番号と合わせて追加される予定です。1行目に1列目のヘッダーとして「受付番号」と入力し、それ以降の列には「タイムスタンプ」、「保護者のお名前」、「保護者のメールアドレス」など「フォームの回答 1」シートのヘッダーをコピーします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530785/c0dbefb7-eadf-9636-8151-e2f71d67495e.png)

### Google Apps Script の記述

受付番号の生成、生成した受付番号のスプレッドシートへの保存、申込み確認メールの送信の機能は Google Apps Script で実装します。

スプレッドシートのメニューから「拡張機能」→「Apps Script」を選択して Apps Script プロジェクトのコード編集ページを開きます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530785/3fb60744-7b61-8302-ce87-6a3c7497c6df.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530785/fb7fde6a-b7de-f968-4877-017e7a9d52e4.png)


#### イベントデータの取得

自動生成された関数の引数に `e` と追記して、以下のような処理を記述します。ここで引数の `e` はフォーム送信時に送られる [イベントオブジェクト](https://developers.google.com/apps-script/guides/triggers/events?hl=ja) です。

```JavaScript
function myFunction(e) {
  // 受信データを表示
  Logger.log("受信データ: " + JSON.stringify(e.namedValues, null, 2));
}
```
「プロジェクトを保存」アイコンをクリックして保存します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530785/44e8349a-9324-9604-e5df-4554cf80bdcb.png)

左側のメニューから「トリガー」ページを開き「+ トリガーの追加」をクリックしてトリガーを作成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530785/52e85814-4e9a-b5c9-dacd-f86e0d35cfb9.png)

トリガーの設定の「イベントの種類を選択」項目で `フォームの送信時` を選択します。開発中の段階では「エラー通知設定」は `今すぐ通知を受け取る` にしておくと良いかもしれません。「保存」ボタンをクリックして保存します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530785/1a01512f-df9b-8a86-4231-d09a58e76e4b.png)

「アカウントを選択してください」ダイアログが出たときは、使用している Gmail アカウントを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530785/8cc8d9fd-6a07-f34d-747d-f37eb9ba7326.png)

「Google はこのアプリを検証していません」と出たら「高度（Advanced）」リンクをクリックしてから「無題のプロジェクトへ（危険）」をクリックします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530785/3c83ef51-18fa-d784-6628-78004c65ae48.png)

「許可する」をクリックしてこのプロジェクトのへのアクセスを許可します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530785/12226a4a-f3a2-6b7e-9fd8-6f13b956352a.png)

トリガーが作成されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530785/a2f1c844-4440-a87d-6a42-5d634de9e2c2.png)

フォーム設計画面の右上の「プレビュー」アイコンをクリックしてフォームを開き、適当なデータを入力してフォームを送信します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530785/2b1f2692-a49a-ccc0-fbca-bdc71ffdbd55.png)

Apps Script 画面の「実行」ページを開くと、いま送信されたフォームのログが記録され、送信データが出力がされていることが確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2530785/5207fd1f-2949-8f51-c5e6-1bf1c16f400f.png)

#### 必要なデータの取得

はじめに必要なデータをイベントオブジェクトから取得します。

```JavaScript
  // 受信データを取得
  const values = e.values;
  const datetime = values[0];
  const parent = values[1];
  const email = values[2];
  const count = values[3];
  const product = values[4];
  const class_1 = values[5];
  const name_1 = values[6];
  const class_2 = values[7];
  const name_2 = values[8];
  const class_3 = values[9];
  const name_3 = values[10];
  const comment = values[11];
```

#### 受付番号の取得と保存

受付番号は、フォームで送信された回答の番号を使います。その実装は以下のようになり 回答の番号である `index` が受付番号になります。

```JavaScript
  // 実行の対象となった回答が保存されるシートの Sheet クラスを取得
  const sheet = SpreadsheetApp.getActiveSheet();

  // Sheet クラスの getFormUrl() メソッドでフォームの URL を取得し、
  // フォームを扱うための Form  クラスを取得
  const form = FormApp.openByUrl(sheet.getFormUrl());

  // すべての回答を配列に取得し、回答数を受付番号として保存
  const res = form.getResponses();
  const index = res.length;
  Logger.log("index = " + index);
```

この受付番号を、同じスプレッドシートの `受付番号` シートに保存します。

```JavaScript
  // 同じスプレッドシートの「受付番号」シートを取得
  const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  const indexSheet = spreadsheet.getSheetByName("受付番号");

  // 受付番号と他の送信データを「受付番号」シートに保存
  const newRecord = [ index, datetime, parent, email, count, product, 
                      class_1, name_1, class_2. name_2, class_3, name_3,
                      comment ];
  indexSheet.appendRow(newRecord);
```

#### 確認メールの送信

Google フォームでは「設定」タブで回答のコピーを回答者に送るように設定することもできます。しかし、今回はメールの内容をカスタマイズして、受付番号を含めたいのでこの機能は使いません。
Google Apps Script では `GmailApp` クラスの `sendEmail()` メソッドで以下のように簡単にメール送信をすることができます。

```JavaScript
  // 受付確認メールを送信
  const title =  `【${parent}様】親と子の工作教室への申し込みをありがとうございました。` ;
  const body = `${parent}様、

親と子の工作教室への申し込みをありがとうございました。
以下の内容で受け付けました。

受付番号：${index}
保護者のお名前：${parent}
メールアドレス：${email}
参加する子どもの人数：${count}
作品：${product}
参加する子ども：
  ${class_1} ${name_1}
  ${class_2} ${name_2}
  ${class_3} ${name_3}
ご質問やコメント：
${comment}

講師の人数が少ないことから、参加者を40組程度に制限します。申込み数がその数を超えたときは有効な申込みの先着順で参加者を決めます。
参加できるかの最終結果は別途メールでお知らせします。

ご質問などございましたら xxxxx@gmail.com にメールでお知らせください

小学校おやじの会
`;
 
  GmailApp.sendEmail(email, title, body);
```

### コード全体

最後に、作成したコードの全文を掲載します。

```JavaScript
function myFunction(e) {
  // 受信データを表示
  Logger.log("受信データ: " + JSON.stringify(e.namedValues, null, 2));

  // 受信データを取得
  const values = e.values;
  const datetime = values[0];
  const parent = values[1];
  const email = values[2];
  const count = values[3];
  const product = values[4];
  const class_1 = values[5];
  const name_1 = values[6];
  const class_2 = values[7];
  const name_2 = values[8];
  const class_3 = values[9];
  const name_3 = values[10];
  const comment = values[11];

  // 実行の対象となった回答が保存されるシートのクラス(Class Sheet)を取得
  const sheet = SpreadsheetApp.getActiveSheet();

  // Sheet クラスの getFormUrl() メソッドでフォームの URL を取得し、フォームを扱うための Form  クラスを取得
  const form = FormApp.openByUrl(sheet.getFormUrl());

  // すべての回答を配列に取得し、回答数を受付番号として保存
  const res = form.getResponses();
  const index = res.length;
  Logger.log("index = " + index);

  // 同じスプレッドシートの「受付番号」シートを取得
  const spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  const indexSheet = spreadsheet.getSheetByName("受付番号");

  // 受付番号と他の送信データを「受付番号」シートに保存
  const newRecord = [ index, datetime, parent, email, count, product, 
                      class_1, name_1, class_2. name_2, class_3, name_3,
                      comment ];
  indexSheet.appendRow(newRecord);

  // 受付確認メールを送信
  const title =  `【${parent}様】親と子の工作教室への申し込みをありがとうございました。` ;
  const body = `${parent}様、

親と子の工作教室への申し込みをありがとうございました。
以下の内容で受け付けました。

受付番号：${index}
保護者のお名前：${parent}
メールアドレス：${email}
参加する子どもの人数：${count}
作品：${product}
参加する子ども：
  ${class_1} ${name_1}
  ${class_2} ${name_2}
  ${class_3} ${name_3}
ご質問やコメント：
${comment}

講師の人数が少ないことから、参加者を40組程度に制限します。申込み数がその数を超えたときは有効な申込みの先着順で参加者を決めます。
参加できるかの最終結果は別途メールでお知らせします。

ご質問などございましたら xxxxx@gmail.com にメールでお知らせください

小学校おやじの会
`;
 
  GmailApp.sendEmail(email, title, body);
}
```

## 参考文献

この記事を書くために以下のページを参考にしました。

- [Googleフォームの使い方と自動返信メールの設定方法](https://ferret-one.com/blog/google-form)
- [GASでGoogleフォームの値を取得する（トリガー編）](https://walking-elephant.blogspot.com/2021/01/gas.namedvalues.html)
- [【GAS】Googleフォームの回答データに連番をふる](https://qiita.com/ta9star/items/5522177c2df07e6df477)
- [【GAS】appendRowメソッドの使い方｜スプレッドシートの最終行に書き込む](https://tetsuooo.net/gas/2093/)