GASとスプレッドシートで作るGmail一括送信ツール

ほとんど同じ内容のメールをたくさんの人に送信したい時があります。

そんなときBCCを使うと同じ内容のメールをたくさんの人に送信できますが、この方法だと以下のような問題が発生します。

1. メール本文に宛先の人の名前を入れたいのに同じ内容になってしまう
2. BCCをたくさん入れると迷惑メールとして判定されやすくなり、メールを読んでもらえない。
3. 間違ってCCで送信してしまう

そこでGoogleスプレッドシートとGASとGoogleドキュメントを使ってGmail一括送信ツールを作ってみました。

:::note warn
警告
必ず自分のメールアドレス宛にテストしてから使用してください。
:::

##### 一括送信シート
以下のようなシートを作成します。
<img src= "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276059/8a2c9251-826a-5884-bf6e-b68d15ac8ae2.png" width="650px">

A〜D列でメール文の構成文を指定
E列で送り先メールアドレスを指定
F2でメールタイトルを指定
G2でメール差出人を指定
H2でメール本文が記載されているドキュメントのURLを指定しています。

一括送信ボタンは挿入⇨図形描画を選択し図形の中からベベルというボタンっぽい図形を選択します。

<img src= "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276059/9e3b0121-08e6-3c5b-5ef2-fe615d6a357a.png" width="450px">

テキストボックスで一括送信と名前を付けて、シート内のちょうどいい場所に配置します。

テスト用にシートのA〜H列にテスト用に文と自分のメールアドレスを追加します。

##### メール本文ドキュメント
Googleドキュメントをシートと同じフォルダの中に作成し以下の文章を貼り付けます。(内容は送信する際に変更してください。)

<details><summary>メール本文例</summary>

```
{A}様 


お世話になっております。 


旬の果物屋{B}ショップです。 
数ある店舗の中から当店をお選びいただき、誠にありがとうございます。 



ご注文いただきました{C}については現在配送のため収穫中でございます。 

{D}はこの時期、大変美味しく熟しております。 


ご注文いただきました商品を無事にお届けできるよう細心の注意を払ってまいります。 

商品到着まで、どうぞよろしくお願いいたします。
```
</details>

作成したドキュメントのURLを先ほどのシートのH2(本文ドキュメント)に貼り付けます。

##### スクリプト

シートを開き、拡張機能からApps Scriptを選択し以下のスクリプトを貼り付けます。

```javascript
function sendEmails() {

    var mySheet = SpreadsheetApp.getActiveSheet(); //シートを取得
    var rowSheet = mySheet.getDataRange().getLastRow(); //シートの使用範囲の最終行を取得

    var docURL = mySheet.getRange("H2").getValue();//メール本文ドキュメントのURLを取得
    var docID = docURL.slice(35,-5);//URLからIDのみを抽出
    var docOpen = DocumentApp.openById(docID); //ドキュメントをIDで取得
    var strDoc = docOpen.getBody().getText(); //ドキュメント内容取得

    var strTitle = mySheet.getRange("F2").getValue();//メールタイトル
    var strMe = mySheet.getRange("G2").getValue(); //差出人

    var strSubject = strTitle;　//表題
    var strFrom = '送信元の自分のメールアドレスを入れる'; //From
    var strSender = strMe; //差出人

    /* ドキュメントの内容とメールアドレスの取得*/
    for (var i = 2; i <= rowSheet; i++) {
        var strBody_A = mySheet.getRange(i, 1).getValue(); //メール文変数A
        var strBody_B = mySheet.getRange(i, 2).getValue(); //メール文変数B
        var strBody_C = mySheet.getRange(i, 3).getValue(); //メール文変数C
        var strBody_D = mySheet.getRange(i, 4).getValue(); //メール文変数D
        var strEmail = mySheet.getRange(i, 5).getValue();//email

        var strBody = strDoc.replace(/{A}/,strBody_A).replace(/{B}/,strBody_B).replace(/{C}/,strBody_C).replace(/{D}/,strBody_D); //ドキュメントの文章を置き換え

        /* メールを送信 */
        GmailApp.sendEmail(
            strEmail, //toアドレス
            strSubject,  //メールタイトル
            strBody,//本文
            {
                from: strFrom,//fromアドレス
                name: strSender//差出人
            }
        );

    }
    var strResult = Browser.msgBox(rowSheet - 1 + "件のメールを送信しました。", Browser.Buttons.OK);
}
```

##### スクリプトの保存とテスト実行

プロジェクト保存ボタンを押します。

シートを確認しテスト用の自分のメールアドレス宛になっているかを確認します。

実行ボタンを押すと`承認が必要です`と表示されるので、以下の記事を参考に承認します。

https://tonari-it.com/gas-script-approval/

自分のメールアドレスにメールが届いていたら成功です。文章などおかしな点がないか確認しシートやドキュメントを調整しましょう。


##### ボタンにスクリプトを割り当てる

シートを開きボタンを右クリックし右上の点々をクリックしスクリプトの割り当てを選択します。
<img src= "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276059/77270b52-35b8-9ac6-1fc9-117136730591.png" width="350px">
sendEmailsと入力し確定を押します。

ボタンを押してスクリプトが実行され、メールが届いたらツールの完成です。


#### スクリプト解説
このスクリプトはシートとドキュメントを取得しドキュメントとシートの内容を組み合わせメールを作成し送信するという処理を連続して行うことができます。

##### シートの取得とドキュメント内容の取得
```javascript
    var mySheet = SpreadsheetApp.getActiveSheet(); //シートを取得
    var rowSheet = mySheet.getDataRange().getLastRow(); //シートの使用範囲の最終行を取得

    var docURL = mySheet.getRange("H2").getValue();//メール本文ドキュメントのURLを取得
    var docID = docURL.slice(35,-5);//URLからIDのみを抽出
    var docOpen = DocumentApp.openById(docID); //ドキュメントをIDで取得
    var strDoc = docOpen.getBody().getText(); //ドキュメント内容取得
```
メール本文ドキュメントのIDはドキュメントURLの `/d/` と `/edit`に挟まれた44文字の文字列です。 
https\://docs.google.com/document/d/`aaahllihalhlkajkeujjjjaiaiue00000klahlybaaad`/edit
スクリプト内にIDを直接打ち込むことでも指定可能ですが、多くの人が使いやすいツールにするため、シートでURLを指定すればIDが抽出できるようにslice関数を使いIDだけを抽出できるようにしました。

##### メールタイトル、差出人、送信元の指定
```javascript
    var strTitle = mySheet.getRange("F2").getValue();//メールタイトル
    var strMe = mySheet.getRange("G2").getValue(); //差出人

    var strSubject = strTitle;//表題
    var strFrom = '送信元の自分のメールアドレスを入れる'; //From
    var strSender = strMe; //差出人
```
メールタイトルと差出人はシートで指定します。
F2とG2を読み込んでいるのでF3やG3に書き込んでも読み込まれません。
メールタイトルは内容によって変化させたい需要がありそうなので、いずれ作成したいと思います。

##### シートで指定した内容を元に、指定された行数分繰り返し処理を実行する

<details><summary>メール文を作成し送信するスクリプト</summary>

```javascript
 /* ドキュメントの内容とメールアドレスの取得*/
    for (var i = 2; i <= rowSheet; i++) {
        var strBody_A = mySheet.getRange(i, 1).getValue(); //メール文変数A
        var strBody_B = mySheet.getRange(i, 2).getValue(); //メール文変数B
        var strBody_C = mySheet.getRange(i, 3).getValue(); //メール文変数C
        var strBody_D = mySheet.getRange(i,　4).getValue(); //メール文変数D
        var strEmail = mySheet.getRange(i, 5).getValue();　//email

        var strBody = strDoc.replace(/{A}/,strBody_A).replace(/{B}/,strBody_B).replace(/{C}/,strBody_C).replace(/{D}/,strBody_D); //ドキュメントの文章を置き換え

        /* メールを送信 */
        GmailApp.sendEmail(
            strEmail, //toアドレス
            strSubject,  //メールタイトル
            strBody,　//本文
            {
                from: strFrom,　//fromアドレス
                name: strSender　//差出人
            }
        );

    }
```

</details>


長いので分けて解説します。

##### シートに入力されている最終行まで繰り返し処理
``` javascript
    for (var i = 2; i <= rowSheet; i++) {
```
シートの最終行をrowSheet関数で取得しているのでその回数分処理を実行します。　
エラーの場合3行目以降に値が入ったセルがあるとエラーになるので、エラーになってしまった場合は3行目以降の列を全選択しBackSpaceを押して綺麗にします。

##### シートに記載されているメール文の構成文を読み込みドキュメントの文章を置き換える

```javascript
 var strBody_A = mySheet.getRange(i, 1).getValue(); //メール文変数A
        var strBody_B = mySheet.getRange(i, 2).getValue(); //メール文変数B
        var strBody_C = mySheet.getRange(i, 3).getValue(); //メール文変数C
        var strBody_D = mySheet.getRange(i, 4).getValue(); //メール文変数D
        var strEmail = mySheet.getRange(i, 5).getValue();//email

        var strBody = strDoc.replace(/{A}/,strBody_A).replace(/{B}/,strBody_B).replace(/{C}/,strBody_C).replace(/{D}/,strBody_D); //ドキュメントの文章を置き換え
```
ここでドキュメントに記載されている{A}といった変数をシートの文章と置き換えていきます。
注意点として{A}が名前で最初に置き換えた場合にもう一度文中に使用したい時に{A}を2回記載しても、2回目の{A}は無効となります。
例

メール本文ドキュメント
```
{A}様 
お世話になっております。 
{A}様はいつも{B}ショップをご贔屓いただき誠にありがとうございます。
```
シート
|A  |B  |
|---|---|
|田中太郎  |りんご  |

↓置き換え処理でこうしたい
```
田中太郎様 
お世話になっております。 
田中太郎様はいつもりんごショップをご贔屓いただき誠にありがとうございます。
```
↓実際はこうなってしまう
```
田中太郎様 
お世話になっております。 
{A}様はいつもりんごショップをご贔屓いただき誠にありがとうございます。
```
なので同じ文でも2回目の置き換えをしたい場合は以下のように記載する必要があります。

```
{A}様 
お世話になっております。 
{B}様はいつも{C}ショップをご贔屓いただき誠にありがとうございます。
```
シート
|A  |B  |C|
|---|---|---|
|田中太郎  |田中太郎  |りんご|

↓成功
```
田中太郎様 
お世話になっております。 
田中太郎様はいつもりんごショップをご贔屓いただき誠にありがとうございます。
```

#### メールを送信する
```javascript

        /* メールを送信 */
        GmailApp.sendEmail(
            strEmail, //toアドレス
            strSubject,  //メールタイトル
            strBody,//本文
            {
                from: strFrom,//fromアドレス
                name: strSender//差出人
            }
        );

```

GmailAppのメソッドのsendEmail関数でメールの送信をしています。
toアドレス
メールタイトル
本文
fromアドレス
差出人を指定し送信し、シートの次の行の処理へ移行します。

#### ポップアップを表示しし一括処理完了

```javascript
var strResult = Browser.msgBox(rowSheet - 1 + "件のメールを送信しました。", Browser.Buttons.OK);
```
何件のメールを送信したかを表示してくれます。
<img src= "https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276059/86b39afd-7ca2-d087-a50a-a5ab7119bcd3.png" width="280px">

動かない場合はご相談ください。

#### 参考
https://tonari-it.com/gas-replace/

https://developers.google.com/apps-script/reference/spreadsheet