コツコツと

Node.js + TypeScript で GmailAPI を利用してみる

June 30, 2020

Node.js + TypeScript で、Gmail API を使ってメールを取得するまでの実装を説明します。

Gmail API は 下図の OAuth 2.0 のプロトコルフローに沿って、 ユーザーから Gmail のアクセス権に対する認可を得ることで利用できます。
このフローを念頭に置いておくと、以降の説明が理解しやすくなると思います。

ちなみに Google が、 Gmail API 含む Google が提供する API を利用できるデモサイト(OAuth 2.0 Playground)を用意してくれているので、 そちらで OAuth2.0 プロトコルフローを試してみることもできます。

+----------+
| Resource |
|   Owner  |
|          |
+----------+
     ^
     |
    (B)
+----|-----+          Client Identifier      +---------------+
|         -+----(A)-- & Redirection URI ---->|               |
|  User-   |                                 | Authorization |
|  Agent  -+----(B)-- User authenticates --->|     Server    |
|          |                                 |               |
|         -+----(C)-- Authorization Code ---<|               |
+-|----|---+                                 +---------------+
  |    |                                         ^      v
 (A)  (C)                                        |      |
  |    |                                         |      |
  ^    v                                         |      |
+---------+                                      |      |
|         |>---(D)-- Authorization Code ---------'      |
|  Client |          & Redirection URI                  |
|         |                                             |
|         |<---(E)----- Access Token -------------------'
+---------+       (w/ Optional Refresh Token)

Note: The lines illustrating steps (A), (B), and (C) are broken into
two parts as they pass through the user-agent.

                Figure 3: Authorization Code Flow
        RFC6749(https://tools.ietf.org/html/rfc6749) より

事前準備

クライアント登録と資格情報を取得する

まずは、Google の認可サーバーにクライアント(アプリケーション)情報を登録します。 (RFC6749 の 2.Client Registrationにあたる仕様)
クライアントの登録は、Google API Consoleからできます。 RAKUS Developers Blogが参考になりました。

クライアント登録する際、リダイレクト URI を設定するのですが、 "http://127.0.0.1:ポート番号"を設定してください。
ポート番号は 3000 など、空いているポートの値を設定してください。
クライアント登録後、資格情報ファイル(json 形式)をダウンロードして、ワークディレクトリのトップ($ npm initしたディレクトリ)に保存します。
この資格情報は、Authorization Server(上記のAuthorization Code Flow参照)にリクエストする際のパラメータで利用します。

ライブラリを install する

コマンドラインで、ワークディレクトリまで移動して次のコマンドを実行します。

$ npm install googleapis -S

実装

ソースコードはこちらに公開していますので、ポイントのみ説明します。

ソースファイル構成

ファイル名 内容
OAuthForGoogleApi.ts Google API との OAuth2 フローを扱う OAuthForGoogleApi クラスを定義している
GmailApi.ts Gmail からメール情報を取得する GmailApi クラスを定義している
sample.ts メイン処理
Util.ts ファイル操作などのユーティリティメソッドをまとめている
Constants.ts 定数をまとめたファイル
OAuthForGoogleApi.ts

OAuthForGoogleApi.ts には、OAuthForGoogleApi クラスを定義しています。
そのクラスにて、googleapis ライブラリで定義されてる OAuth2Client クラスを利用して、 アクセストークンを取得するまでの処理を記述しています。
OAuthForGoogleApi クラスをインスタンス化する際、第一引数にスコープを設定します。
ここで、スコープとはクライアント(アプリケーション)がユーザーに要求する権限のことです。
例えば、メールを参照したい場合は、https://www.googleapis.com/auth/gmail.readonlyを設定します。
メールの編集や送信をしたい場合は、別のスコープを設定する必要があります。
スコープの詳細は、こちらを参照ください。

第二引数には、こちらで取得した資格情報ファイルのパスを設定します。 ちなみに資格情報は OAuth2Client のインスタンス化時に利用します。

その他、詳細はソースコード中のコメントに記載しましたので、そちらを参照ください。
コメントには、上に載せた Authorization Code Flowと実装を対応づけるため、 A〜E のアルファベットを記しています。

GmailApi.ts

googleapis ライブラリの gmail_v1.Resource$Users$Messages クラスを利用して、 Gmail からメール情報を取得しています。

gmail_v1.Resource$Users$Messages は次のようにインスタンス化できます。

const usersMessages = new gmail_v1.Resource$Users$Messages({
  _options: {
    auth: oAuth2Client, // OAuth2Clientのインスタンスをセットする
  },
})
検索条件に一致するメールを取得する

gmail_v1.Resource$Users$Messages#list メソッドを利用します。
list メソッドのパラメータは、gmail_v1.Params$Resource$Users$Messages$List型です。
メールアドレスが、xxx@example.com のメールを検索したい場合は、次のようにパラメータを生成すればよいです。

// メールの検索条件を生成する
const param: gmail_v1.Params$Resource$Users$Messages$List = {
  userId: `me`,
  q: `from:xxx@example.com`,
}
// 検索の実行
const result = await usersMessages.list(param)

qプロパティに設定できる条件は、こちらを参照ください。

list メソッド を実行すると次の形式の結果が取得できます。
messages に検索条件に一致したメールの id が設定されています。

{"resultSizeEstimate": hoge,
  "messages": [
    {
      "id": "xxx",
      "threadId": "xxxx"
    },
    {
      "id": "yyy",
      "threadId": "yyy"
    },
    ...
  ],
  "nextPageToken":fuga
}
特定のメールの詳細情報(差出元のアドレスや本文など)を取得する

特定のメールの詳細情報(差出元のアドレスや本文など)を取得したい場合は、 gmail_v1.Resource$Users$Messages#get を利用します。
get メソッドのパラメータは、Params$Resource$Users$Messages$Get型です。
パラメータは次のように生成します。

const param: gmail_v1.Params$Resource$Users$Messages$Get = {
  userId: `me`,
  id: "xxx", // listメソッドで得られたメールのidを設定する
}

get メソッドを実行するとgmail_v1.Schema$Message型の結果を得ます。
テキストメールの本文は、gmail_v1.Schema$Message.payload.body.dataに格納されています。
但し、メール本文は Base64 エンコードされているので、デコードしないと理解できません。

sample.ts

メイン処理です。
検索条件に一致したメールの内、 最初の 1 件のメール本文をコンソールに表示する処理を実装しています。
サンプルプログラムの実行方法は、ソースコード公開先の README を参照ください。

留意点やメモ

  • リダイレクト URI を http にしてるので、https 化しないとセキュリティ的によろしくないかも?
  • アプリケーション終了後、アクセストークンを revoke した方(失効させた方)がいいかも。
  • アクセストークンは有効期間がある。
    そのため失効した場合、リフレッシュトークンを用いて新しいアクセストークンを取得する必要があるが、 こちらによると、googleapis ライブラリが自動で対応してくれていそう。

参考情報


© 2020 jiri3