【決定版】GAS で Gmail の検索結果をスプレッドシートに抽出する方法

## はじめに

Gmail の検索結果をスプレッドシートにためる方法を紹介します。 Google Apps Script (GAS) を使います。

はじめに簡易版のコードを提示して、その後に特定のケースにあった追加実装について説明します。

## 実装
実装は以下で 30 行ほどで実装できる。かなり処理を絞ったコンパクト版なので、テンプレート的に使っていただければ！

```JavaScript
// 設定情報
function getConfig() {
  return {
    spreadSheetId: '',// スプレッドシートの ID
    spreadSheetTabName: '',// スプレッドシートのタブ名
    searchText: ''// Gmail の検索ワード
  };
}

// 実行関数
function main() {
  var config   = getConfig();
  var sheet    = SpreadsheetApp.openById(config.spreadSheetId)
                               .getSheetByName(config.spreadSheetTabName);
  var messages = [['Subject', 'From', 'To']];

  GmailApp
    .search(config.searchText, 0, 500)
    .forEach(function (thread) {
      thread.getMessages().forEach(function (message) {
        var subject = message.getSubject();
        var to      = message.getTo();
        var from    = message.getFrom();
        messages.push([subject, from, to]);
      });
    });

  if (messages.length === 0) return;
  sheet.getRange('A1:C' + messages.length ).setValues(messages);
}
```
https://github.com/tanabee/gmail-to-spreadsheet

## 使い方

基本的に、上記のコードを GAS エディタ（ https://script.google.com ）に貼り付けて getConfig 関数内の、それぞれのキーに値を入力すれば動作する。最大 500 件を一回で取ってくる仕様なので、使い方によって追加開発が必要。

### 件名、送信元、宛先以外の情報取得

上記のコードでは件名、送信元、宛先しか取れていない。本文や、日付、添付ファイルなど取りたければ追加取得可能。

![スクリーンショット 2018-08-28 17.40.37.png](https://qiita-image-store.s3.amazonaws.com/0/19698/7c7a3dbf-f20d-6256-86ea-734bfb8affb6.png)
[Class GmailMessage](https://developers.google.com/apps-script/reference/gmail/gmail-message) の Get 系メソッド一覧

### 複雑な検索をしたい
時間を指定するなど、動的に検索条件を変えたい場合や複雑な検索条件で検索したい場合などは、 getConfig から外出しして、検索ワードを整形する必要がある。

検索ワードの組み立て方については公式ヘルプの [Gmail で使用できる検索演算子](https://support.google.com/mail/answer/7190?hl=ja) を参考にするとよい。

上記ヘルプでは特に触れられていないが after/before などは UNIX Time で指定も可能。以下のコードで 1 時間前からのメールを抽出できる。

```JavaScript
var after = parseInt(((new Date()).getTime() - 1 * 60 * 60 * 1000) / 1000);
var searchText = 'subject:github after:' + after;
```

### 大量のメールを一度に抽出したい

[GmailApp.search](https://developers.google.com/apps-script/reference/gmail/gmail-app#search(String,Integer,Integer)) メソッドは大量のメールにヒットするとエラーになってしまう。第 2 引数で skip の指定が可能なので、 for 文などで回して、500 件ずつくらいでメールを取得して、大量取得が可能になる。

```JavaScript
for (var i = 0; i < 100; i++) {
  var threads = GmailApp.search(searchText, i*max+1, 500);
  // 省略
  if (threads.length === 0) break;
}
```

### 定期的にメールを抽出して、シートに溜めていきたい

定期的に抽出したい場合は、[時間主導型のトリガー](https://qiita.com/tanabee/items/2c51681396fe12b6a0e4#%E3%83%88%E3%83%AA%E3%82%AC%E3%83%BC)を使って定期実行させる。正確な抽出が求めれられる場合には、ダブリや漏れが起こらないように、 after （↑複雑な検索をしたい部分で紹介）に余裕を持たせて実行間隔よりも長い期間で検索して、メールの ID かぶりをチェックするのが良い。

[GmailMessage.getId()](https://developers.google.com/apps-script/reference/gmail/gmail-message#getId()) で一意の ID を取得できるので、 ID もシートに記録するようにして、 Array.push 前に重複しないかチェックするのが良い。

### 数の集計をしたい

数の集計をする場合には、 Google Apps Script でやってもよいが、[スプレッドシート関数](https://support.google.com/docs/table/25273?hl=ja)を使うのがおすすめ。できるだけ、GAS のコードは極小化して、 Google Apps （スプレッドシートや Gmail など） の機能を活かしたほうが後々メンテも楽になる。

特に SQL ライクに書ける [QUERY 関数](https://support.google.com/docs/answer/3093343)はかなり使える。

以下の例では、別シート（シート名: data）の A 列に特定の文字列（github）が含まれる数を返す。

```javascript
=QUERY(data!A:C, "select count(A) where A contains 'github'")
```

## まとめ

以上、簡易なコードからそれぞれのケースにあった実装指針を紹介しました。他の GAS ネタも書いているので、以下ご参考ください。

## 関連記事
- [GAS ビギナーが GAS を使いこなすために知るべきこと 10 選](https://qiita.com/tanabee/items/2c51681396fe12b6a0e4)
- [3 分で作る無料の翻訳 API with Google Apps Script](https://qiita.com/tanabee/items/c79c5c28ba0537112922)
- [Google Apps Script (GAS) で毎週 30 分の雑務を自動化した話](https://qiita.com/tanabee/items/e51f107f1e95a42cc636)