HOME Python 書き込む

Message Object から添付ファイルを取り出す


1. 初めに

この記事は、imaplib と email ライブラリーを使ったメールの処理 の続編です。
email をパースして生成する Message Object から添付ファイルを取り出す方法について述べます。

2. INBOX にある全ての添付画像ファイルを保存するスクリプト

簡単な例として、INBOX にある全てのメールを調べ、画像ファイルが添付されていれば それをまとめて保存するスクリプトを示します。

2.1. ソースコード

以下にソースコードを示します。

[img_from_mail.py]

001:   #!python
002:   
003:   '''to save all attached image files in a mailbox'''
004:   
005:   
006:   import imaplib, email.parser, email.header, os, os.path
007:   
008:   HOST='mail.a.org'
009:   USER='x'
010:   PW='q1!!!'
011:   
012:   MBOX='INBOX'
013:   
014:   IMG_DIR = 'img'
015:   
016:   
017:   def decode_mime_header(s0):
018:       '''decode a mime encoded header to get a string'''
019:       return ''.join( str(s, c or 'ascii') if isinstance(s, (bytes,)) else s  \
020:                        for s,c in email.header.decode_header(s0) )
021:   
022:   
023:   def is_attachment(obj):
024:       '''see if obj is an attachment'''
025:       s=obj['Content-Disposition']
026:       return s and s.startswith('attachment')
027:   
028:   
029:   def get_img_each(d_img, e):
030:       '''save attachments of a Message Object (e) in d_img'''
031:       if e.is_multipart():       # I
032:           for p in e.walk():
033:               if          (not p.is_multipart())             \
034:                       and is_attachment(p)                   \
035:                       and p.get_content_maintype() =='image':  # J
036:                   fname0 = p.get_filename()                    # K
037:                   if fname0:
038:                       fname=decode_mime_header(fname0)         # L
039:                       try:
040:                           with open(os.path.join(d_img, fname), 'wb' ) as f:  # M
041:                               f.write(p.get_payload(None, True))              # N
042:                       except:
043:                           print('cannot save ' + fname)
044:                       print(fname)
045:                   else:
046:                       print('cannot get filename')
047:   
048:   
049:   def get_imgs(con, mbox, d_img):
050:       '''save attachments of all emails in mbox'''
051:       con.select(mbox)   # D
052:       p=email.parser.BytesParser()    # E
053:       _type, _data = con.search(None,  'ALL')   # F
054:   
055:       for num in _data[0].split():
056:           type, data = con.fetch(num, '(RFC822)')      # G
057:           get_img_each(d_img, p.parsebytes(data[0][1]))  # H
058:   
059:   
060:   
061:   
062:   if __name__=='__main__':
063:   
064:       if not os.path.isdir(IMG_DIR):
065:           os.mkdir(IMG_DIR)
066:   
067:       con = imaplib.IMAP4_SSL(HOST)      # A
068:       con.login(USER, PW)                # B
069:   
070:       get_imgs(con, MBOX, IMG_DIR)       # C
071:   
072:       con.close()
073:       con.logout()
サーバーに接続 (A) してログインした (B) 後、 get_imgs() 関数で、INBOX にある全ての添付画像ファイルを取得します (C)。

get_imgs() 関数では、 まず、INBOX に入り (D)、それから、ByteParser() のインスタンスを作成します (E)。 その後、INBOX にある全てのメールを検索します (F)。
個々のメールの全文を取得し (G)、パースして Message Object にして、 get_img_each() 関数に渡します。(H)

get_img_each() 関数 は個々の Message Object から添付されている画像ファイルを取り出して 保存する関数です。 引数で渡された Message Object がマルチパート (添付ファイルがあるときは必然的にマルチパートになる) のとき (I) は Message Object の walk() メソッドで個々のパーツについて調べていきます。 もし、そのパーツがシングルパートかつ、添付ファイルかつ、maintypeimage ならば (J)、 ファイル名を取得し (K)、それをデコードします (L)。 そして、そのファイル名で指定されたディレクトリにファイルを開き (M)、 内容を保存します (N)。

ファイル名の取得には get_filename() メソッドを 内容の取得には get_payload() メソッドを使います。

2.2. 実行結果

コンソールに次のように出力され、画像ファイルが指定したディレクトリ (img) に保存されます。

なお、スクリプト内で、ホスト名、ユーザー名、パスワード (8--10 行) は架空のものに変えてあります。 実際に試すときはそれらを実在するものに書き換えてから実行してください。

Z:\doc\monthly\12-03>d:\python32\python.exe img_from_mail.py
IMAG0894.jpg
IMAG0895.jpg
IMAG0904.jpg
IMAG0903.jpg
IMAG0902.jpg
IMAG0901.jpg
IMAG0900.jpg
IMAG0899.jpg
IMAG0898.jpg
IMAG0897.jpg
IMAG0896.jpg
IMAG0907.jpg
IMAG0906.jpg
IMAG0905.jpg
IMAG0908.jpg
IMAG0910.jpg
IMAG0911.jpg
IMAG0914.jpg
IMAG0915.jpg
IMAG0916.jpg

Z:\doc\monthly\12-03>ls img
IMAG0894.jpg  IMAG0898.jpg  IMAG0902.jpg  IMAG0906.jpg  IMAG0911.jpg
IMAG0895.jpg  IMAG0899.jpg  IMAG0903.jpg  IMAG0907.jpg  IMAG0914.jpg
IMAG0896.jpg  IMAG0900.jpg  IMAG0904.jpg  IMAG0908.jpg  IMAG0915.jpg
IMAG0897.jpg  IMAG0901.jpg  IMAG0905.jpg  IMAG0910.jpg  IMAG0916.jpg

Z:\doc\monthly\12-03>

3. 終わりに

Message Object の扱いについて詳しくは Python ドキュメントの 18.1.1. email: Representing an email message を見てください。 実は、日誌用スクリプトを紹介する予定だったのですが、 添付ファイルの取り扱いを除いて imaplib と email ライブラリーを使ったメールの処理 と重複するので、ここでは添付ファイルの取り扱いについてだけ述べました。