分类: LINUX
2008-10-25 09:32:04
简介
Procmail 是一个邮件过滤工具,可以根据邮件的发信人、主题、长度以及关键字等对邮件进行排序、分类、整理等工作,特别是在你订阅了邮件列表的时候显得非常有用。
配置
基本配置
Procmail 的配置文件是 ~/.procmailrc 。配置非常简单,首先是一些选项,后面则是一些过滤规则:
# -*- Conf -*-
MAILDIR=$HOME/Maildir/
ORGMAIL=/var/mail/$USER
LOGFILE=$HOME/.maillog
SHELL=/bin/zsh
LOCKFILE=$HOME/.lockmail
VERBOSE=no
# webmaster always sends junk mail~~
:0
* ^From: webmaster@st\.zju\.edu\.cn
/dev/null
# all other mail goes to inbox
:0:
inbox/
值得注意的是,邮箱末尾的 / 告诉 Procmail 使用 maildir 邮箱格式,而不是 mbox 格式。
关于 recipe
Procmail 使用 recipe 来决定处理哪些邮件以及如何处理他们。一个 recipe 有这种格式:
:0 [flags] [ : [locallockfile] ]
flags 具体可以参见 man procmailrc ,后面如果加上冒号则表示对文件进行锁定,这样可以避免同时运行几个 Procmail 操纵相同的文件的时候造成混乱。
conditions 以 * 开头,当然处理使用正则表达式进行匹配,还有其他可用的命令,例如以 < 开头可以检查邮件的长度是否小于给定的值。其他具体可以参见 man procmailrc 。
接下来是 action line 。如果以 ! 开头,则对邮件进行 forward 到指定的地址;如果是以 | 开头则是启动相应的程序;以 { 开头则可以指定嵌套的 recipe ;其他情况则被视为本地邮箱,如果是一个目录,则表示 maildir 格式,否则是 mbox 格式。
一个例子
最近 MSTC 内部组建了一个邮件列表,凡是发送到 的邮件都会被自动投递给 MSTC 的每一个成员,可是萝卜时常在外网,不方便使用内网邮箱,正好我这里有 VPN 连接,可以同时连接到内网和外网,所以我决定对邮件进行 forward 。
首先是要把我受到的 allmstc 的邮件列表 forward 到萝卜的外网邮箱,观察 allmstc 的邮件列表的邮件头可以找出一个合适的匹配的正则表达式:
:0:
* ^X-MDMailing-List: allmstc@mstczju.org
{
:0 c
! yujiazi@gmail.com
:0:
mstc/
}
可以看到,所有匹配到的邮件进入嵌套的下一轮匹配,首先是 forward 到萝卜的外网邮箱,这里使用了 c 这个标志,表示对邮件进行拷贝,这样可以保证接下来的 recipe 能够继续处理这个邮件,否则我自己就收不到邮件了,于是下一个 recipe 我让 Procmail 把邮件放到我的 mstc 这个本地邮箱里面。
同时,为了让萝卜能够参与邮件列表的讨论,他把邮件发送到我的外网邮箱,并保证在主题里面有 [allmstc] 的字样,那么我就把这封邮件转发到 里面去:
:0
* ^To: pluskid.zju@gmail.com
* ^Subject.*\[allmstc\].*
! allmstc@mstczju.org
运行
要让发送给自己的邮件都经过 Procmail 过滤, 上讲了一个方法,只需要在主目录下面建立一个 .forward 文件,内容为:
"|IFS=' ' && exec /usr/bin/procmail || exit 75 #kid"
其中路径替换成自己 procmail 真正的路径,并把 kid 替换成自己真正的用户名即可。注意主目录的属性,如果不小心打开了组或者其他人的写属性,那么邮件服务器将会拒绝处理 .forward 文件。
这个应该是针对 Sendmail 的语法,我使用 ,试验了一下并不能正常运行,而且从 的日志可以看出有错误。我在 上对日志里面的出错信息进行了一番搜索以后得到了答案。
那怪异的语法是针对 Sendmail 的各种功能以及安全漏洞的,许多文档都给出那样的例子,以至于那甚至被认为是所有 MTA 的“正常行为”了。对于 Sendmail ,如果两个用户的 .forward 文件的内容是一样的,就会出现问题。因为 Sendmail 会对邮件的 forward 进行优化,如果一个邮件同时发送到这两个用户,并且他们的 forward 地址都是一样的,就删除一个重复的。这样的行为对于 .forward 内容为电子邮件地址的情况是好的,但是对于用管道输出到程序的情况就不行了。因此人们总是在命令末尾加上一些“垃圾信息”(例如自己的用户名) 来避免重复。
而其他的 MTA 总是能够区分不同用户的管道命令,因为除了对命令行进行比较以外,他们还对程序运行的 UID 进行比较。
Sendmail 调用一个 shell 来执行管道命令,这有可能出现安全漏洞,所以大家添加 IFS=' ' 一类的东西,试图控制局面。 自己进行命令行解析,所以不需要这个。
因此,在使用 的时候, .forward 里面的内容很简单:
|/usr/bin/procmail