Postfix:如何使用简单脚本以“virtual_alias_maps”样式映射收件人地址?

Postfix:如何使用简单脚本以“virtual_alias_maps”样式映射收件人地址?

我希望 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;

相关内容