【0からGASを学ぶ】GASを用いてGoogleフォーム+ドキュメント+メール送信を自動化しよう

# はじめに
本シリーズでは、GASの始め方や便利な使い方、ビジネス活用まで幅広く解説します。シリーズをひと通り読んでいただければ、あなたもきっとGASマスターになれるはずです。

# シリーズの対象者
* そもそもGASってなんだか**わからない**方
* GASを学びたいけど**何から始めればいいか**わからない方
* GASはわかり始めたけど、**もっと活用ができないか**と模索している方
* とにかく**Googleが好き！** という方

# 前回記事
https://qiita.com/gas-suke/items/c97d0dfb56ca051a8c3f

# Googleフォームと連携する
では早速始めていきましょう。【0からGASを学ぶ】シリーズの第12回は「GASを用いてGoogleフォーム+ドキュメント+メール送信の自動化をしよう」です。盛りだくさんのように見えますが、これまで学んできたことの組み合わせです。<a href="https://qiita.com/gas-suke/items/a1783b68fac098c8c3ae" target="_blank">第7回</a>にてスプレッドシート内のデータをもとに、**注文書をドキュメント**でつくり、**PDF変換**し、**メール送信**するということをしました。今回はその**トリガーをGoogleフォームにする**というものです。ひとつひとつのサービスをつなぎ合わせるイメージです、楽しんでいきましょう。イメージはこんな感じ！
![Qiita012.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3575702/5dec4212-2b28-61e8-2dcc-08b34f52921f.png)

:::note info
今回は、私が以前受注しました出席管理システムの**欠席届フォーム（簡略版）** をベースに解説いたします。
:::

## 今回やること
1. Googleフォームのフォーム項目をGASで取得する。
1. Googleドキュメントで作成したテンプレートに**1 で取得した値**を設定する。
1. GoogleドキュメントをPDF変換する。
1. 変換したPDFを添付ファイルとして相手先にメールを送信する。

## やることのイメージ

## 事前準備
### Googleフォームを作成
今回の起動元となるフォームを作成していきましょう。どのようなフォームでもよいのですが欠席届フォームっぽく以下のようなフォームを作成しました。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3575702/592bb577-448c-1f51-19e6-d54e835a4d48.png" width="600">

| 項目名 | タイプ | 必須 |
|:--|:--|:--:|
| 氏名を選択してください。 | プルダウン | 〇 |
| 欠席日を入力してください。 | 日付 | 〇 |
| 連日にまたがって欠席する場合は、欠席期間の終了日を入力してください。 | 日付 |   |
| 届出理由を選択してください。 | ラジオボタン | 〇 |

参考に私が作成したフォームは以下となります。

https://forms.gle/JsYYLBu1e9mN8K2h9

### 欠席届テンプレートの準備
Googleドキュメントで欠席届テンプレートを適当に作成しましょう。どんな様式でも構いませんが上記フォームの値をマッピングさせるため、それを意識して作成してみて下さい。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3575702/be71780f-f7a2-a911-4f7c-def96aaa2368.png" width="600">

:::note info
<a href="https://qiita.com/gas-suke/items/a1783b68fac098c8c3ae" target="_blank">第7回</a>でもご説明しましたが、この枠で囲った**可変文字部**がポイントです。
:::

### PDF出力場所の作成
「今回やること」にも記載しましたが、途中でGoogleドキュメントをPDF変換するため、その出力先を作成しておきましょう。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3575702/f888070f-8f12-2cc5-5347-d6458aa3a115.png" width="300">

### IDの取得
`欠席届テンプレート`と`PDF出力場所`のIDは事前に取得しておきましょう。

### 試しに一度回答
Googleフォームを作成したら、右上の「プレビュー」ボタンを押下して、一度回答してみましょう。のちほど**回答データを取得するためだけ**なので、どのような回答でも構いません。

## プログラム開始
### GASエディタを開く
準備したGoogleフォームから**コンテナバインド型でGASプログラム**を記述していきましょう。Googleフォームからコンテナバインド型のGASを開く場合は、<a href="https://qiita.com/gas-suke/items/cf4a809d54464a43f3ac#gas%E3%82%A8%E3%83%87%E3%82%A3%E3%82%BF%E3%82%92%E9%96%8B%E3%81%8F" target="_blank">こちら</a>を参考にしてください。では、どんどんいきますよ、ついてきてください。

### STEP.1　Googleフォームのフォーム項目をGASで取得する
```javascript:Qiita012.gs
function Qiita012_formSubmit(e) {
  let itemResponses;
  // フォームの回答をイベントオブジェクトまたはフォーム自身から取得する。
  if (e !== undefined) {
    itemResponses = e.response.getItemResponses();
  } else {
    const wFormRes = FormApp.getActiveForm().getResponses();
    itemResponses =  wFormRes[wFormRes.length-1].getItemResponses();
  }
  console.log(itemResponses);
}
```

```:実行結果
18:50:29	お知らせ	実行開始
18:50:31	情報	[ { toString: [Function],
    getItem: [Function],
    setFeedback: [Function],
    setScore: [Function],
    getScore: [Function],
    getFeedback: [Function],
    getResponse: [Function] },
…
  { toString: [Function],
    getItem: [Function],
    setFeedback: [Function],
    setScore: [Function],
    getScore: [Function],
    getFeedback: [Function],
    getResponse: [Function] } ]
18:50:30	お知らせ	実行完了
```
これだとどんな値がとれているかはわかりませんが、ばっちりとオブジェクトは取得できていますので準備万端です。

### STEP.2　Googleドキュメントで作成したテンプレートにSTEP.1で取得した値を設定する。
次に、回答内容をGoogleドキュメントに設定していきましょう。

:::note info
このSTEP以降の
1. Googleドキュメント上の**可変文字部**に値を設定する
1. Googleドキュメントを**PDF変換**する
1. 作成した**PDFをメール送信**する

については<a href="https://qiita.com/gas-suke/items/a1783b68fac098c8c3ae#creategdoc" target="_blank">第7回</a>も併せて参考にしていただけると幸いです。
:::

```javascript:Qiita012.gs
// Qiita012_欠席届テンプレートファイル
const DOC_TEMPLATE = DriveApp.getFileById('1CMhLZpBcQ9Y_v0X1YzFOyWuBsmOzqaTmG6uDceVsDz8');

function Qiita012_formSubmit(e) {
  let itemResponses;
  // フォームの回答をイベントオブジェクトまたはフォーム自身から取得する。
  if (e !== undefined) {
    itemResponses = e.response.getItemResponses();
  } else {
    const wFormRes = FormApp.getActiveForm().getResponses();
    itemResponses =  wFormRes[wFormRes.length-1].getItemResponses();
  }
  
  // 回答をもとに欠席届を作成する 
  let wFileRtn = createGDoc(itemResponses);
}

function createGDoc(itemResponses) {
  // テンプレートファイルをコピーする
  const wCopyFile = DOC_TEMPLATE.makeCopy()
        , wCopyFileId = wCopyFile.getId()
        , wCopyDoc = DocumentApp.openById(wCopyFileId); // コピーしたファイルをGoogleドキュメントとして開く
  let wCopyDocBody = wCopyDoc.getBody()                 // Googleドキュメント内の本文を取得する
      , today = dayjs.dayjs();
  // 本日の日付を設定する
  wCopyDocBody = wCopyDocBody.replaceText(`{{date}}`, today.format('YYYY年MM月DD日'));
  // 以降はGoogleフォームの回答をマッピングする
  itemResponses.forEach(function(itemResponse){
    switch (itemResponse.getItem().getTitle()) {
      case '氏名を選択してください。':
        wCopyDocBody = wCopyDocBody.replaceText(`{{name}}`, itemResponse.getResponse());
        break;

      case '欠席日を入力してください。':
        dateF = dayjs.dayjs(itemResponse.getResponse()).format('YYYY年MM月DD日');
        break;

      case '連日にまたがって欠席する場合は、欠席期間の終了日を入力してください。': // 欠席の場合のみ対応
        if ( itemResponse.getResponse()!='' ) {
          dateT = dayjs.dayjs(itemResponse.getResponse()).format('YYYY年MM月DD日');
        } else {
          dateT = dateF;
        }
        wCopyDocBody = wCopyDocBody.replaceText(`{{applydatefrom}}`, dateF);
        wCopyDocBody = wCopyDocBody.replaceText(`{{applydateto}}`, dateT);
        break;

      case '届出理由を選択してください。':
        wCopyDocBody = wCopyDocBody.replaceText(`{{reason}}`, itemResponse.getResponse());
        break;

      default:
        break;
    }
  });
  wCopyDoc.saveAndClose();
  // ファイル名を変更する
  let fileName = '欠席届_'+today.format('YYYYMMDD');
  wCopyFile.setName(fileName);
  // コピーしたファイルIDとファイル名を返却する（あとでこのIDをもとにPDFに変換するため）
  return [wCopyFileId, fileName];
}
```
これを実行すると、作成した欠席届テンプレートと**同階層に値が設定された欠席届**が作成されます。ゴールはもうすぐそこですね。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3575702/b431ffe0-da3f-033d-3ec4-14db8f039349.png" width="300">
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3575702/38a14601-81c3-edf2-c267-8390991e6123.png" width="600">

ここでのポイントは<a href="https://qiita.com/gas-suke/items/a1783b68fac098c8c3ae#creategdoc" target="_blank">第7回</a>ではスプレッドシートの値をループさせながら可変文字部を変更していきましたが、今回はGoogleフォームの値をもとにするため、以下のようにフォームの項目名を判断しながら、対象となる個所を変更することです。

```javascript
  itemResponses.forEach(function(itemResponse){
    switch (itemResponse.getItem().getTitle()) {
      case '氏名を選択してください。':
        wCopyDocBody = wCopyDocBody.replaceText(`{{name}}`, itemResponse.getResponse());
        break;
//
    }
  });
```

また何気なく使用しましたが、`dayjs.dayjs()`と記載している箇所があります。こちら、GASで使用できる**日付操作ライブラリ**となっており、非常に**強力で柔軟なライブラリ**となっています。日付操作を行う際は、ぜひお使いください。

:::note info
dayjsライブラリを追加する場合は、GASエディタの左メニューよりライブラリ横の「＋」をクリックし、出てきたダイアログのスクリプトIDに以下のIDを入力してください。

**1ShsRhHc8tgPy5wGOzUvgEhOedJUQD53m-gd8lG2MOgs-dXC_aCZn9lFB**

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3575702/f5a807ac-fcaf-d6bd-8ced-11a812f59ab5.png" width="400">

そのまま「追加」をクリックすればGAS上で使用できるようになります。
:::

### STEP.3　GoogleドキュメントをPDF変換する。
こちらは、<a href="https://qiita.com/gas-suke/items/a1783b68fac098c8c3ae#createpdf" target="_blank">第7回</a>とまるっきり一緒ですので、再掲だけしておきます。
```javascript:createPdf
function createPdf(docId, fileName){
  // PDF変換するためのベースURLを作成する
  let wUrl = `https://docs.google.com/document/d/${docId}/export?exportFormat=pdf`;

  // headersにアクセストークンを格納する
  let wOtions = {
    headers: {
      'Authorization': `Bearer ${ScriptApp.getOAuthToken()}`
    }
  }; 
  // PDFを作成する
  let wBlob = UrlFetchApp.fetch(wUrl, wOtions).getBlob().setName(fileName + '.pdf');

  //PDFを指定したフォルダに保存する
  return PDF_OUTDIR.createFile(wBlob).getId();
}
```

### STEP.4 変換したPDFを添付ファイルとして相手先にメールを送信する。
こちらは、<a href="https://qiita.com/gas-suke/items/9fbbbd1563bd83f978ae#%E3%82%88%E3%81%97%E7%AA%81%E7%A0%B4%E3%81%99%E3%82%8B%E3%81%9E" target="_blank">神回</a>で学んだ限界突破方式のメール送信を使いましょう。
```javascript:sendEmailEx
function sendEmailEx(_recipient, _subject, _body, _option) {
  // 引数の内容でメールを下書き保存する
  const mailDraft = GmailApp.createDraft(_recipient, _subject, _body, _option);
  // 下書き保存したメールIDから下書きを取得し、メール送信を依頼する
  GmailApp.getDraft(mailDraft.getId()).send();
}
```

### 結論 こんな感じのプログラムができました
```javascript:Qiita012.gs
// Qiita012_欠席届テンプレートファイル
const DOC_TEMPLATE = DriveApp.getFileById('1CMhLZpBcQ9Y_v0X1YzFOyWuBsmOzqaTmG6uDceVsDz8');

// PDF出力先
const PDF_OUTDIR = DriveApp.getFolderById('1LSyUSpoHP8mMCyPIwgmy7QwKCQ_KQJkT');

function Qiita012_formSubmit(e) {
  let itemResponses;
  // フォームの回答をイベントオブジェクトまたはフォーム自身から取得する。
  if (e !== undefined) {
    itemResponses = e.response.getItemResponses();
  } else {
    const wFormRes = FormApp.getActiveForm().getResponses();
    itemResponses =  wFormRes[wFormRes.length-1].getItemResponses();
  }

  // 回答をもとに欠席届を作成する 
  let wFileRtn = createGDoc(itemResponses);
  // PDF変換してファイルIDを取得する
  let wPdfId = createPdf(wFileRtn[0], wFileRtn[1]);
  // PDF変換したあとは元ファイルを削除する
  DriveApp.getFileById(wFileRtn[0]).setTrashed(true);
  
  // 今回はPDFファイルを添付してメールを送信する
  sendEmailEx(
    '***************@gmail.com'
    , '【自動送信メール】欠席届の送信'
    , `受講生より欠席届が送信されました。`
    , {attachments: DriveApp.getFileById(wPdfId).getBlob()}
  );
}

function createGDoc(itemResponses) {
  // テンプレートファイルをコピーする
  const wCopyFile = DOC_TEMPLATE.makeCopy()
        , wCopyFileId = wCopyFile.getId()
        , wCopyDoc = DocumentApp.openById(wCopyFileId); // コピーしたファイルをGoogleドキュメントとして開く
  let wCopyDocBody = wCopyDoc.getBody()                 // Googleドキュメント内の本文を取得する
      , today = dayjs.dayjs();
  // 本日の日付を設定する
  wCopyDocBody = wCopyDocBody.replaceText(`{{date}}`, today.format('YYYY年MM月DD日'));
  // 以降はGoogleフォームの回答をマッピングする
  itemResponses.forEach(function(itemResponse){
    switch (itemResponse.getItem().getTitle()) {
      case '氏名を選択してください。':
        wCopyDocBody = wCopyDocBody.replaceText(`{{name}}`, itemResponse.getResponse());
        break;

      case '欠席日を入力してください。':
        dateF = dayjs.dayjs(itemResponse.getResponse()).format('YYYY年MM月DD日');
        break;

      case '連日にまたがって欠席する場合は、欠席期間の終了日を入力してください。': // 欠席の場合のみ対応
        if ( itemResponse.getResponse()!='' ) {
          dateT = dayjs.dayjs(itemResponse.getResponse()).format('YYYY年MM月DD日');
        } else {
          dateT = dateF;
        }
        wCopyDocBody = wCopyDocBody.replaceText(`{{applydatefrom}}`, dateF);
        wCopyDocBody = wCopyDocBody.replaceText(`{{applydateto}}`, dateT);
        break;

      case '届出理由を選択してください。':
        wCopyDocBody = wCopyDocBody.replaceText(`{{reason}}`, itemResponse.getResponse());
        break;

      default:
        break;
    }
  });
  wCopyDoc.saveAndClose();
  // ファイル名を変更する
  let fileName = '欠席届_'+today.format('YYYYMMDD');
  wCopyFile.setName(fileName);
  // コピーしたファイルIDとファイル名を返却する（あとでこのIDをもとにPDFに変換するため）
  return [wCopyFileId, fileName];
}

function createPdf(docId, fileName){
  // PDF変換するためのベースURLを作成する
  let wUrl = `https://docs.google.com/document/d/${docId}/export?exportFormat=pdf`;

  // headersにアクセストークンを格納する
  let wOtions = {
    headers: {
      'Authorization': `Bearer ${ScriptApp.getOAuthToken()}`
    }
  }; 
  // PDFを作成する
  let wBlob = UrlFetchApp.fetch(wUrl, wOtions).getBlob().setName(fileName + '.pdf');

  //PDFを指定したフォルダに保存する
  return PDF_OUTDIR.createFile(wBlob).getId();
}

function sendEmailEx(_recipient, _subject, _body, _option) {
  // 引数の内容でメールを下書き保存する
  const mailDraft = GmailApp.createDraft(_recipient, _subject, _body, _option);
  // 下書き保存したメールIDから下書きを取得し、メール送信を依頼する
  GmailApp.getDraft(mailDraft.getId()).send();
}
```

### 
# おわりに
お疲れ様でした。
第12回は「GASを用いてGoogleフォーム+ドキュメント+メール送信を自動化しよう」ということで、Googleフォームを用いた**ドキュメント作成の自動化**を行ってみました。これによって、**実業務でも使えるのでは**と思った方も多いのではないでしょうか。GoogleフォームやGoogleドキュメントなど、単品で考えると「あぁ便利だな」というレベルに過ぎませんが、**組み合わせると「とんでもなく便利！！！」** となります。ぜひ、皆さんも実業務での活用に取り組んでみてください。引き続き、GASを楽しんでいきましょう！！
記事を読んで、「良いな」や「今後に期待できる！」と感じて頂けたら**いいね**や**フォロー**、**コメント**いただけると幸いです。それではまた次回をお楽しみに！

## ブログでより詳しく解説しています！
以下画像をクリックしてブログにアクセス！！
<a href="https://gas-4u.com/gas11/" target="_blank"><img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3575702/80bed013-2869-4b83-a78d-efd3a05cfc55.png" width="600"/></a>