GmailでMail Delivery Subsystemから来たメアドをgasで取得する【初心者向け】

## はじまり

いつもの仕事で、本当に無駄だなぁと思う仕事の1つにセミナーのアンケートを手書きで書いてもらう作業があるんです。
その紙のアンケートを回収して、メアドを打ち込んで「今日はありがとうございました」ってメール送ってるんですよ。

で、だいたいの人が字が汚いとか数字の`0`かアルファベットの`o`か分からないとかで、`Mail Delivery Subsystem`からメール来ちゃうんです。

いつもこの失敗したメールを見つけたら、その人のメアドから電話番号を引っ張ってきて、電話してメアド聞くという超無駄な作業してます。
こういう無駄な仕事するたびに、「こんなの絶対人間のやる仕事じゃないよな」と思いならが惰性で人生を過ごしてきちゃってました。

で、最近Google Apps Scriptという神ツールを見つけて、これめっちゃ勉強して、まずは`Mail Delivery Subsystem`からメールきたメアドを取得するスクリプト書いてみました。

## 最終型

もちろん取得するだけだと意味ないので、最終型として以下のようなものを作ろうと思ってます。

* 失敗してたメアドをスプレッドシートに書いてく (自動で書かれてれば、マスターのシートとvlookup組んでおけば電話番号もスグ分かる)
* 毎日xx時間おきにこのスクリプトを実行 (トリガー設定)
* ただし、すでに取得したメアドはスルーする
* UI上からポチってしたら、初回の実行出来て、トリガー設定できる

## 今日のゴール

gasを使って、`Mail Delivery Subsystem`から来た送信失敗したメアドと日時を取得する。
頑張るぞい。

## まずはスクリプトを作ってく

### 自分のGoogleドライブから、まずは「Googleスプレッドシート」を新しく作ります。

![スクリーンショット 2019-06-11 20.01.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434023/f5f668a9-3353-2c82-fd34-88570f76309d.png)

### スクリプトエディタを開く

「ツール」>「スクリプトエディタ」でスクリプトを開きます。

![スクリーンショット 2019-06-11 20.02.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434023/b06d4ae5-abb5-b1c5-4277-cac5fd4a1ab7.png)

## とりあえずコードをガリガリ書いてく

↓ 今回の完成形です。

```js

// Mail Delivery Subsystem から来たメールを検索
var searchString = "from:'Mail Delivery Subsystem'";

function mainFunction() {
  var myThreads = GmailApp.search(searchString, 0, 1); // まずは直近の1件を取得
  
  // メールが見つからなければ終わる
  if (myThreads.length === 0) {
    Logger.log("送信に失敗したメールはありませんでした");    
    return 0;
  }    
  
  for (var n in myThreads) {
    var thread            = myThreads[n];   
    var msgs              = thread.getMessages();
    var failedMailAddress = "";
    var date              = "";

    for(m in msgs) {
      var msg        = msgs[m];
      var tmpAddress = getFailedMailAddress(msg.getBody());
      
      // 複数スレッドになると、うまく取れない場合があるので、取得可能な場合のみ
      if (tmpAddress !== '') {
        failedMailAddress = tmpAddress;
      } 
      
      date = msg.getDate();
    }
    
    Logger.log(date);
    Logger.log(failedMailAddress);
  }  
}

/**
 * 送信が失敗したメールアドレスを返す
 */
function getFailedMailAddress(body)
{
  var reg = /<b>.*?<\/b>/;
  if (body.match(reg) === null) return '';
  return body.match(reg)[0].replace('<b>', '').replace('<\/b>', '');
}
```

## 丁寧に解説していきます

### 1. 検索するメール条件を指定

![スクリーンショット 2019-06-11 20.29.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434023/a579fef8-404f-ca50-22a2-e605d4107a26.png)

この`var`というよく見る文字は`var`のあとに書いた文字列(変数名)になにか数値や文字を入れる箱の宣言だと思ってください。
今回は`var searchString = "from:'Mail Delivery Subsystem'";`とすることで、今後、`searchString`と書いて呼び出すと、自動的にコードが実行されるときには`from:'Mail Delivery Subsystem'`という文字列が使われるようになります。

もうお決まりごとなので覚えておきましょう！

また、今回はここで、`from:'Mail Delivery Subsystem'`と書いてるのは、Gmailの検索と一緒で、ここから来たメールを探すよーということを宣言しておきました。

### 2. 送信に失敗してたメールを探す

![スクリーンショット 2019-06-11 20.29.41.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434023/f3bca3a8-bf61-499f-0faf-219795f7cd71.png)

`var myThreads`はさっきと一緒ですので気にしなくてOKです。
ここで、`GmailApp`という新しい文字が出てきました。
これはGoogleAppsScriptが用意してるクラスというもので、Gmailのメールを取得したり、メールを送信したりできるという便利アイテムです。
詳しくは、[公式のドキュメント](https://developers.google.com/apps-script/reference/gmail/gmail-![error]()
app)に書いてあります。

このクラスというのは、`.`のあとになにか書くと、そのクラスが持ってる関数を呼び出せます。
今回の`GmailApp.search`は、Gmailを検索するよ。という関数です。
関数には、`引数`というものがあって、そこら辺は[関数の呼び出し方](https://developers.google.com/apps-script/reference/gmail/gmail-app#searchquery-start-max)に書いてあります。
第一引数に検索条件を書いて、第二、第三引数にどこから何件取得するかを書きます。 (今回は1件だけ)

次の行に書いてある`if (myThreads.length === 0)`ってのは、もし検索条件に引っかかるものが1件もなかったら。
という意味になります。


### 3. メール送信に失敗してた日付とメアドを取得してみる

いよいよ本題です。

![スクリーンショット 2019-06-11 20.29.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434023/0b31fb32-eb3f-73c4-f1be-2b8538b031cf.png)

検索結果が見つかると、`myThreads`にはデータが入ってきます。
これを`for`という構文を使って中に入ってるデータ分だけ回して処理します。

ほかはすべてこれまでの`var`を使ってるだけなので特に変わったことはしてません。
途中で、メールの文章から送信に失敗したメアドを取得するために、`getFailedMailAddress`という関数を呼んでますが、これは自分で作ったオリジナルの関数です。

基本的に、今すべて`mainFunction`の中に処理を書いていってますが、1つの関数の中に処理がたくさん書かれると、この関数の役割が何なのか分からなくなってくるので、処理ごとに関数に切り出すのがGoodです。

ちなみに、`getFailedMailAddress`はこんな感じです。

![スクリーンショット 2019-06-11 20.29.56.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434023/a939169b-d549-05e2-735f-1c770d49e17a.png)

関数の中で、正規表現という技術を使って、メールの中から`<b>`タグに囲まれた部分を返してます。
正規表現は[このサイト](https://tonari-it.com/gas-regular-expression/)を参考にさせてもらいました。

## 実際に動かしてみよう

「実行」>「関数を実行」>「mainFunction」をクリックすると、勝手に実行されます。

ただ、最初の実行時にはこんな感じで、承認を求められますので、手順に沿って承認していきましょう。

*まずは承認します。*

![スクリーンショット 2019-06-11 20.08.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434023/285e902d-88ba-a6d0-959b-cab970a75485.png)

*自分のアカウントを選択します。*

![自分のアカウント洗濯.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434023/f12d3380-bd18-7b98-affc-570bf853d326.png)

*詳細をクリック*

![詳細前.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434023/82bfbc56-496c-e07c-8d63-5ee7e98de40d.png)

*ページへ移動をクリック*

![詳細後.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434023/d13f9fa1-0836-e93c-38dd-48a98b889c05.png)


*自分のGmailへGoogleAppsScriptsがアクセスすることを許可*

![許可.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434023/fa9f8a32-12a6-1148-a40e-8323fc87e820.png)


*実行結果を見てみよう*

「表示」>「ログ」か、macならCommand+Enterでログの画面が開きます。

![実行結果.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/434023/459244fc-12ce-5509-13f7-fba63df29476.png)

取得出来てますね！！！

## 次回の野望

次は完成形を目指して以下を実装します。

* 失敗してたメアドをスプレッドシートに書いてく (自動で書かれてれば、マスターのシートとvlookup組んでおけば電話番号もスグ分かる)
* 毎日xx時間おきにこのスクリプトを実行 (トリガー設定)
* ただし、すでに取得したメアドはスルーする
* UI上からポチってしたら、初回の実行出来て、トリガー設定できる