Python
gmail
Slack
gcp
GmailApi

スパムメール一覧を定期postするslackbotを作った


TL;DR

ビジネス系とか知らない分野の勉強会のおしらせみたいな「あまり興味ないけど動向を知りたいメルマガ」があって監視したかったのでタイトルの一覧だけを毎日slackbotで通知するようにしました。slackbotでなくても良いんですけど、ふだんよく見るのがslackなので。対象メールはスマホで通知されないようにフィルタリングでアーカイブするようにしておきます。

Throttle というサービスもあるみたいですがslackで手軽にみれたほうが良いので。 ワードクラウドとか可視化という手もありますが、同じ理由で簡単に件名だけ列挙するだけにしました。


件名取得

Gmailを使ってるのでGmailから取り出しました。GmailAPIがあるので結構簡単でした。

参考 https://qiita.com/orikei/items/73dc1ccc95d1872ab1cf

https://developers.google.com/gmail/api/quickstart/python に書いてあるようにGmail APIを有効にして、Google Client Libraryをインストールしました。subjectとidを取得できればいいので、ここにあるGmailAPI.pyのGmailAPIクラスをそのまま使わせていただきました。以下ソース


run.py

#!/usr/bin/env python3

# -*- coding: utf-8 -*-

from GmailAPI import GmailAPI
import yaml
from pathlib import Path
from datetime import datetime, timedelta
from dateutil.parser import parse as parse_time
from pytimeparse import parse as parse_timedelta
from slackclient import SlackClient

def create_message_slackbot(msg, start, end, mail):
d = {
'start': start.strftime('%Y/%m/%d %H:%M'),
'end': end.strftime('%Y/%m/%d %H:%M'),
'mail': mail,
'subjects': '\n'.join(['<' + x['url'] + '|' + x['subject'] + '>' for x in msg])
}
if len(msg) > 0:
return """{start}~{end}
{mail} 宛てのメールまとめ
{subjects}
"""
.format(**d)
else:
return """{start}~{end}
{mail} 宛ての収集対象メールなし
"""
.format(**d)

if __name__ == '__main__':
conn_gmail = GmailAPI()
homedir = Path().home()
with homedir.joinpath('.mailsummarizer_settings.yml').open('r') as f:
settings = yaml.load(f)
"""
SLACK_API_TOKEN: xorb-XXXXX
CHANNEL: <CHANNEL ID>
UserAddress: zzzz@gmail.com
Targets:
- xxxx@xxx
- "@yyy"
- zzz
- ....
Start: 00:00
Span: 1 day
"""

end = parse_time(settings['Start'])
start = end - timedelta(seconds=parse_timedelta(settings['Span']))
messages = []
for t in settings['Targets']:
messages += conn_gmail.GetMessageList(
DateFrom=str(int(start.timestamp())),
DateTo=str(int(end.timestamp())),
MessageFrom=t
)
url = 'https://mail.google.com/mail?authuser='
messages = [
{'subject': x['Subject'],
'url': url + settings['UserAddress'] + '#all/' + x['ID']
} for x in messages]
text = create_message_slackbot(
messages, start, end, settings['UserAddress'])
client = SlackClient(settings['SLACK_API_TOKEN'])
client.api_call(
method='chat.postMessage',
channel=settings['CHANNEL'],
username='スパムメール要約',
text=text
)


ソースの解説をします。

必要なライブラリは google-api-python-client, google-auth-httplib2, google-auth-oauthlib, oauth2client, pytimeparse, slackclient です.

設定ファイルは.mailsummarizer_settings.ymlという名前でホームディレクトリに置きます。yaml形式で書いてます。

SLACK_API_TOKEN: slackのAPIトークンです

UserAddress: 自分のアドレスです

Targets: 対象のアドレスです(部分一致)。@で始まる文字列はクォーテーションで囲まないとダメなので注意してください

Start: 毎回何時から何時までの範囲で収集するか

Span: 1回の実行でどれくらいの期間収集するか。 pytimeparse で読み込める形式で記入してください。

Gmail検索の検索クエリに変換して投げてます。時間帯指定はエポック時間に変換すると細かい時刻まで指定できる裏技があるらしいのでこれを使います。

参考 https://www.lifehacker.jp/2016/12/161221_gmail_timesearch.html

メールidがあると

https://mail.google.com/mail?authuser=<XXXXXX@gmail.com>#all/<id>

という形でメールを開くURLを作り出せます。なのでGmailAPI.py の処理を使えば必要なデータは全部取得できます。

参考 https://stackoverflow.com/questions/38877956/get-direct-url-to-email-from-gmail-api-list-messages

ハイパーリンクを貼る方法は https://qiita.com/tanjo/items/ea467c7de3fbd849aa4b を参考にしました。

Pythonにはslackbotというのがあるらしいですが、今回は定期的に起動すればいいだけでチャットボットではないので今回はslackclientを使います。

https://github.com/slackapi/python-slackclient


どのサーバーで運用したらいいか?

いままでこういうの作ったことがなかったので調べてみました。GCEとIBM Cloudに無料プランがあるみたいですが、最近流行ってるのでGCEを選びました。一番ロースペックのインスタンスにすれば実質無料になるらしいのでこれを使いました。

参考: https://qiita.com/you8/items/670bfa6573cec2494c96

あとは GmailAPI.py, run.py, credentials.json, token.json, token.pickle を同じディレクトリに置いて、ホームディレクトリに.mailsummarizer_settings.ymlを置いて、cron で定期的にインスタンス上で実行させます。


crontab

SHELL=/bin/bash

00 07 * * * (cd ... && python run.py) > /dev/null

GmailAPI.py がカレントディレクトリのファイルを参照するようになっているので直前で run.py のあるディレクトリに移動する必要があります。

今後のことを考えて pyenv 経由で python3 をインストールしました。この場合上記の python のパスも適当に変えておく必要があります。

参考: https://qiita.com/kaito__/items/a6d805dc6df10dff9244

あと以下も忘れずに

pip install --upgrade google-api-python-client google-auth-httplib2 google-auth-oauthlib oauth2client pytimeparse slackclient pyyaml python-dateutil