HOME | 備忘録 | 書き込む |
そこで、maildrop に振り分けフォルダーを渡す 簡単な python スクリプトを書きました。 このスクリプトは、標準入力からメールをうけとり、振り分け先フォルダーを標準出力に吐き出します。 maildrop はその結果をうけとり、それに基づいてメールを振り分けます。
このスクリプトでは、日本語に変換した Subject と他のヘッダー部分を、あらかじめ登録しておいた振り分けルールと比較することによって 振り分け先フォルダーを決めています。
drop_rules.py には、キーがヘッダ項目で、値が正規表現である辞書のリストが登録されています。
また、各振り分けルールの辞書にはヘッダー項目のほかに 'folder' というキーがあり、
ここの値が振り分け先フォルダーです。
例えば drop_rules.py の
6 行目は、
[drop_rules.py]
001: import re 002: 003: RULES = [ \ 004: {'Subject':re.compile(r'【楽天カード(通信|ニュース)】', re.I), 'From':re.compile(r'@mail\.rakuten-card\.co\.jp', re.I), 'folder':'INBOX.sale'},\ 005: {'Subject':re.compile(r'【出光カード(モール|まいどプラス)】', re.I), 'From':re.compile(r'confirm@ml\.idemitsucard\.com', re.I), 'folder':'INBOX.sale'},\ 006: {'Subject':re.compile(r'お年玉|キャンペーン|ボーナス|クリスマス|ポイント|off|ショッピング|ローン', re.I), 'From':re.compile(r'idemitsucard|rakuten-card|amazon|yahoo', re.I), 'folder':'INBOX.sale'},\ 007: {'Subject':re.compile(r'カード.?利用|請求|明細|引き落とし|注文|発送|パスワード|password|月.*料金', re.I), 'folder':'INBOX'}\ 008: ]
001: #!/usr/local/bin/python3.2 002: 003: ''' 004: The program writes the distination folder to sys.stdout for the e-mail read from sys.stdin 005: according to drop_rules.RULES which is a list of dictionaries containing header elements and regular expressions. 006: 007: The program is designed to be used with maildrop. 008: 009: The goal of this program is to deal with Japanese headers, 010: which maildrop cannot handle. 011: ''' 012: 013: 014: import email.parser, sys, email.header, drop_rules 015: 016: def get_folder(em, ls_rules): 017: sbj = decode_mime_header(em['Subject']) if em['Subject'] else '' 018: for h in ls_rules: 019: if all( em[k] and h[k].search(sbj if k=='Subject' else em[k]) for k in h if k!='folder') : 020: return h['folder'] 021: else: 022: return '*** No Idea ***' 023: 024: 025: def decode_mime_header(s0): 026: return ''.join( str(s, c or 'ascii') if isinstance(s, (bytes,)) else s for s,c in email.header.decode_header(s0) ) 027: 028: 029: def get_email(fp): 030: p=email.parser.BytesParser() 031: return p.parse(fp, True) 032: 033: 034: 035: 036: if __name__=='__main__': 037: sys.stdout.write( \ 038: get_folder(get_email(sys.stdin.detach()), \ 039: drop_rules.RULES))
[make_drop_rules.py]
001: #! /usr/local/bin/python3.2 002: 003: ''' 004: The program is to make a python code for e-mail filtering rules which is invoced from suggest_folder.py 005: from an input file that consisting of sets of [header elements] -- [regular expression] pairs and distination folders. 006: ''' 007: 008: 009: import re, py_compile, os.path, sys 010: 011: FIN='/home/takafumi/drop_rule/drop_rules.txt' 012: FOUT='/home/takafumi/bin/drop_rules.py' 013: 014: #FIN='drop_rules.txt' 015: #FOUT='drop_rules.py' 016: 017: RE_COL=re.compile(r'^[-\w]+:', re.ASCII) 018: RE_RECSEP = re.compile('([ \t]*\n){2,}') 019: 020: def make_a_record(s0): 021: return [ line for line in s0.splitlines() if RE_COL.search(line) ] 022: 023: 024: def get_records(s0): 025: return (rec for rec in ( make_a_record(s) for s in RE_RECSEP.split(s0) ) \ 026: if any(line.startswith('folder:') for line in rec) ) 027: 028: 029: def format_record(ls0): 030: return '{' + ', '.join(format_col(s) for s in ls0) +'}' 031: 032: 033: def format_col(s_col): 034: k,v=s_col.split(':', 1) 035: s_fmt="'{0}':'{1}'" if k=='folder' else "'{0}':re.compile(r'{1}', re.I)" 036: return s_fmt.format(k, v.strip()) 037: 038: 039: def format_rules(s0): 040: return \ 041: 'import re\n\nRULES = [ \\\n' + \ 042: ',\\\n'.join( format_record(rec) for rec in get_records(s0) ) + \ 043: '\\\n]\n' 044: 045: 046: def make_drop_rules(fname_in, fname_out): 047: with open(fname_out, 'w', encoding='utf8') as fout: 048: with open(fname_in, encoding='utf8') as fin: 049: fout.write(format_rules(fin.read())) 050: 051: py_compile.compile(fname_out) 052: 053: 054: if __name__=='__main__': 055: if (len(sys.argv)>1 and sys.argv[1]=='force') \ 056: or not os.path.isfile(FOUT) \ 057: or (os.path.getmtime(FOUT) < os.path.getmtime(FIN)): 058: make_drop_rules(FIN, FOUT)
[drop_rules.txt]
Subject:【楽天カード(通信|ニュース)】 From:@mail\.rakuten-card\.co\.jp folder:INBOX.sale Subject:【出光カード(モール|まいどプラス)】 From:confirm@ml\.idemitsucard\.com folder:INBOX.sale Subject:お年玉|キャンペーン|ボーナス|クリスマス|ポイント|off|ショッピング|ローン From:idemitsucard|rakuten-card|amazon|yahoo folder:INBOX.sale Subject:カード.?利用|請求|明細|引き落とし|注文|発送|パスワード|password|月.*料金 folder:INBOX
001: MAILDIR="/home/takafumi/Maildir/" 002: DEFAULT=$MAILDIR 003: NKF="/usr/local/bin/nkf" 004: NKF_OPTION="-Z -m -j" 005: WAKATI="/usr/local/bin/kakasi -w" 006: BOGOFILTER="/usr/local/bin/bogofilter" 007: BOGOFILTER_OPTION="-u -e -p" 008: FORMAT_HEADER="/home/takafumi/bin/format_header.py" 009: BOGOJP="${FORMAT_HEADER} | ${WAKATI} | ${BOGOFILTER} ${BOGOFILTER_OPTION}" 010: SENDMAIL="/usr/sbin/sendmail" 011: SUGGEST_FOLDER="/home/takafumi/bin/suggest_folder.py" 012: 013: xfilter "${BOGOJP}" 014: 015: if (/^X-Bogosity: Spam, tests=bogofilter/:h) 016: { 017: to "${MAILDIR}.Junk/" 018: } 019: 020: 021: if (/^Subject: Undelivered Mail Returned to Sender/:h) 022: { 023: to "${MAILDIR}" 024: } 025: 026: if (/^Return-Path: <(root|daemon)@www\.shido\.info>$/:h) 027: { 028: to "${MAILDIR}.log_of_shido2/" 029: } 030: 031: 032: 033: DIR = `${SUGGEST_FOLDER}` 034: if($DIR eq "INBOX") 035: { 036: to "${MAILDIR}" 037: } 038: if ($DIR=~/^INBOX/) 039: { 040: SUBDIR=substr($DIR, 5) 041: to "${MAILDIR}${SUBDIR}/" 042: } 043: 044: 045: if (/^From:\s*(.*)/:h) 046: { 047: FADDR=getaddr($MATCH1) 048: if (lookup($FADDR, "drop_rule/inbox.txt")) 049: { 050: to "${MAILDIR}" 051: } 052: if (lookup($FADDR, "drop_rule/sale.txt")) 053: { 054: to "${MAILDIR}.sale/" 055: } 056: if (lookup($FADDR, "drop_rule/magazines.txt")) 057: { 058: to "${MAILDIR}.magazines/" 059: } 060: } 061: 062: 063: if (/Return-Path:\s*(.*)/:h && lookup($MATCH1, "drop_rule/mailing_lists.txt")) 064: { 065: to "${MAILDIR}.mailing_lists/" 066: } 067: 068: to "${MAILDIR}" 069:
日本語の Subject を使って振り分けるようにしたところ、同じアドレスから来る重要なメールと宣伝用メールを 振り分けられるようになり、大変便利に使っています。 たとえば、注文の確認、発送の知らせ、カード利用の知らせなどが INBOX に振り分けられるので、宣伝用メールに埋もれてしまうことがなくなりました。
HOME | 備忘録 | 書き込む |