1. 起缘
我是被逼出来的...
最开始, 我只是拿 txt2tags 写写文档, 在 Gmail 的 Web 界面看看 CPyUG 而已.
工作中的邮件我先是使用的 Thunderbird 来处理, 虽然我觉得它的搜索功能很难用, 但是收发功能正常也就算了. 后来不知道从什么时候开始, 这东西时不时会出现无法发信的问题, 就是报一个网络错误, 也没有其它信息. 我开始想是不是公司的邮件服务器有问题, 但是同事些都好好的, 哪怕同样是用 Thunderbird 的也没有问题. 我也把问题反映到 ES 那里, 他们对此也无解.
郁闷的是, Thunderbird 不能发信的时候, 我直接 telnet , 做完一个 SMTP 交互过程是没有任何问题的.
不能发信的问题有时非常影响工作, 没有办法, 我换了一个叫 claws-mail 的客户端. 发信是没有问题了, 但是它对邮件格式的富文本渲染好像很有问题. 而且它虽然可以让我使用 vim 来编写邮件, 但是因为有其它操作, 整个过程也感觉不是很顺畅.
没办法, 我开始考虑重新使用 mutt , 这个我曾经折腾过一阵放弃的东西. 与过去不同的是, 对于邮件, 现在我很熟悉. 这也使得我可以只关注使用 mutt 管理部分的功能, 收取与发送不使用它, 可能这样真给我少了很多麻烦.
下面我会挨着介绍相关的工具.
整套东西不是我一开始就想做成这样的, 而是逐渐地, 在有一个想法之后, 会发现, 唉, 我可以把另外一个工具整合进来. 为了舒服的目的, 就一直折腾过来了.
每部分介绍之后, 相关代码我会放到 gist 上, 它们只算是代码片段, 对我而言不算是项目, 只会随需随手修改, 很长一段时间内不会作为项目去统筹维护的.
题目虽然是说"邮件客户端", 但是其实邮件只是一种载体, 只是使用这种形式去处理你的信息, 与信息本身是不是邮件没有关系. 后面会示例说明这点.
2. 一个标记语言工具 txt2tags
标记语言工具, 可能大部分人对 markdown 会比较熟悉. 我当初也考虑过 markdown , 但是, 因为它原本没有对表格的支持, 所以我开始考虑其它的类似工具.
其实在考虑这类标记语言之前, 我很长一段时间在固执地尝试将 LaTeX 作为日常工具使用, 最后在找到一个使用 Lisp 写成的 LaTeX -> HTML
工具之后, 对于最重要的转换到 HTML 这部分功能算是能很好地控制了. 但是长期的折腾, 也使我意识到, 我平时需要写的东西, 真费不着扛上 LaTeX 这门超级大炮, 写起来比较累. 而它最大的优势, 各种科学记号与漂亮的纸质输出品质大部分时间我都用不着.
一个简单的工具, 能得到可控的 HTML 输出, 这就是我需要的. 我知道这类工具实现起来不难, 同时我更清楚, 肯定有人已经做过了, 只是我还没有找到. 于是, 后来单文件的 txt2tags 自然而然成了最合适的选择.
txt2tags 的官网在 http://txt2tags.org/ , 它源文件只有一个文件, 并且支持多种格式的输出.
放弃 LaTeX 选择 txt2tags 之后, 我很留恋那些漂亮的数学公式, 好在 MathJaxhttp://www.mathjax.org/ 这个项目真是超级牛 X , 而且整合也很容易.
这里先说一下, MathJax 是使用 js 处理公式的. 如果需要, 本地编译 txt2tags 时, 可以把这些 LaTeX 代码单独抽出来处理, 最后以图片代替结果, 以前我尝试过, 见http://zouyesheng.blogspot.com/2009/04/2.html .
最开始, 我为了得到我期望中的 HTML 格式, 开始修改 txt2tags 的代码.
因为之前的一些折腾经验, 以及为了适应邮件需要的一种预感, 我直接放弃外链 CSS 文件, 而是直接在源码中修改各种标签, 在里面嵌入 style
属性以控制格式.
刚开始的时候, 还是使用的 prettyprint 在页面中通过 js 做代码高亮. 我只是扩展了 txt2tags , 让它可以在源码中支持标记语言类型. 后来涉及邮件内容之后, js 实现高亮的方法就没法用了, 而且 prettyprint 的高亮效果也不是十分好看, 于是我尝试更大程度地修改 txt2tags 源码, 使用pygments 输出格式加工后的 HTML . 我达到了我的目的. 当然, 后来我还给我的 txt2tags 添加了对 gnuplot 代码的支持, 让其输出 svg 嵌入到 HTML 中. 这对我记录一些课程的笔记很有用.
代码:
- 我修改过的 txt2tags https://gist.github.com/AceFantasy/7870470
3. 一个编辑器 vim
编辑器部分就不说太多了. vim 的作用, 主要是两个:
- 在 mutt 中作为编辑器写内容.
- 为 txt2tags 语法配置各种方便的键绑定.
当然, 也会使用 F2 编译 txt2tags , 然后使用 F3 在 firefox 中浏览结果.
代码:
4. 一个邮件客户端 mutt
使用 mutt 的原因开头说过了. 我只使用它管理邮件, 发送和收取我都使用自己做的工具完成, 这样做很有趣的.
其实 mutt 本身的配置内容并不多, 但我强烈建议打一个 patch , 让其可以支持边栏分类的显示.
mutt 配置好之后, 在指定目录创建需要的分类目录, 使用自己的工具收到邮件, 或其它信息时, 只要把对应的内容做成 RFC 822 的那种格式, 就叫 eml 格式吧, 直接往对应目录下的 new
目录一扔就可以了. 剩下的就可以交给 mutt 来处理了.
发送邮件也简单, 直接配置调用一个命令行工具, 剩下的全在工具里完成, mutt 也不需要做其它事.
这里另外要做的一件事, 就是对公司 Active Directory 中, 联系人的查询. 这个使用 Python 实现 LDAP 的交互也很容易.
代码:
- mutt 配置文件 https://gist.github.com/AceFantasy/7870763
- LDAP 查询 https://gist.github.com/AceFantasy/7870791
5. 获取信息
这里我都说"获取信息", 没说"获取邮件"了. 最开始我是只想处理邮件的, 后来发现要处理其它需要交互的内容也不费什么事.
不同之处只在于, 获取邮件时, 是使用 POP 直接获取一封邮件内容, 放到目录下就完事. 而获取其它网站中的内容的话, 需要做"抓取"操作, 并且获取到的是 HTML 的文本, 还需要加工拼成一封信才能放入指定目录, 让 mutt 处理.
额外说一下, 这里需要使用邮件中的 Message-ID 这个头来做相关信息的传递. 这部分信息最重要的, 是在你回复这封信时, 知道原始来源, 这样后续你才能正确做出处理. 比如你从一个 Discuz论坛抓取了一条信息, 当你想回复它时, 你要知道是哪个论坛, 信息的 forum_id
, thread_id
, post_id
是什么吧.
至于实现 POP 客户端部分, 使用 Tornado 也很容易做.
代码:
- 获取信息文件, 包括抓取 Discuz https://gist.github.com/AceFantasy/7870934
- Tornado 实现的简单 POP 客户端https://gist.github.com/AceFantasy/7870960
6. 发出信息
这部分是比较麻烦一些. 涉及邮件解析, 邮件拼装, 及 txt2tags 对各种格式的转换.
从流程上来说, 当 mutt 调用指定工具, 准备发信时, 我们的这个工具得到的是一封邮件, 及相应的投递信息. 但是如何处理这个信息, 却完全在我们工具的控制当中.
行为上来说, 我们决定是通过 SMTP 交互来发出一个邮件, 还是通过新浪微博的 SSO 授权登录到一个论坛, 通过一个 HTTP 的 POST 请求来发一个贴子.
内容上来说, 我们从邮件中解析得到的只是纯文本内容. 自然地, 可以是使用 vim 写出的 txt2tags 格式的纯文本内容. 那么, 如果是发出一封邮件, 我们可以把 txt2tags 编译成 HTML 格式的文本, 然后重新拼成 multipart/alternative
的邮件. 如果我们是准备发一个贴子, 我们把 txt2tags 编译成 bbcode 格式. 附件也可以类似处理, 或打包到邮件, 或上传到网盘什么的. 总之, 一切都可以在工具中完全控制.
代码:
- 发出信息的工具 https://gist.github.com/AceFantasy/7871237
- Tornado 实现的 SMTP 客户端 https://gist.github.com/AceFantasy/7871107
- 邮件解析 https://gist.github.com/AceFantasy/7871128
- 邮件内容过滤 https://gist.github.com/AceFantasy/7871161
- 新浪的 SSO 登录 和 Discuz 发贴 https://gist.github.com/AceFantasy/7871187