Postfix的header_checks/body_checks功能补充说明(if-endif)
适用于regexp的header_checks
语法:
if /regexp pattern 1/
/regexp pattern 2/
endif
应注意事项:
1. 不要在Windows下打好字再copy-paste,有可能有换行字符产生的错误;
2. 换行方式要严格依照上述结构,也不要为了美观而去缩排或加空格,不然Postfix会不接受(ignoring extra text after IF)。
补充:
1. 如果你要match『否定』的pattern,那可以用 !/regexp pattern/ DISCARD,其中「!」就代表「与这个正规表示式相match的被排除适用;
2. 如果你要比对多个pattern,可以用 /(pattern_1|pattern_2|pattern_3)/,当然,!/(pattern_1|pattern_2|pattern_3)/也是可以的
以上,是根据资料和正规表示式所得到的结论。但是呢,天下没有这么简单的事,我的情况是,我要指定某些账号只接受某些特定寄件者的信,所以我的/etc/postfix/header_checks这样写:
if /^To:.*test@mail\.domain/
!/^From:.*(valid_mailbox1|valid_mailbox2|valid_mailbox3)/
DISCARD
endif
现在,问题来了,所有寄给这个信箱的信都被DISCARD了,为什么呢?
我试过简化版:(不用(|) )
if /^To:.*test@mail\.domain/
!/^From:.*valid_mailbox3/ DISCARD
endif
逻辑:从valid_mailbox3以外的信箱寄到test的信都应该被discard
实际:Postfix会discard所有寄到这个信箱的信!
以及简化版二:(不用反义 ! )
if /^To:.*test@mail\.domain/
/^From:.*valid_mailbox3/ DISCARD
endif
逻辑:只有从valid_mailbox3的信箱寄到test的信才会被discard
实际:Postfix接受任何寄到这个信箱的信!
我崩溃了
其实答案就在这里
http://www.postfix.org/header_checks.5.html
"These rules operate on one logical
message header or one body line at a time, and a decision made for one line is
not carried over to the next line"
这些规则一次只检视一条表头(header_checks规则)或一行内文(body_checks规则),你不能把某一行的检查结果带到另一行去。
换句话说,假如我们订定一个检查规则,要求比对两个pattern:
if /^From:.*sender@thatdomain/
/^To:.*recipient@thisdomain/ DISCARD
endif
则only &
only if有一行标头『同时符合』这两个pattern,Postfix才会对这个邮件执行DISCARD。而很明显的,不可能有哪一行文字『同时』以From和To作起头,所以,这个DISCARD永远不会被执行!这个规则语法100%正确、实际上效果是0。
再讲明确一点,在Postfix的header_checks检查邮件标头时,不管你要比对几个pattern,这几个patterns「必须位于邮件标头的同一行」才有效。
范例:
if /^Content\-Type:.*audio.*x\-midi/
/^.*name\=.*\.scr/ DISCARD drop the header
inavalid
endif
并没有错,只是你必须注意,这个规则只对下面这一行标头生效:
Content-Type:*audio.*x-midi*name=*.scr (在此,*代表零或多个字符)
不是,重复一次,不是下面这样:
1. 发现Content-Type:*audio.x-midi*;
2. 找寻标头档内其它地方还有没有*name=*.scr;
3. 若有,抛弃这封邮件。
不~是~的!
此外,该文还说:
"Message headers added by the cleanup(8)
daemon itself are excluded from inspection. Examples of such message headers
are From:, To:, Message-ID:, Date:.
Message headers deleted by the cleanup(8)
daemon will be examined before they are deleted. Examples are: Bcc:, Content-Length:,
Return-Path:. "
cleanup程序所撰写的邮件标头(如From:, To:,
Message-ID:, Date:)不会被header_checks检查,cleanup程序所删除的邮件标头(如Bcc:,
Content-Length:, Return-Path:)仍然会被header_checks检查。
这也就是说,header_checks根本不可能检查到From: xxxx@nowhere.com、To: yyyy@everywhere.com这种header,你可能会奇怪为什么在mbox中明明可以看到这些headers,header_checks规则却死也找不到? well,因为这两个headers连同Date:,都是cleanup程序写的,而在cleanup接手前,header_checks已经完成了它的工作了。
就Postfix而言,一封邮件在写进mbox档前,经过smtpd和pickup、cleanup、trivial-rewrite程序的处理,已经不是header_checks所看到的那样了,所以『按图(mbox)索骥(mail headers)』是很有可能失败的。
不知道什么是cleanup程序的人,请去翻O'Reilly的Postfiix技术手册第三章。(不难,非常易懂)
所以呢,为什么简化版一会失败?
因为,Postfix收到邮件时检查,发现了有一行标头符合/To:.*test@mail\.domain/的pattern,而这一行『不符合』/^From:.*valid_mailbox3/的pattern,所以 !/^From:.*valid_mailbox3/ = TRUE、/To:.*test@mail\.domain/ = TRUE,所以规则生效,DISCARD!