Google Groups 上的邮件列表可以根据管理员的设置自动添加在邮件主题前添加指定的字符串。对于 mutt,固定的字符串没什么,但当这个添加的字符串不断地变化呢?比如这个字符串设置成[vim-cn:%d]
,%d
会被邮件的序号所取代,于是每封邮件都有了不同主题。(对于回复邮件,按 RFC 5322 3.6.5 节的意思,应当将开头的一个Re:
不予考虑。)
这样的邮件会话,mutt 一看,哎呀,会话中出现了新的主题,得显示一下啦。于是,本来通常情况下一个会话只会显示一次的邮件主题,在添加了邮件序号后变成了N个。对比下图中黄线上方和下方的区别。
本来呢,vim-cn 列表是下边那个样子的。最近觉得 vim-cn 的邮件多了起来,看起来眼烦,正好有管理权限,就去把%d
删掉了。可谁知我才收到几封不带序号的 vim-cn 邮件呢,python-cn 却开始加序号了,不知道管理员是不是想看看第20万封邮件是谁发的。唉,既然改变不了那个列表的设置,那么就改变本地的邮件处理好了。
在开始使用 mutt 等工具的时候,我一直是把 procmail 当成邮件分发和过滤工具的。如今需要它来修改邮件了,语法还不会呢。另外它的示例中大多是 formail 工具,但我实在不想再学一种语法晦涩的工具了,于是自己搞。本来觉得挺简单的,一句 sed 就能搞定的东西,等真正查看邮件源码时才发现,远没有想像的那么简单!
Subject: =?GB2312?B?W0NQeVVHOjE4MzI0OV0gcHl0aG9uIL+qt6LN+NKz087Pt7rNyta7+rbL?=
=?GB2312?B?zfjC59POz7e+rdHpx/PW+g==?=
第一,它编码过了;第二,它分成了多行。哦还有第三,邮件正文即使出现也不要处理,不然我这文章发过去不是变了样么?
后两点还好,awk 可以搞定,可是这编码不是那么容易呢,于是用上了 Python。既然 Python 3.3 已经发布,所以试了试新的yield from
语法。反正我不认为我会需要在只有 Python 3.2 或者更早的系统上使用这个脚本。
#!/usr/bin/env python3
# vim:fileencoding=utf-8
import sys
import re
from email import header
subject_seq = re.compile(r'''((?:..[::]\s?)? # Re、回复等
\[[^:]+)
:\d+ # 要删除的序号''', re.X)
def stripSeq(input):
subject = None
while True:
l = next(input)
if l.startswith('Subject: '):
# Subject appears
subject = l
continue
elif subject and l[0] in ' \t':
# Subject continues
subject += l
elif subject:
# Subject ends
s = subject[9:]
h = header.decode_header(s)
assert len(h) == 1, 'unexpected subject line: ' + s
s, enc = h[0]
if isinstance(s, bytes):
s = s.decode(enc)
m = subject_seq.match(s)
if not m:
yield subject
else:
s = m.group(1) + s[m.end():]
yield 'Subject: ' + header.Header(s, 'utf-8').encode() + '\n'
subject = None
yield l
elif l.strip() == '':
# mail body
yield from input
else:
yield l
if __name__ == '__main__':
sys.stdout.writelines(stripSeq(iter(sys.stdin)))
Github 上的地址。
procmail 的规则如下,参考了 Stackoverflow 的这个回答。
:0 fw
| ~/scripts/python/pyexe/procmail.py