Google Apps Scriptでメール配信

# はじめに

「自分宛に送信されたんだと感じさせた方が、返信率・既読率・イベント参加率が高い」という妄想のもと、以下のようなことを実現しようとしていました。Bcc使っても誰も見てくれないよなと。

+ SpreadSheetに載せた連絡先をもとに、一人一人にメールを配信
+ Documentでメールのテンプレートを作成
+ 宛名の形式は「〇〇大学 〇〇学部 〇〇様」

# 前提

以下のようなファイルを予め用意します。

### SpreadSheet(Contact.sheet)

こんなイメージ

| 名前 | 大学 | 学部 | メールアドレス |
|:-:|:-:|:-:|:-:|
| 田中太郎 | 〇〇大学 | ××学部 | ~~@△△.com |

### Document(MailTemplate.document)

```
${university} ${faculty}
${name} 様

こんにちは。...

よろしくお願いします。
```

# 実装

## プログラムの全体像

こんな感じで作れば大丈夫ですね。

1. メールのテンプレートを取得
2. 連絡先を取得
3. 連絡先ごとに
    1. メールのテンプレートのプレースホルダを実データに差し替え
    2. 作成したメール本文と取得した連絡先をもとにメールを送信

## プログラム

### メールのテンプレートを取得

Document内の文章を取得する関数です。

```js
/**
 * Documentからメールのテンプレートを取得する関数.
 * 戻り値の型 String
 */
function getTemplateBody(){
  const documentId = 'yourTemplateDocumentId';
  const document = DocumentApp.openById(documentId);
  
  const body = document.getBody().getText();
  return body;
}
```

画面上の操作と同様に、Documentを開いて、テキストデータを取得しています。

個々のオブジェクトとメソッドについては[公式ドキュメント](https://developers.google.com/apps-script/reference/document/)をご覧ください。

### 連絡先を取得

SpreadSheet内に書いてある連絡先を取得する関数です。
`Range`オブジェクトから`getValues()`メソッドでデータを取得すると2次元配列でデータを取得できます。

```js
/**
 * SpreadSheetから連絡先を取得する関数.
 * 戻り値の型 配列
 */
function getContacts() {  
  const spreadsheetId = 'yourSpreadSheetId';
  const spreadsheet = SpreadsheetApp.openById(spreadsheetId);
  
  const sheetName= 'シート1';
  const sheet = spreadsheet.getSheetByName(sheetName);
    
  const nameColumnIndex = 0;
  const universityColumnIndex = 1;
  const facultyColumnIndex = 2;
  const mailAddressColumnIndex = 3;
  const numColumns = 4;
  const data = sheet.getRange(2, 1, sheet.getLastRow() - 1, numColumns).getValues();
    
  var contacts = data.map(d => ({
      name: d[nameColumnIndex], 
      university: d[universityColumnIndex], 
      faculty: d[facultyColumnIndex], 
      mailAddress: d[mailAddressColumnIndex]
  }))  
  return contacts;
}
```

今回は1行目がヘッダなので、あえて2行目からデータを抜き取っていますが、全セルのデータを抜き取るのであれば`getDataRange()`メソッドで範囲を指定すると良さそうです。

### 参考サイト

- [GASでSpreadsheetを操作する自分的ベストプラクティス](https://qiita.com/ryan5500/items/e72eb205fbe006c2eb6f)
- 個々のオブジェクトとメソッドについては[公式ドキュメント](https://developers.google.com/apps-script/reference/spreadsheet/)

## メインの処理(本文作成・メール送信)

ここまでで作成した関数を呼び出して、メールのテンプレートと連絡先を取得しています。
そのあと、連絡先1件ずつにつき、テンプレートからメール本文の作成、メールの送信を行っています。

```js
function myFunction() {
  const templateBody = getTemplateBody();
  const contacts = getContacts();
  
  contacts.forEach(contact => {
    const body = templateBody
        .replace('${name}', contact.name)
        .replace('${university}', contact.university)
        .replace('${faculty}', contact.faculty);
    GmailApp.sendEmail(contact.mailAddress, "subject", body, {
      name: "送信者名"
    })
  })
}
```

Gmailの操作方法については[公式ドキュメント](https://developers.google.com/apps-script/reference/gmail/)をご覧ください。

## 補足
様々な種類のメールを自動配信しようというユースケースの場合、件名も固定値ではなく動的にしなくてはならないと思います。テンプレートファイルの名前をメールの件名にすると、わかりやすい＆プログラムで件名を簡単に指定できるのでいい感じになります。

# 感想

別記事で[GoogleCalendarを操作する話](https://qiita.com/DaisukeKURATA/items/6fc800e9c10faa2f6367)をしましたが、今回の記事のように複数のGoogleアプリケーションをまたいだ操作もすることができます。実行環境を整えずにプログラムを書くことができるので非ソフトウェアエンジニアの人にもおすすめです！大学生の時は私プログラミングの勉強とかしていなかったので！

# 参考サイト

- [公式ドキュメント](https://developers.google.com/apps-script/reference/)
- [Qiita イマドキのJavaScriptの書き方2018](https://qiita.com/shibukawa/items/19ab5c381bbb2e09d0d9)
- [Qiita GASでSpreadsheetを操作する自分的ベストプラクティス](https://qiita.com/ryan5500/items/e72eb205fbe006c2eb6f)
パフォーマンスの出る書き方という観点で記事がかいてあるので、大量のデータを扱う方は見るとよいかもしれません。
- [Qiita GASでのメール送信についてまとめてみる](https://qiita.com/mistolteen/items/404c10657b1b27007a3c)
日本語の記事なのでありがたや。