GASとGmailAppのAPIを連携してみた

# はじめに
社内の共有会をきっかけに、GoogleAppsScript(GAS)を調べることになりました。連携できるサービスが豊富で学習コストも低くて、面白そうだったので使ってみることにしました。

自分のGmailにメールがたまりすぎると昔から思ってて、どんなメールが入ってきているのかなってふわっと気になりました。入ってくるメールにフィルターをかけているものの、実際の割合や数がわからない。そこで、分析アプリを作ればいい！とふと思いました。

今回は、GASでGmailの分析アプリを作ってみたいと思います。

# 使うもの
- Google Sheets (https://www.google.com/intl/ja_jp/sheets/about/)
- GoogleAppsScript (https://workspace.google.co.jp/intl/ja/products/apps-script/)
- GmailAppのAPI (https://developers.google.com/apps-script/reference/gmail/gmail-app)

# この記事でやること
- GASで自分のGmailアカウントにあるメールを種類別で件数を取得
- メールの件数のデータでチャートを作る
- Google Sheetsにデータとチャートを出力

# Google SheetとApps Scriptのセットアップ
1. 新規スプレッドシート作成し、スプレッドシートIDを取っておく
![スクリーンショット 2023-03-30 9.43.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3199930/92e4d027-5e6b-8149-8b18-1fab399ed141.png)

1. シートから、「拡張機能 → Apps Script」でApps Scriptを開く
![スクリーンショット 2023-02-27 20.32.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3199930/1debd09a-3ab1-3772-6468-40e1f4d922dc.png)

1. Apps Scriptの新規プロジェクトが作成される
プロジェクトは「Gmail Metrics App」と名付けた
![スクリーンショット 2023-02-27 20.33.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3199930/a5178311-3d7f-6f0b-8d47-6fffd0fcf315.png)

# 取りたいメールの種類（件数）
* 全件
* 未読メール
* 下書き
* 迷惑メール
* お気に入り（star付き）
* ラベル付き **※1**
* ゴミ箱

:::note warn
※1 注意：Gmailのラベルを使用していない方は、この記事のラベル付きメール取得・ラベル別チャート作成のステップができませんのでご了承ください。
:::

# メールを取得するfunctionを書く
メールの取得にGmailAppのAPIを使います。

https://developers.google.com/apps-script/reference/gmail/gmail-app

```javascript:コード.gs
function collectGmails() {
  // 自分のスプレッドシートのIDを指定する
  var book = SpreadsheetApp.openById('スプレッドシートのID');
  // 未読メールの数取得
  var unread = GmailApp.getInboxUnreadCount();
  // spamの未読メールの数取得（spamは基本開かないので未読でOK）
  var spam = GmailApp.getSpamUnreadCount();
  // 下書き取得
  var drafts = GmailApp.getDraftMessages();
  // star付きメール取得（基本的に既読なので既読としてカウント）
  var starred = GmailApp.getStarredThreads();
  // ゴミ箱に入っているメール取得
  var trash = GmailApp.getTrashThreads();
}
```
メールの全件数取得APIがないため、ループして全件を取って、ラベルごとに分けます。
```javascript:コード.gs
---省略---
  // 一気に全通取得できないので、ループさせる
  var startIndex = 0;
  var maxThreads = 500;
  var totalInbox = 0;
  var allThreads = [];

  do {
    // 500メール取得
    threads = GmailApp.getInboxThreads(startIndex, maxThreads);    
    allThreads.push(...threads); 
    totalInbox += threads.length;
    // 500通取得したら、全通取得するまで次の500通を取得する
    startIndex += maxThreads;
  } while (threads.length == maxThreads);

  // 全ラベル取得
  var allLabels = GmailApp.getUserLabels();
  var allLabelsCount = [];
  // ラベル名ごとの未読と既読のメールの数を分ける
  for (var i = 0; i < allLabels.length; i++) {
    // 既読
    allLabelsCount[allLabels[i].getName()] = 0;
    // 未読
    allLabelsCount[allLabels[i].getName() + " (Unread)"] = 0;
  }
  // ラベルがついていない数用
  var noLabelCount = 0;

  // 全通をループさせて、ラベル→「未読・既読」とラベルなしの数を計算
  for(var i = 0, n = allThreads.length; i < n; i++) {
    var labels = allThreads[i].getLabels();
    if (labels.length > 0) {
      // 計算をやりやすくするために、複数ラベルがついている場合、1個目のみカウントする
      if (allThreads[i].getMessages()[0].isUnread()) {
        // ラベルあり（未読）
        allLabelsCount[labels[0].getName() + " (Unread)"] += 1;
      } else {
        // ラベルあり（既読）
        allLabelsCount[labels[0].getName()] += 1;
      }
    } else {
      // ラベルなし（既読）
      noLabelCount += 1;
    }
  }
  // 書き込みたいシートに切り替える
  var sheet = book.getActiveSheet();
  // A列：カテゴリ名
  sheet.getRange(1, 1).setValue('Category');
  sheet.getRange(2, 1).setValue('Unread');
  sheet.getRange(3, 1).setValue('Spam');
  sheet.getRange(4, 1).setValue('Drafts');
  sheet.getRange(5, 1).setValue('Starred');
  sheet.getRange(6, 1).setValue('Trash');
  sheet.getRange(7, 1).setValue('Read');
  sheet.getRange(8, 1).setValue('Total');

  // B列：メールの数
  sheet.getRange(1, 2).setValue("Count");
  sheet.getRange(2, 2).setValue(unread);
  sheet.getRange(3, 2).setValue(spam);
  sheet.getRange(4, 2).setValue(drafts.length);
  sheet.getRange(5, 2).setValue(starred.length);
  sheet.getRange(6, 2).setValue(trash.length);
  sheet.getRange(7, 2).setValue(totalInbox - unread - starred.length);
  sheet.getRange(8, 2).setValue(totalInbox);

  // C列：カテゴリ名（ラベル別）
  sheet.getRange(1, 3).setValue('Category');
  sheet.getRange(2, 3).setValue('No Label');
  // D列：メールの数（ラベル別）
  sheet.getRange(1, 4).setValue("Count");
  sheet.getRange(2, 4).setValue(noLabelCount);
  var nextRow = 2;
  for (const [key, value] of Object.entries(allLabelsCount)) {
    nextRow += 1;
    sheet.getRange(nextRow, 3).setValue(key);
    var val = isNaN(value) ? 0 : value;
    sheet.getRange(nextRow, 4).setValue(val);
  }
}
```
functionを書き終わったら、保存します。
![スクリーンショット 2023-02-26 12.49.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3199930/ced030fa-4bd0-521a-4fa6-14a3975840b0.png)
※初回だけ承認する必要があります。
![スクリーンショット 2023-02-26 12.50.47.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3199930/fd750526-4a38-3904-fbf9-159829c24858.png)
「（自分のアプリの名前）（安全ではないページ）に移動」をクリック
![スクリーンショット 2023-02-26 12.51.42.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3199930/d990552b-4c92-8ea2-bf17-35d708cd1c45.png)
GASのアプリのGmailアクセスを許可
![スクリーンショット 2023-02-26 12.52.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3199930/868dcf5a-7e1c-f8ef-efeb-9672b5ae6b77.png)

保存できましたので早速実行しましょう。
![スクリーンショット 2023-03-30 23.26.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3199930/a7ab6c2b-0ed3-419d-305f-53dc65f0c6fb.png)

console.log()を埋め込めば、実行ログに表示されます。（今回は出してない）
![スクリーンショット 2023-02-28 7.47.24.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3199930/72fa2e3d-67d5-b5de-f6e4-880f3e6b3d88.png)

実行完了しましたら、Google Sheetsを開きます。そして。。
![スクリーンショット 2023-02-28 8.12.02のコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3199930/3cdc49ce-8a3d-b81b-bdf2-6262aa60b386.png)
おお！ちゃんとカテゴリと件数を出せてますね。
次はデータを可視化するために、チャートを作成します。

# Column Chart作成
まずは全体の種類別のチャートを作ってみます。
※collectGmails()の中にチャート作成のfunctionの呼び出しも追加してください。
```javascript:コード.gs
    ---省略---
    var val = isNaN(value) ? 0 : value;
    sheet.getRange(nextRow, 4).setValue(val);
  }
  // chart作成functionの呼び出し
  makeChart(sheet);
}

function makeChart(sheet) {
  // 新規column chart作成
  var chart = sheet.newChart()
  .setChartType(Charts.ChartType.COLUMN)
  .addRange(sheet.getRange("A2:A7"))
  .addRange(sheet.getRange("B2:B7"))
  .setOption('title', 'Gmail Statistics: All Emails')
  .setOption('vAxis.title', '# of Emails')
  .setOption('hAxis.title', 'Category')
  .setPosition(2, 6, 0, 0) // データの右側に置く
  .build();
  sheet.insertChart(chart);
}
```
保存、実行しますと、カラムチャートが作成されます。
![スクリーンショット 2023-02-28 20.21.22のコピー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3199930/0a8cb12f-dc84-0ad6-2961-2ba6c4d7f471.png)
既読メールの数が多すぎて見栄えがひどくなって、出さなくてもよかったかもって後から思ったんですけど、
まぁ、一応出したかった情報出せたので、後で不要な情報非表示できるからいいや。

次行きます。

# Pie Chart作成
次は、ラベルごとに取得した全件のメールをチャートに入れます。
Pie chartが一番みやすいかと思って選びましたが、GmailのAPIで色んなチャートを作ることができます。

https://developers.google.com/apps-script/reference/spreadsheet/embedded-pie-chart-builder

column chartの下にこのコードを追加して、パイチャートを作成します。
```javascript:コード.gs
  var lastRow = sheet.getLastRow();
  // 新規pie chart作成
  var labelChart = sheet.newChart()
    .setChartType(Charts.ChartType.PIE)
    .addRange(sheet.getRange("C1:C" + lastRow))
    .addRange(sheet.getRange("D1:D" + lastRow))
    .setOption('title', 'Gmail Statistics By Labeled Emails')
    .setOption('legend', {position: 'left'})
    .setOption('pieSliceText', 'value-and-percentage')
    .setOption('pieHole',0.5)
    .setPosition(2, 12, 0, 0)
    .setNumHeaders(1)
    .build();
  
  sheet.insertChart(labelChart);
```
再度プロジェクトを保存して、実行しますとー。
![スクリーンショット 2023-02-28 8.12.02のコピー2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3199930/a972cbee-37b9-21dc-b7aa-289cf354acad.png)

見やすい〜 わかりやすい〜
ラベルなしが全件の1/4くらいって一目でわかりますね、いいですね。

# あとがき
今回は GAS と Google Sheets を用いて、簡単なGmail集計アプリを構築してみました。
Javascriptで書けますので、学習コストがとても低くく、初めてのアプリ開発にピッタリなサービスだと思います。

GASと連携しているGmailのAPIは、時期を指定したり、メールを一括操作（削除、送信等）したりすることもできるらしいので、ご興味のある方はぜひ試してみてください。

# 参考になった記事

https://tetsuooo.net/gas/746/

https://tech.torico-corp.com/blog/gmail-export-to-google-spreadsheet-via-google-apps-script-gas/

https://tonari-it.com/gas-gmail-sendemail/