稼働中

(v_07)Python メールの受信 popLib

popLib

Pythonでいろいろ試してみたことを記載しています。※開発環境はThonnyを使用しています。
popLibモジュールを使ってメールの受信を試しました。
popLibモジュールはクラス POP3(POP:Post Office Protocol)を定義しているそうです。イメージ的にはメーラーを使ってメールサーバーからメールをダウンロードするような感じです。

class poplib

以下で初期化します。


class poplib.POP3(host, port=POP3_PORT[, timeout])
port が省略されると、POP3標準のポート(110)が使われます。
class poplib.POP3_SSL(host, port=POP3_SSL_PORT, *, timeout=None, context=None)
port が指定されていない場合、 POP3-over-SSL 標準の 995 番ポートが使われます。

自分が使っている受信メールサーバー名、ポート番号に合わして初期化します。
※udat[0]は受信メールサーバー名 (例:’pop.***.ne.jp’)


M=poplib.POP3(udat[0], port=110, timeout=10)      #port=110
M=poplib.POP3_SSL(udat[0], port=995, timeout=10)  #port=995 SSL 

私の場合は、現在のメーラーの設定を参照してpoplib.POP3_SSLを使いました。
ちなみに、poplib.POP3でも動作確認すると問題なさそうな感じでした。

使い方

初期化からログイン、ログオフを確認してみます。※ThonnyのShellで動作確認しています。


>>> M=poplib.POP3_SSL(udat[0], port=995, timeout=10)
>>> M
<poplib.POP3_SSL object at 0x03AF42B0>

ユーザー名を送ります。※udat[1]はユーザーアカウント名 (例:’abcd@****.ne.jp”)


>>> M.user(udat[1])     # udat[1]:'user_account'
b'+OK'

パスワードを送ります。※udat[2]はパスワード


>>> M.pass_(udat[2])    # udat[2]:'Passwords'
b'+OK Logged in.'       # ログインできたようです

サインオフします。


>>> M.quit()
b'+OK Logging out.'     # ログアウトできたようです

以下はログイン後の各動作の確認です。

メールボックスのメール数とmailbox sizeを返します。


>>> M.stat()
(6, 28291)          # 6通、28291bytes

受信メールのリストを(応答,[メール番号とサイズ,・・],octets)で返します。


>>> M.list()
(b'+OK 6 messages:', [b'1 8974', b'2 4294', b'3 3913', b'4 3639', b'5 5145',
 b'6 2326'], 48)
>>> 

メッセージに削除のためのフラグを立てます。quit()が実行されると削除されます。


>>> M.dele(6)               #番号6を削除のフラグを付けます
b'+OK Marked to be deleted.'

サインオフします。


>>> M.quit()
b'+OK Logging out, messages deleted.'# 削除フラグ付が削除された

受信ボックスのリストを再確認します。


>>> M.list()
(b'+OK 5 messages:', [b'1 8974', b'2 4294', b'3 3913', b'4 3639', 
b'5 5145'], 40)     # (6)は削除されています。
>>> 

指定した受信メールの内容(メッセージ)を返します。((応答, [‘行’,’行’,…], octets)で返ります。


>>> M.retr(5)
大幅に抜粋しています。メッセージの内容は以下のようになっていました。大半は読めませんでした。
(b'+OK 5145 octets', [b'Return-Path: <information@ma.email.aeon.co.jp>',
 省略
 b'Content-Type: text/plain;', b'\tcharset="utf-8"', b'Content-Transfer-Encoding: 8bit',
 b'', b'\xe2\x80\xbb\xe6\x9c\xac\xe3\x83\xa1\xe3\x83\xbc\xe3\x83\xab\xe3\x81\xaf\xe5\xa4
\xa7\xe5\x88\x87\xe3\x81\xaa\xe3\x81\x8a\xe7\x9f\xa5\xe3\x82\x89\xe3\x81\x9b\xe3\x81\xae
\xe3\x81\x9f\xe3\x82\x81\xe3\x80\x81\xe3\x83\xa1\xe3\x83\xbc\xe3\x83\xab\xe9\x85\x8d\xe4
\xbf\xa1\xe3\x81\xae\xe8\xa8\xb1\xe8\xab\xbe\xe3\x82\x92\xe3\x81\x84\xe3\x81\x9f\xe3\x81
\xa0\xe3\x81\x84\xe3\x81\xa6\xe3\x81\x84\xe3\x81\xaa\xe3\x81\x84\xe6\x96\xb9\xe3\x81\xab
\xe3\x82\x82\xe9\x85\x8d\xe4\xbf\xa1\xe3\x81\x97\xe3\x81\xa6\xe3\x81\x8a\xe3\x82\x8a\xe3
\x81\xbe\xe3\x81\x99\xe3\x80\x82', b'',
  省略 
 b'\xe3\x81\x84\xe3\x81\xa4\xe3\x82\x82\xe3\x82\xa4\xe3\x82\xaa\xe3\x83\xb3\xe3\x83\x9e
\xe3\x83\xbc\xe3\x82\xaf\xe3\x81\xae\xe3\x82\xab\xe3\x83\xbc\xe3\x83\x89\xe3\x82\x92\xe3
\x81\x94\xe6\x84\x9b\xe9\xa1\xa7\xe3\x81\x84\xe3\x81\x9f\xe3\x81\xa0\xe3\x81\x8d\xe3\x81
\x82\xe3\x82\x8a\xe3\x81\x8c\xe3\x81\xa8\xe3\x81\x86\xe3\x81\x94\xe3\x81\x96\xe3\x81\x84
\xe3\x81\xbe\xe3\x81\x99\xe3\x80\x82', b'',, b'\xe3\x80\x90\xe5\xa4\x89\xe6\x9b\xb4\xe7
\x82\xb9\xe3\x80\x91', b'\xe3\x…

一行づづ表示して見ます。以下のよう見やすくなりましたが読めないです。


>>> g_msg=M.retr(2)
>>> msg=g_msg[1]    #(応答, ['行','行',...], octets)の ['行','行',...]の部分
>>> m=len(msg)
>>> for i in range(m):
    print(msg[i])

M.retr(2)
省略
g_msg=M.retr(2)_2

読めないので試しに


msg[i].decode()

にしてみました。
From:、Subject:など読めない部分もありますが本文は読めました。


>>> g_msg=M.retr(5)
>>> msg=g_msg[1]    #(応答, ['行','行',...], octets)の ['行','行',...]の部分
>>> m=len(msg)
>>> for i in range(m):
    print(msg[i].decode())      # decode

Return-Path: <information@ma.email.aeon.co.jp>
省略
From: =?utf-8?B?44Kk44Kq44Oz44OV44Kj44OK44Oz44K344Oj44Or44K144O844OT44K55q
Cq5byP5Lya56S+?= <information@ma.email.aeon.co.jp>
Subject: =?utf-8?B?44Kk44Kq44Oz44K344ON44Oe54m55Yil6ZGR6LOe5YSq5b6F?=
 =?utf-8?B?44Gu54m55YW444Oq44OL44Ol44O844Ki44Or44Gr44Gk44GE44Gm?=
省略
MIME-Version: 1.0
X-mailer: nlserver, Build 6.7.0
Message-ID: <NM615C1EE87014602A2acsprd@ma.email.aeon.co.jp>
Content-Type: text/plain;
	charset="utf-8"
Content-Transfer-Encoding: 8bit

※本メールは大切なお知らせのため、メール配信の許諾をいただいていない方にも配信しております。

いつもイオンマークのカードをご愛顧いただきありがとうございます。
省略
※スマートフォン限定のサービスとなります。

──────────
カード発行元:株式会社イオン銀行
業務受託会社:イオンフィナンシャルサービス株式会社
http://t.ma.aeon.co.jp/r/?id=t26c80fdd,17e1ccf7,cff6dd3
──────────
>>> 

調べてみました。
From:、Subject:のような’=?’で始まり’?=’で終わる形式は「MINE(Multipurpose Internet Mail Extensions)」と言うそうです。
MIMEエンコードは=?<文字コード>?<エンコード方式>?<エンコードされた内容>?=の形式で記載するそうです。
エンコード方式は’B’ならbase64、’Q’ならquoted-printableだそうです。
上記の例では’B’なのでbase64になるようです。

上記の本文は
charset=”utf-8″, Content-Transfer-Encoding: 8bitだったのでdecode()だけで読めたようです。

他のメールなど確認してみるとエンコードには、
‘Content-Transfer-Encoding: quoted-printable’
‘Content-Transfer-Encoding: base64′
また、文字コードには
charset=’utf-8′
charset=’iso-2022-jp’
がありました。別の機会に試したいと思います。

スクリプトの例

以下はメールデータを得るまでの一連の処理をまとめた例です。


#!/usr/bin/env python
# -*- coding: utf-8 -*-
import poplib
udat=[' ']*3            #['POP server','user_account','Passwords']
#user data
udat[0]='****.****.jp'          #'POP server'
udat[1]='****@*****.ne.jp'      #'user_account'
udat[2]='*********'             #'Passwords'


#M=poplib.POP3(udat[0], port=110, timeout=10)     #udat[0]:''POP server'
M=poplib.POP3_SSL(udat[0], port=995, timeout=10)  #udat[0]:''POP server'
M.user(udat[1])   #udat[1]:'user_account'
M.pass_(udat[2])  #udat[2]:'Passwords'

rs=M.list()
print('List',rs)

which=int(input('Open email num ? = '))    #INPUT
print('')

#g_msg[1]がメール本文になります。
g_msg=M.retr(which)     #(response, ['line', ...], octets)
#print(g_msg)

# sighn off
M.quit()

実行結果

以下は実行した結果例です。※Thonnyのshellに表示されます。
poplib_3

まとめ

popLibモジュールを使って受信メールのデータ確認をしました。
データの確認だけなら簡単にできました。
しかし、データを可読するには各文字コード、エンコードで変換する必要があるようです。
別の機会に試したいと思います。