これは ユニキャストアドベントカレンダー の1日目の記事です。
個人的に滅びて欲しいけどどうにもならない技術TOPにランクインしているのが電子メールです。
早くチャットに置き換わって欲しいと常日頃感じているのですが、業務上使わざるを得ないのが実情です。
(ちなみにユニキャストでは Chatwork で基本的に社内コミュニケーションを取っています。非エンジニアにも馴染みやすいUIなのがよいですね。)
poplib で迷惑メールを処理する
電子メールのつらさを助長している存在の一つとして、SPAMメールがあります。
「ものすごい量の迷惑メールが来てしまってメールがパンクしてます!助けて!」というヘルプが来ることがまれに良くあります。
Battery Included の思想を掲げる Pythonなら標準ライブラリの一部である poplib を使って POP3 で簡単にメールボックス内のメールの迷惑メールの削除処理をすることができます。
POP3 の仕組み
POP3 (Post Office Protocol v3) はリモートのメールボックスからメールを受信するためのプロトコルです。
POP3プロトコルはメールサーバ上の電子メールの受信、削除、およびそれらを実行するユーザの認証の手順を定めており、ほぼすべてのメールソフトやメールサーバがサポートしているプロトコルです。
POP3はシンプルなテキストプロトコルなので、telnet や netcat でも比較的簡単に使うことが出来ます。
TLSによる暗号化もサポートしていますが、本稿では簡単のためすべて平文にて例示します。
以下は netcat で POP3 を話す例です。
[jsaito@localhost ~] $ netcat pop.example.com 110
+OK Dovecot ready.
USER jsaito@example.com
+OK
PASS password
+OK Logged in.
LIST
+OK 102 messages:
1 614923
2 2487
~中略~
.
RETR 1
~中略~
.
DELE 1
+OK Marked to be deleted.
QUIT
+OK Logging out, messages deleted.
以下の操作をしています。
-
USER
コマンドとPASS
コマンドでユーザ認証 - メールの一覧を
LIST
コマンドで取得 -
RETR
コマンドで1番のメールを受信 -
DELE
コマンドで1番のメールに削除フラグを立てる -
QUIT
コマンドで削除フラグを立てたメールの削除を実行し、セッションを切断
QUITコマンドを実行せずに接続を切断した場合は、DELEコマンドで指定したメールは削除されません。
Python で POP3 するサンプル
poplib は POP3 のコマンドとメソッドが1対1で実装されているので、POP3 の仕組みがわかっていれば、雰囲気でやっていけます。
以下は送信者(Fromヘッダ)に特定の文字列、例えば迷惑メールの送信者が含まれていた場合に DELE
コマンドで削除するスクリプトです。
ヘッダだけ受信して処理するため、普通にメールソフトで受信して削除するよりも高速にメールを削除することができます。
#!/usr/bin/python3
import poplib
import email
import email.header
# サーバに接続
cli = poplib.POP3('mail.example.com')
print('connected.')
# 認証
cli.user('jsaito@example.com')
cli.pass_('password')
print('logged in.')
# メールボックス内のメールの総数を取得
count = len(cli.list()[1])
print('found ' + str(count) + ' messages.')
deleted = 0
try:
for i in range(count):
no = i + 1
# TOPコマンドでヘッダだけ受信する
content = cli.top(no, 0)[1]
msg = email.message_from_bytes(b'\r\n'.join(content))
from_ = str(msg['From'])
# 送信者(Fromヘッダ)に特定の文字列が含まれていたらメールを削除
if from_.find('qq.com') > 0 or from_.find('163.com') > 0 or from_.find('sina.com') > 0:
print('From: ' + from_ + ' => DELE ' + str(deleted))
cli.dele(no)
deleted += 1
finally:
cli.quit() # 最後に必ず QUIT する
print(str(deleted) + ' messages deleted.')
quit()
は例外がスローされても必ず呼ばれるようにしておきます。
でないと、ものすごく大量のメール削除を走らせていて途中でエラーになった場合、QUITで削除が実行されず、最初からやり直しになってしまいます。
まとめ
POP3 プロトコルを Python の標準ライブラリの poplib で処理するサンプルを例示しました。
Python は近頃の Linux ディストロなら必ずインストールされているので、このような保守運用をサポートするプログラムをさくっと書けるのでよいですね。
以上、よろしくお願いします。