typememo.jp

Gmail API Python メッセージとスレッドの取得方法

2020.09.13

#tech#gmail#python

Contents


はじめに

Gmail の API を Python で叩き、メッセージやスレッドを取得する方法についての紹介です。

使っているパソコンは MacMini でして、作業環境は以下のとおりです。

  • macOS Catalina 10.15.4
  • Python 3.7.5

ターミナルにてコマンドを2つ実行して、Gmail API を叩きブラウザ経由でメッセージやスレッドを取得します。

メッセージやスレッドを取得する前には Gmail API を認証する必要 があります。 まだ認証していない方は,認証してからこちらの記事を読み進めてください.

ソースコードは筆者の Gitlab リポジトリに置いてあります. なのでソースコード全文はこの記事に記載しません. ソースコード全文を見ながらこの記事を読むことをお勧めします.

以下では次の2つに絞って重点的に説明します.

  1. メッセージを取得するにはどうすれば良いか?
  2. スレッドを取得するにはどうすれば良いか?

ソースコード全文へのリンク

メインプログラムである quickstart.py の全文はこちら:

自作モジュール gmail.py の全文はこちら:

必要なパッケージをインストールする

ひとまず,Gmail API の実行に必要なパッケージをインストールしましょう. これらのパッケージがインストールされていないと Gmail API を叩くことができません.

python のバージョンが変わるとパッケージを再インストールする必要があります. 既にインストールしていると思っている方はご注意くださいませ.

pip install --upgrade \
google-api-python-client \
google-auth-httplib2 \
google-auth-oauthlib

これ以降は gmail.authorize()gmail.build_service() で認証が成功していることを前提にして話を進めます. まだ認証に成功していない方は Gmail API 認証方法 をお読みいただき認証に成功してからこの記事に帰ってきてください.

メッセージの取得方法

メッセージを取得する方法は次の2ステップで実現できます.

  1. メッセージリストを取得する
  2. 取得したメッセージリストの中からメッセージを抽出する

メッセージリストを取得する

まず1つ目の メッセージリストを取得する 実装について説明します.

quickstart.pygmail.get_messages() でメッセージリストを取得しています.

def main():
...
# Get messages list
msgs = gmail.get_messages(service, userid="me", query="newer_than:1h")

絶対に必要な引数は service だけで useridquery はオプション引数です. queryquery="newer_than:1d" に変更すれば現在時刻から1日前の間に受信したメッセージリストを取得できます.

では,gmail.get_messages() の実体はどうなっているのでしょうか? gmail.py に実体が次のように記述されています.

def get_messages(service, userid="me", query=""):
"""Get messages list."""
msgs_list = service.users().messages().list(
userId=userid,
q=query
).execute().get('messages')
return msgs_list

service.users().messages().list().execute().get('messages') でメッセージリストを取得しています. メッセージリストにはメッセージの ID やタイトルなど,メッセージを識別できる最低限の情報が含まれています.

list() の引数 userId は必ず指定する必要があります. デフォルトの値を "me" に設定していますが,自分ではないユーザー ID を指定することもできます. その時は認証云々の問題が出てくると思いますので,自分ではないユーザーさんと相談しながら作業を進めてくださいませ.

また list() の引数 q でクエリーパラメータを指定できます. 送信元を指定してメッセージを取得することも,任意の日時を指定してメッセージを取得することもできます. クエリーパラメータの指定方法についての詳細は Gmail で使用できる検索演算子 をお読みいただければと思います.

その他の引数については Method: users.messages.list をお読みいただければと思います.

取得したメッセージリストの中からメッセージを抽出する

続いて,メッセージリストの中から任意のメッセージを抽出する実装についてです.

quickstart.py では gmail.get_message() で先頭のメッセージ (Head message) を抽出しています.

def main():
...
# Get a head message
msg = gmail.get_message(service, msgs[0], userid="me")

gmail.get_message()msgs[0] を渡しているのが重要ポイントです. 今回はお試しで先頭のメッセージを渡していますが,msgs[-1] と書けば最後尾のメッセージを渡すこともできます. なんなら for 文を書いてしまえば取得した全てのメッセージをループ処理することもできます.

では,gmail.get_message() の実体に迫りましょう. gmail.pygmail.get_message() の実体が次のように記述されています.

def get_message(service, message, userid="me"):
"""Get a message."""
msg = service.users().messages().get(
userId=userid,
id=message['id']
).execute()
return msg

service.users().messages().get().execute() でメッセージを取得しています. get() の引数には必ず userIdid を渡してください. id はメッセージの ID です. gmail.get_messages() で取得したメッセージリストの各メッセージには既に固有の ID が割り振られています. その固有の ID を get() に渡してあげれば良いのです.

より詳しい情報は Method: users.messages.get をお読みいただければと思います.

スレッドの取得方法

スレッドの取得方法はメッセージの取得方法とほとんど同じです.

  1. スレッドリストを取得する
  2. 取得したスレッドリストの中からスレッドを抽出する

重要なポイントは service.users().threads() になることです. service.users().messages() ではなく. 説明が重複するのでスレッドの説明はわりかし雑にしておきます.

スレッドリストを取得する

スレッドリストの取得は quickstart.py 中の gmail.get_threads() を使えばできます.

def main():
...
# Get threads list
threads = gmail.get_threads(service, userid="me", query="newer_than:1h")

gmail.get_threads() の実体は gmail.py に記述されています.

def get_threads(service, userid="me", query=""):
"""Get messages list."""
threads_list = service.users().threads().list(
userId=userid,
q=query
).execute().get('threads')
return threads_list

一目瞭然ですが gmail.get_messages() とほとんど同じです. messagesthreads に変わっているだけです.

取得したスレッドリストからスレッドを抽出する

スレッドリストからとあるスレッドを抽出するには quickstart.py の中の gmail.get_thread() を使えば良いです.

def main():
...
# Get a head thread
thread = gmail.get_thread(service, threads[0], userid="me")

今回も先頭のスレッド threads[0] を抽出しています.

gmail.get_thread() の実体は gmail.py に次のように記述されています.

def get_thread(service, thread, userid="me"):
"""Get a message."""
thread = service.users().threads().get(
userId=userid,
id=thread['id']
).execute()
return thread

これまた gmail.get_message() とそっくりですね.

こんな感じで Gmail API は綺麗な設計になっています. なので,触っていてすごく面白いし “こういう風に設計すると良いんだな” と勉強にもなります.

スレッド関連の詳細は REST Resource: users.threads をお読みいただければと思います.

もしも quickstart.py と gmail.py を実行したい場合は?

quickstart.pygmail.py は筆者の Gitlab リポジトリからダウンロードしてください. credentials.jsonPython Quickstart の Step1 を行えば入手できます.

一番簡単な方法は quickstart.py gmail.py credentials.json を全て同じディレクトリに保存して python ./quickstart.py コマンドを実行する方法です.

python quickstart.py

quickstart.py には条件に当てはまるメッセージやスレッドがなかった場合のエラーハンドリングは実装していません. 条件に当てはまるメッセージやスレッドが見つからなかった場合は,条件を変更して再検索してください.

参考文献

Gmail API についての知識は主に Web 記事から得ました.

Python のモジュールの import についてのお作法は書籍から得ました. python import 方法 などのキーワードで google 検索かけるといくつか記事は見つかります. しかし,やっぱり書籍の方が知識がまとまっていてわかりやすかったです. Python の基本的なことは みんなの Python 第4版 から学び,自動化のヒントは 退屈なことは Python にやらせよう 初版 から学びました. ちなみに 退屈なことは Python にやらせよう 初版 の改訂版で 退屈なことは Python にやらせよう 第2版 が出版されるようです.(2020/09/15 時点: 予約受付中)

おわりに

Gmail API を Python で叩いてメッセージやスレッドを取得する方法についての紹介でした.

この記事ではメッセージやスレッドを取得する方法だけ紹介しましたが,別記事としてメッセージ本文を取得してデコードする方法を書こうと思っています.

タイミングが良ければ #gmail にその記事が見つかるかもしれません.

良ければチラッと覗いてもらえると嬉しいです.

最後までお読みいただきありがとうございました!


山田 武尊 / 立教大学(理学) / ACCESS CO LTD