GASで簡易的な自動送信メルマガを作る

## 目的
指定した時間に自動的に送信される簡易的なメールマガジンをGASで実装します。
エンジニア以外のメンバーに運用してもらうため、スプレッドシート上に内容を記入してもらう形にしています。

## 概要
スプレッドシート上に以下の項目を記入しておくと、指定した内容でメールが送信されます。

* 送信日/時間
* 宛先(to,cc,bcc)
* タイトル
* 本文（定型文）
* 本文（都度変更文）

このような形です。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/9417fe36-9030-53d5-d2fd-f0c35b1c937e.png" width=90%>

今回の例では宛先に英語圏と中国語圏を含み、本文（都度変更文）としてそれぞれの言語のメッセージボックスを用意しておき、必要に応じて挨拶を記入してもらいます。

## 事前準備

### スプレッドシートに必要な入力項目を用意する
概要で記した通りです。日付部分や宛先部分は条件付き書式や入力制限を使ってバリデーションします。

### moment.js
日付を扱うためのライブラリです。文字列からパースしたり、月末月初を求める演算ができたり、任意のフォーマットで出力できたり、と様々な機能があります。指定した時間にメールを送る処理を調べていて知り、使ってみました。

### ライブラリ追加
デフォルトだと利用できないので、ライブラリの追加を行います。リソースタブからライブラリを選択します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/347966ac-e4dd-87e1-be47-7e50dd83938c.png" width=30%>

「Add a library」部分に`MHMchiX6c1bwSqGM1PZiW_PxhMjh3Sh48`を指定して「追加」を選択します。
するとMomentが表示されますので、最新バージョンを指定して追加します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/e2e2db29-e5e7-6468-b03f-152c81c548ed.png" width=70%>

これでmoment.jsを使えるようになりました。

## 実装

事前準備で作成したスプレッドシートの`ツール`タブから`スクリプトエディタ`を選び、以下の通り貼り付けます。
`sh.getRange`で取得している値はスプレッドシート上の項目の場所を参照しているので、ご利用の際は用途に応じて適当に変更してご利用ください。

```js:sendMail.gs
function sendMail() {
  var SS_ID = "スプレッドシートID";
  var TARGET_SHEET_MAIL = "シート名";
  
  var sh = SpreadsheetApp.openById(SS_ID).getSheetByName(TARGET_SHEET_MAIL);
  var range = sh.getRange('B:B').getValues(); 
  var lastRow = range.filter(String).length;
  
  var toAdr = [];
  var ccAdr = [];
  var bccAdr = [];
  var title = sh.getRange("L11").getValue();
  var body = sh.getRange("L12").getValue();
  var EnglishGreeting = sh.getRange("L3").getValue();
  var ChineseGreeting = sh.getRange("L4").getValue();
  var deliveryDateTime = "";
  var moment = Moment.moment();
  
  //メール本文の置き換え
  body = body.replace("ChineseGreeting",ChineseGreeting); 
  body = body.replace("EnglishGreeting",EnglishGreeting); 
  
  //当月確認
  for(i=1; i<=lastRow; i++){
    var deliveryValue = sh.getRange(i + 3,2).getValue(); 
    var Month = new Date().getMonth() + 1 + "月";
    if (moment.isSame(deliveryValue[i],'hour')) {
      body = body.replace("Month",Month); //本文中に記載した月の書き換え
   }
  }
  
  //メール宛先振り分け
  for(i=1; i<=lastRow; i++){
    var sendToValue = sh.getRange(i + 3,7).getValue()
    if (sendToValue == "to") {
       toAdr.push(sh.getRange(i + 3,9).getValue()); 
       body = body.replace("sendTo",(sh.getRange(i + 3,8).getValue())); 
    }
    if (sendToValue == "cc") ccAdr.push(sh.getRange(i + 3,9).getValue()); 
    if (sendToValue == "bcc") bccAdr.push(sh.getRange(i + 3,9).getValue()); 
  }
  
  //メール送付時間になったら送付する
  if (moment.isSame(deliveryDateTime,'hour')) {
    MailApp.sendEmail({to:toAdr[0], cc:ccAdr[0], bcc:bccAdr[0], subject:title, body:body});
    console.log("\nmailto: " + toAdr + "\n" + ccAdr + "\n" + bccAdr + "\n" +
             "title: " + title + "\n" +
             "body: " + body + "\n"
               );
   }
}
```

## 自動送信のための設定

[Apps Script ダッシュボード](https://script.google.com/)からマイトリガーで以下の通り設定します。
これにより、1時間に一度スクリプトが起動し、スプレッドシートで指定した時間と重なった時に指定した宛先にメールを送信します。
重ならない時は空振りします。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/f8cb0700-ceba-9db6-2c06-ec91481bb100.png" width=60%>

## 結果
1時間ごとにスクリプトが実行されます。
なお、GASでのメールは[1日の送信制限件数](https://support.google.com/a/answer/166852?hl=ja)がありますので,
特に宛先が多い場合は気をつけてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/1e01e92e-42c0-d5be-6f9b-40c0ff18dd3a.png)

指定した時間になると自動的にメール送信されます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/dfb5e577-69f8-71f9-3b02-2adaf790e678.png" width=50%>