IMAPプロトコルでメール通知
思うところがあり、メールが来た時に本文を見て一部をslackに通知したくなった
そこで、少し調べているとIMAP4というプロトコルがあるということを知りメール通知 + 本文取得を実装したのでメモ
IMAP4プロトコルとは
IMAP4は、オンラインでサーバ上に設けたメールボックスにアクセスし、操作や管理を行うことができる。そのため、オンラインでサーバにアクセスできる環境であれば、外出先や異なるマシンからでも同じメッセージを確認できるという利点をもっている。IMAP4は、フリーメールとして提供されることの多いWebメールや、モバイルメールなどでよく利用されている。
これに加えてIdleという機能があり、IMAPサーバーからメールの通知が受け取れる機能があるらしい
さらに各社フリーメールで提供されているらしいので、Gmail API等に依存しない形で実現できそうだ
今回使用したコマンド
通知と本文の取得だけであればすべてのコマンドを使う必要がなく、今回は↓のコマンドのみを使用した
LOGIN
LOGIN ユーザー名 パスワード
ユーザー名とパスワードでログインを行う
SELECT
SELECT ラベル名
メール操作の対象をラベル名で指定する
IDLE
IDLE
コマンドを実行するとサーバーがアイドル状態になり、メールを受信するとサーバーから通知が送られる
通知される際にFETCHで利用できるメッセージ番号も同時に送られる
FETCH
FETCH メッセージ番号 データ名
メッセージ番号のメールを取得する、データ名を指定することで目的のデータが手に入る。
今回は、メールの平文が欲しかったので BODY[1]
のみ使用することにした
LOGOUT
LOGOUT
ログアウトする
コマンドを試してみる
上記のコマンドをopensslで試してみる
kaneta@tk2-239-29469:~/kakin-notify$ openssl s_client -quiet -crlf -connect imap.gmail.com:993 depth=3 C = US, O = Equifax, OU = Equifax Secure Certificate Authority verify return:1 depth=2 C = US, O = GeoTrust Inc., CN = GeoTrust Global CA verify return:1 depth=1 C = US, O = Google Inc, CN = Google Internet Authority G2 verify return:1 depth=0 C = US, ST = California, L = Mountain View, O = Google Inc, CN = imap.gmail.com verify return:1 * OK Gimap ready for requests from 2001 ? LOGIN {ユーザー名} {パスワード} * CAPABILITY IMAP4rev1 UNSELECT IDLE NAMESPACE QUOTA ID XLIST CHILDREN X-GM-EXT-1 UIDPLUS COMPRESS=DEFLATE ENABLE MOVE CONDSTORE ESEARCH UTF8=ACCEPT LIST-EXTENDED LIST-STATUS LITERAL- SPECIAL-USE APPENDLIMIT=35651584 ? OK {ユーザー名} authenticated (Success) ? SELECT INBOX * FLAGS (\Answered \Flagged \Draft \Deleted \Seen $NotPhishing $Phishing) * OK [PERMANENTFLAGS (\Answered \Flagged \Draft \Deleted \Seen $NotPhishing $Phishing \*)] Flags permitted. * OK [UIDVALIDITY 1] UIDs valid. * 7556 EXISTS * 0 RECENT * OK [UIDNEXT 7667] Predicted next UID. * OK [HIGHESTMODSEQ 441443] ? OK [READ-WRITE] INBOX selected. (Success) ? IDLE + idling * 7557 EXISTS ? NOOP ? BAD Could not parse command ? FETCH 7557 BODY[1] * 7557 FETCH (FLAGS (\Seen) BODY[1] {14} Hello IMAP!= ) ? OK Success ? LOGOUT * BYE LOGOUT Requested ? OK 73 good day (Success) read:errno=0 kaneta@tk2-239-29469:~/kakin-notify$
メール通知 + 本文取得は↓を繰り返せば良いことになる
? IDLE + idling * 7557 EXISTS ? NOOP ? BAD Could not parse command ? FETCH 7557 BODY[1] * 7557 FETCH (FLAGS (\Seen) BODY[1] {14} Hello IMAP!= ) ? OK Success
成果物
プロトコルを完全に網羅するのは辛すぎるので、今回の目的(通知 + 本文の取得)として利用できるようにラップしたパッケージを練習中のgolangで書いた
作成したパッケージでGmailに来るGoogle Playの課金メールを監視して、合計金額をslackに通知するbotも作った github.com
ハマりポイント
- 送信時はcrlfが末尾にないとレスポンスが一切帰ってこない(消費4時間)
- yamlの読み込みに使用する構造体のメンバは公開メンバ(頭文字大文字)にしないとだめ(消費1時間)