我希望 postfix 查阅一个简单的 (bash/python) 脚本,以便在队列之前确定 (virtual_alias_maps - style) 收件人地址是否合法。例如,我希望使用以下邮件地址
[email protected]
如果 $EXIPRYDATE 尚未过去并且 $CHECKSUM 已通过,则 $USER 被接受,否则被拒绝。
如果它简化了解决方案,我会为单个、恒定的用户执行此操作,因此 postfix 只需要从某些地址检查脚本中观察 True/False。
我对要求 postfix 先接受邮件,然后在发现收件人地址无效时将其退回的解决方案不感兴趣(“after-queue”)。我需要 postfix 在初始 SMTP 会话期间拒绝(“before-queue”)。
答案1
我遇到了和你类似的问题。排队要求让我们有三个选择
因为我们只检查收件人,所以SMTP 访问策略委派就足够了。如果我们也需要访问标头和正文,则使用 Milter 和 SMTPD 代理。
我的检查器脚本由开发人员提供。程序用法只是./myscript recipient_address
通过 postfix 调用 which mailbox_address。为此,我使用了修改后的版本perl 脚本。这个 perl 脚本允许我读取 stdin、按行拆分字符串并用等号拆分行=
。
然后我宣布生成守护进程在 master.cf 中
policy unix - n n - - spawn user=mydedicateduser argv=/path/to/perl/script.pl
然后定义它main.cf
smtpd_recipient_restrictions =
...
reject_unauth_destination
check_policy_service unix:private/policy
...
下面的脚本可以用另一种编程语言替代。下面是伪代码来解释它的工作原理。
while True:
get the stdin
if stdin = '' # ---> the end of parameter
call the external script with recipient parameter
get the return code
if recipient valid
print "dunno"
else if recipient not valid
print "reject"
else # ---> command error
print "defer if permit"
break
else
validate the stdin, the proper format is 'parameter=value'
if valid
put it in array
为了python 代码,你可以修改代码摘自此片段. 无需设置 spawn daemon。
为了完整性,这里是完整的源代码/path/to/perl/script.pl
#!/usr/bin/perl -w
use strict;
use Sys::Syslog qw(:DEFAULT setlogsock);
use Getopt::Long;
#
# Syslogging options for verbose mode and for fatal errors.
# NOTE: comment out the $syslog_socktype line if syslogging does not
# work on your system.
#
my $syslog_socktype = 'unix'; # inet, unix, stream, console
my $syslog_facility = 'mail';
my $syslog_options = 'pid';
my $syslog_priority = 'info';
# Configuration
my $executable_path = '/my/execute/script.sh';
#
# Procedures
#
#
# Log an error and abort.
#
sub fatal_exit {
my $first = shift @_;
syslog "err", "fatal: $first", @_;
exit 1;
}
# SMTPD access policy routine. The result is an action just like
# it would be specified on the right-hand side of a Postfix access
# table. Request attributes are available via the %attr hash.
sub smtpd_access_policy() {
system($executable_path, $attr{'recipient'});
# -1 command error
# 0 user isn't valid
# else user valud
if ( $? == -1 ) {
# command error
return "defer_if_permit Something error"
}
if ( $? == 0 ) {
return "reject user not found";
}
return "dunno";
}
#
# Main program
#
#
# This process runs as a daemon, so it can't log to a terminal. Use
# syslog so that people can actually see our messages.
#
setlogsock $syslog_socktype;
openlog $0, $syslog_options, $syslog_facility;
unless(GetOptions('v:+' => \$verbose)) {
syslog $syslog_priority, "Invalid option. Usage: %s [-v] [-v] ...", $0;
exit 1;
}
#
# Unbuffer standard output.
#
select((select(STDOUT), $| = 1)[0]);
#
# Receive a bunch of attributes, evaluate the policy, send the result.
#
while (<STDIN>) {
chomp;
if (/^([^=]+)=(.*)$/) {
$attr{substr($1, 0, 512)} = substr($2, 0, 512);
} elsif ($_ eq '') {
if ($verbose>2) {
for (keys %attr) {
syslog $syslog_priority, "Attribute: %s=%s", $_, $attr{$_};
}
}
fatal_exit "unrecognized request type: '%s'", $attr{'request'}
unless $attr{'request'} eq 'smtpd_access_policy';
my $action = smtpd_access_policy();
syslog $syslog_priority, "Action: %s", $action if $verbose>1;
print STDOUT "action=$action\n\n";
%attr = ();
} else {
syslog $syslog_priority, "warning: ignoring garbage: %.100s", $_;
}
}
exit 0;