13
22

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ユニキャストAdvent Calendar 2017

Day 1

Python の標準ライブラリで POP3 を操ってみる

Last updated at Posted at 2017-12-01

これは ユニキャストアドベントカレンダー の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 ディストロなら必ずインストールされているので、このような保守運用をサポートするプログラムをさくっと書けるのでよいですね。

以上、よろしくお願いします。

13
22
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
13
22

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?