Gmailにすでにあるメールをスプレッドシート出力する

今回作成したのは、「Gmailにすでにあるメールをスプレッドシート出力する」です！
gmailで特定条件のメールをスプレッドシートに出力して、件数を調べたりする事ができます！

以下様々なGASの記事を紹介してます！
https://bzbot.work/

##紹介記事
今回紹介している記事は以下です！
https://bzbot.work/2019/01/29/gmail-spreadsheet/

###スクリプトエディタを開く
![image.png](https://qiita-image-store.s3.amazonaws.com/0/363116/ef06cbce-b73e-95a8-3fbd-2c6be60ff548.png)

###スクリプトエディタにコードを記述
![image.png](https://qiita-image-store.s3.amazonaws.com/0/363116/65f16406-f211-bdb9-2850-110bf170b996.png)


##コード
```javascript:GAS
var SEARCH_TERM = "【Microsoft Flowでテスト送信してみた】";
var SEARCH_COUNT = 50; //取得スレッド数
var sheet = SpreadsheetApp.getActiveSheet(); 

function searchContactMail() {

  var myThreads = GmailApp.search(SEARCH_TERM, 0, SEARCH_COUNT);
  var myMessages = GmailApp.getMessagesForThreads(myThreads); //スレッドからメールを取得する　→二次元配列
  
  
  for(var i=0;i < myMessages.length;i++){
  Logger.log(myMessages[i][0].getId()); //メッセージIDをログ表示
    sheet.getRange(i + 2, 1).setValue(myMessages[i][0].getId());
    
  Logger.log(myMessages[i][0].getFrom()); //宛先をログ表示
    sheet.getRange(i + 2, 2).setValue(myMessages[i][0].getFrom()); 
    
  Logger.log(myMessages[i][0].getDate()); //送信日時をログ表示
    sheet.getRange(i + 2, 3).setValue(myMessages[i][0].getDate()); 
    
  Logger.log(myMessages[i][0].getSubject()); //件名をログ表示
    sheet.getRange(i + 2, 4).setValue(myMessages[i][0].getSubject());  

  Logger.log(myMessages[i][0].isInInbox()); //Inboxをログ表示
    sheet.getRange(i + 2, 5).setValue(myMessages[i][0].isInInbox());  
  }
}
```


まずは検索する情報を指定

```javascript:GAS
var SEARCH_TERM = "【Microsoft Flowでテスト送信してみた】"
```


次はスレッドの取得する件数のMAX件数を指定します。
Gmailの取得件数は1日で上限があるらしく、それに抵触しない回数で取得が必要そうです。
※今回は特にそういったことは無視してます

```javascript:GAS
var SEARCH_COUNT = 50; //取得スレッド数
```

Gmailで検索します。検索ワードとメールの検索するlimitで指定した件数分。
その後、スレッドからメールを取得します。

```javascript:GAS
var myThreads = GmailApp.search(SEARCH_TERM, 0, SEARCH_COUNT);
var myMessages = GmailApp.getMessagesForThreads(myThreads); //スレッドからメールを取得する　→二次元配列
```

最後はfor文にて、取得した件数のループ処理の中に、取得した情報をそれぞれログとスプレッドシートのセルにsetしていきます。

```javascript:GAS
.getId() //メールIDを取得します。
.getFrom() //宛先を取得します。
.getDate() //日時を取得します。
.getSubject() //件名を取得します。
.isInInbox() //受信ボックスにある場合はTRUE、それ以外はFALSEが表示されます。
```

```javascript:GAS
for(var i=0;i < myMessages.length;i++){
  Logger.log(myMessages[i][0].getId()); //メッセージIDをログ表示
    sheet.getRange(i + 2, 1).setValue(myMessages[i][0].getId());
    
  Logger.log(myMessages[i][0].getFrom()); //宛先をログ表示
    sheet.getRange(i + 2, 2).setValue(myMessages[i][0].getFrom()); 
    
  Logger.log(myMessages[i][0].getDate()); //送信日時をログ表示
    sheet.getRange(i + 2, 3).setValue(myMessages[i][0].getDate()); 
    
  Logger.log(myMessages[i][0].getSubject()); //件名をログ表示
    sheet.getRange(i + 2, 4).setValue(myMessages[i][0].getSubject());  

  Logger.log(myMessages[i][0].isInInbox()); //Inboxをログ表示
    sheet.getRange(i + 2, 5).setValue(myMessages[i][0].isInInbox());  
  }
```


##しかし、問題が出ました。。。
Gmailにあるメールの数と、取得したはずの値が完全に一致しないのです。。。
これには理由があるだろうとデバックしてみると配列の値で取得できてなさそうな値があることがわかりました。
そして今回作成したコードのピックアップした部分がこちら
このあと詳しく記載していきます。

```javascript:GAS
for(var i = 0;i<myMessages.length;i++){
 var myMessagesLen = myMessages[i].length
 Logger.log(myMessagesLen);
 for(var j = 0;j<myMessagesLen;j++){
  sheet.getRange(rowCnt, 1).setValue(myMessages[i][j].getId());		    
  sheet.getRange(rowCnt, 2).setValue(myMessages[i][j].getFrom()); 
  sheet.getRange(rowCnt, 3).setValue(myMessages[i][j].getDate()); 
  sheet.getRange(rowCnt, 4).setValue(myMessages[i][j].getSubject());  
  sheet.getRange(rowCnt, 5).setValue(myMessages[i][j].isInInbox());  
  rowCnt = rowCnt + 1; //値をsetしたら（処理を実行したら）一行下にずれる
 }
}
```


まず、変数myMessages①より小さいときは中に記載された処理を実行します。
変数myMessageLen②に変数myMessages①で取得した値で取れていない値を取得します。
※以下例でいうと、0[3]の3の部分。ここには要素がそれぞれ3つ入っているため、これらも取得の対象となります

![image.png](https://qiita-image-store.s3.amazonaws.com/0/363116/ec5162ae-df92-3805-7bdd-c93adc109fcc.png)

そのため、以下処理を追加しています。
処理にLogger.log(myMessageLen)を追加している為、roopされて実行される度にログにmyMessageLenに入っている値が表示されます。
このfor処理はそのmyMessageLenの数をそれぞれ繰り返すという処理です。
その為、3回、1回 ..... 72回、1回というように処理をしています。

```javascript:GAS
Logger.log(myMessagesLen);
for(var j = 0;j<myMessagesLen;j++){
      sheet.getRange(rowCnt, 1).setValue(myMessages[i][j].getId());            
      sheet.getRange(rowCnt, 2).setValue(myMessages[i][j].getFrom()); 
      sheet.getRange(rowCnt, 3).setValue(myMessages[i][j].getDate()); 
      sheet.getRange(rowCnt, 4).setValue(myMessages[i][j].getSubject());  
      sheet.getRange(rowCnt, 5).setValue(myMessages[i][j].isInInbox());  
      rowCnt = rowCnt + 1; //値をsetしたら（処理を実行したら）一行下にずれる
 　}
```


![image.png](https://qiita-image-store.s3.amazonaws.com/0/363116/f2d90f80-422e-b8f1-d165-a5d941682f6c.png)

次は改行処理です。当初作成した処理は処理して繰り上がり、処理して繰り上がり...となってましたが、今回追加したプログラムで改行を追加しない場合は2回目のforを実行中は同じ値が上書きされてしまいます。

簡単に説明するとmyMessageLenが3だった場合、1回目はスプレッドシートの1行目の1列目に「AAA」という値が入ります。しかし、本来2回目の処理で2行目の1列目に新しい値「BBB」が入って欲しいですが、改行処理を入れないと「AAA」に「BBB」が上書きされてしまいます。

そのため、以下を追加してます。

```javascript:GAS
rowCnt = rowCnt + 1; //値をsetしたら（処理を実行したら）一行下にずれる
```

さらに「sheet.getRange(rowCnt, 1)」で行の指定をrowCntにすることで毎に繰り上がっていきます。
1回目の処理は(1,1)。2回目の処理は(2,1)。3回目の処理は(3,1)。。。という形で行を改行していきます。

少し昔に作った処理ですが、どんどん可読性が高い、メンテナンスのしやすいコードにゆくゆくは書き換えて行ければと思います！
楽しみながら、勉強あるのみ。笑