HOME | Python | 書き込む |
紫藤は、領収書のない支出の記録と、体重の記録に e-mail を使っています。 以下にそれらのスクリプトを例に挙げながら、imaplib と email ライブラリのユーティリティを 簡単に解説します。
Python 3.2.2 (default, Sep 4 2011, 09:51:08) [MSC v.1500 32 bit (Intel)] on win 32 Type "help", "copyright", "credits" or "license" for more information. >>> import imaplib >>> c=imaplib.IMAP4_SSL('gmail.com') (オブジェクトの作成) >>> c.login('jhon_smith', '__hello-world__') (ログイン) ('OK', [b'[CAPABILITY IMAP4rev1 LITERAL+ SASL-IR LOGIN-REFERRALS ID ENABLE SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS MULTIAPPEND UNSELECT IDLE CHILDREN NA MESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCH RES WITHIN CONTEXT=SEARCH LIST-STATUS] Logged in']) >>> c.select('INBOX') (メールボックスの選択) ('OK', [b'1106']) >>> c.search(None, '(SENTON "10-Nov-2011")') (メールの検索。ここでは 10-Nov-2011 に受信したメールを検索している。) ('OK', [b'1102 1103 1104 1105']) >>> c.fetch(b'1102', '(RFC822.HEADER)') (1102 の番号のメールを取得) ('OK', [(b'1102 (RFC822.HEADER {1106}', b'Return-Path: <20111110020231989c6dfa88 e44e28b208f5d27dad271b@bounces.amazon.com>\r\nX-Original-To: jhon_smith@gmail.com \r\nDelivered-To: jhon_smith@gmail.com\r\nReceived: from smtp-out-188-18.amazon.c om (smtp-out-188-18.amazon.com [207.171.188.18])\r\n\tby gmail.com (Postfix ) with ESMTP id 8E231694048\r\n\tfor <jhon_smith@gmail.com>; Thu, 10 Nov 2011 11: 02:42 +0900 (JST)\r\nDate: Thu, 10 Nov 2011 02:02:39 +0000 (UTC)\r\nFrom: "Amazo n.co.jp" <ship-confirm@amazon.co.jp>\r\nReply-To: "ship-confirm@amazon.co.jp" <s hip-confirm@amazon.co.jp>\r\nTo: "jhon_smith@gmail.com" <jhon_smith@gmail.com>\r\n Message-ID: <urn.correios.msg.20111110020231989c6dfa88e44e28b208f5d27dad271b@132 0890559990.rte-svc-fe-31001.sea31.amazon.com>\r\nSubject: =?ISO-2022-JP?Q?Amazon .co.jp_=1B$B$4CmJ8$NH/Aw=1B(B_(503-7809728-0738205)?=\r\nMIME-Version: 1.0\r\nCo ntent-Type: text/plain; charset=ISO-2022-JP\r\nContent-Transfer-Encoding: 7bit\r \nBounces-to: 20111110020231989c6dfa88e44e28b208f5d27dad271b@bounces.amazon.com\ r\nX-AMAZON-MAIL-RELAY-TYPE: notification\r\nX-AMAZON-RTE-VERSION: 2.0\r\nX-Bogo sity: Ham, tests=bogofilter, spamicity=0.000000, version=1.0.2\r\n\r\n'), b')']) >>> c.close() (クローズ) ('OK', [b'Close completed.']) >>> c.logout() (ログアウト) ('BYE', [b'Logging out'])メールの検索は search() メソッドで行います。 このメソッドの使い方は 20.13. imaplib - IMAP4 protocol client、 また IMAP4 の検索条件は IMAP4のSEARCH条件の一覧 を見てください。
メールの取得は fetch() メソッドで行います。 引数に、メールの番号と、取得する情報を指定します。 取得する情報については、 IMAP4のFETCHオプションの一覧 を参照してください。
def decode_mime_header(s0): return ''.join([str(s,c) if c else s for s,c in email.header.decode_header(s0)])
>>> from email.utils import parsedate >>> parsedate('Sun, 13 Nov 2011 00:24:16 +0900 (JST)') (2011, 11, 13, 0, 24, 16, 0, 1, -1) >>>
01: #! /usr/bin/python3 02: import imaplib, email.parser, email.header, email.utils, time, re 03: 04: HOST='mail.gmail.com' 05: USER='jhon_smith_weight' 06: PW='__hello-world__' 07: 08: MBOX='INBOX' 09: FROM_EMAIL='jhon_smith@gmail.com' 10: 11: #FOUT='/home/jhon/weight/weight.dat' 12: FOUT='weight.dat' 13: 14: def fetch_headers(host, user, passwd, mbox, _from): 15: 16: con = imaplib.IMAP4_SSL(host) 17: con.login(user,passwd) 18: con.select(mbox) 19: p=email.parser.HeaderParser() 20: typ, data = con.search(None, 'UNSEEN', '(FROM "{0}")'.format(_from)) 21: 22: if not data[0]: return 23: 24: def _parse(num): 25: typ, data = con.fetch(num, '(RFC822)') 26: con.store(num, '+FLAGS', '\\Seen') 27: return p.parsestr(str(data[0][1], 'ascii')) 28: 29: ls = [ _parse(num) for num in data[0].split() ] 30: con.expunge() 31: con.close() 32: con.logout() 33: return ls 34: 35: def extract_weight_data(fout, ls0): 36: 37: re_d = re.compile(r'^\d{2}(\.\d)? +\d{2}(\.\d)?$') 38: 39: def wconv(e): 40: dt = email.utils.parsedate(e['Date']) 41: dat=''.join([str(s,c) if c else s for s,c in email.header.decode_header(e['Subject'])]) 42: return "{flag}{year}/{month}/{date} {sec} {dat}\n".format( \ 43: flag='' if re_d.match(dat) else '# ', \ 44: year=dt[0], \ 45: month=dt[1], \ 46: date=dt[2], \ 47: sec=time.mktime(dt), \ 48: dat=dat 49: ) 50: 51: if ls0: 52: with open(fout, 'a', encoding='ascii') as f: 53: f.write(''.join([wconv(e) for e in ls0])) 54: 55: 56: 57: 58: if __name__=='__main__': 59: extract_weight_data(FOUT, fetch_headers(HOST, USER, PW, MBOX, FROM_EMAIL))以下が集計したデータの例です。
#date, sec, weight(kg), fat contents(%) 2011/11/5 1320446330.0 72.8 23.2 2011/11/6 1320530436.0 73.7 23.8 2011/11/7 1320616449.0 74.0 23.6 2011/11/8 1320701737.0 73.3 23.8 2011/11/9 1320789021.0 73.5 23.3 2011/11/10 1320875695.0 72.3 23.3 2011/11/11 1320962043.0 73.0 23.6 2011/11/12 1321048826.0 71.8 23.6 2011/11/13 1321134392.0 71.8 23.2 2011/11/14 1321220334.0 71.5 23.1 2011/11/15 1321306494.0 72.1 23.1
01: #! /usr/bin/python3 02: import imaplib, email.parser, email.header, email.utils, re, datetime, os.path 03: 04: HOST='mail.gmail.com' 05: USER='jhon_smith_expence' 06: PW='__hello-world__' 07: 08: MBOX='INBOX' 09: FROM_EMAIL='jhon_smith@gmail.com' 10: 11: OUTDIR='' 12: #OUTDIR='/home/jhon/expence/' 13: 14: 15: 16: def this_and_last_month(): 17: dt = datetime.date.today() 18: y, m =dt.year, dt.month 19: y_last, m_last = (y-1, 12) if m==1 else (y, m-1) 20: return datetime.date(y,m,1), datetime.date(y_last, m_last, 1) 21: 22: 23: def fetch_headers(host, user, passwd, mbox, _from, since_date, before_date): 24: 25: con = imaplib.IMAP4_SSL(host) 26: con.login(user,passwd) 27: con.select(mbox) 28: p=email.parser.HeaderParser() 29: 30: typ, data = con.search(None, \ 31: '(FROM "{0}")'.format(_from), \ 32: since_date.strftime('(SENTSINCE "1-%b-%Y")'), \ 33: before_date.strftime('(SENTBEFORE "1-%b-%Y")')) 34: 35: if not data[0]: return 36: 37: def _parse(num): 38: typ, data = con.fetch(num, '(RFC822.HEADER)') 39: con.store(num, '+FLAGS', '\\Seen') 40: return p.parsestr(str(data[0][1], 'ascii')) 41: 42: ls = [ _parse(num) for num in data[0].split() ] 43: con.expunge() 44: con.close() 45: con.logout() 46: return ls 47: 48: def decode_mime_header(s0): 49: return ''.join([str(s,c) if c else s for s,c in email.header.decode_header(s0)]) 50: 51: def calc_total(ls): 52: ls1=[decode_mime_header(e['Subject']).split()[0] for e in ls] 53: return sum([int(x) for x in ls1 if x.isdigit()]) 54: 55: 56: 57: 58: def write_keihi(since_date,ls): 59: 60: def _each(e): 61: return '\n'.join(['{0}: {1}'.format(x, decode_mime_header(e[x])) for x \ 62: in ['Message-Id', 'Date', 'Subject']]) 63: 64: fout = os.path.join(OUTDIR, since_date.strftime('keihi%y%m.txt')) 65: with open(fout, 'w') as f: 66: f.write(since_date.strftime('payment for miscs in %b %Y\n\n')) 67: f.write('\n\n'.join([_each(e) for e in ls])) 68: f.write('\n\n\n---------------------------\ntotal: {0}\n'.format(calc_total(ls))) 69: 70: 71: if __name__=='__main__': 72: before_date, since_date = this_and_last_month() 73: ls=fetch_headers(HOST, USER, PW, MBOX, FROM_EMAIL, since_date, before_date) 74: if ls: 75: write_keihi(since_date, ls)以下が出力ファイルの例です。
payment for miscs in Sep 2011 Message-Id: <20110901060053.924E5694049@gmail.com> Date: Thu, 01 Sep 2011 15:00:51 +0900 Subject: 1000 昼食 Message-Id: <20110906043215.CA87F694049@gmail.com> Date: Tue, 06 Sep 2011 13:32:14 +0900 Subject: 1000 昼食 Message-Id: <20110928041038.1EB44694049@gmail.com> Date: Wed, 28 Sep 2011 13:10:35 +0900 Subject: 800 昼食 Message-Id: <20110926224824.06949694049@gmail.com> Date: Tue, 27 Sep 2011 07:48:21 +0900 Subject: 800 昼食 Message-Id: <20110924041729.89CD4694049@gmail.com> Date: Sat, 24 Sep 2011 13:17:27 +0900 Subject: 130 コーラ Message-Id: <20110923042115.17A45694049@gmail.com> Date: Fri, 23 Sep 2011 13:21:13 +0900 Subject: 220 切符 ----------------------------- total: 5000
また、ごく簡単なスクリプトでデータの集計や加工ができます。
さらに、http を使ったデータの送信と比較して、 web ページや専用クライアントを作成する必要もなく、認証もメール送信サーバーの認証機能が使えるので、 準備に手間がかからず、気軽に始められます。
HOME | Python | 書き込む |