Postfix

出自 ArchWiki

Postfix 是一个邮件传输代理,根据其网站

旨在快速、易于管理和安全,同时又与 sendmail 兼容,不会让现有用户感到不安。因此,外部具有 sendmail 风格,但内部完全不同。

本文建立在邮件服务器之上。本文的目标是设置 Postfix 并解释基本配置文件的作用。本文提供了设置仅限本地系统用户的交付的说明,以及指向虚拟用户交付指南的链接。

安装

安装 postfix 软件包。

配置

请参阅 Postfix 基本配置。配置文件默认位于 /etc/postfix 中。两个最重要的文件是

  • master.cf,定义启用了哪些 Postfix 服务以及客户端如何连接到它们,请参阅 master(5)
  • main.cf,主配置文件,请参阅 postconf(5)

配置更改需要 postfix.service 重载 或运行 postfix reload 才能生效。

别名

请参阅 aliases(5)

您可以在 /etc/postfix/aliases 中指定别名(也称为转发器)。

您应该将所有发送给 root 的邮件映射到另一个帐户,因为以 root 身份读取邮件不是一个好主意。

取消注释以下行,并将 you 更改为真实帐户。

root: you

完成编辑 /etc/postfix/aliases 后,您必须运行 postalias 命令

 # postalias /etc/postfix/aliases

对于以后的更改,您可以使用

 # newaliases
提示: 或者,您可以创建文件 ~/.forward,例如 /root/.forward 用于 root 用户。指定应将 root 邮件转发给哪个用户,例如 user@localhost
/root/.forward
user@localhost

本地邮件

要仅将邮件传递给本地系统用户(在 /etc/passwd 中),请更新 /etc/postfix/main.cf 以反映以下配置。取消注释、更改或添加以下行

myhostname = localhost
mydomain = localdomain
mydestination = $myhostname, localhost.$mydomain, localhost
inet_interfaces = $myhostname, localhost
mynetworks_style = host
default_transport = error: outside mail is not deliverable

所有其他设置可以保持不变。设置好上述配置文件后,您可能希望设置一些#别名,然后#启动 Postfix

虚拟邮件

虚拟邮件是不映射到用户帐户 (/etc/passwd) 的邮件。

虚拟别名

虚拟别名用于重写所有本地、虚拟和远程目的地的目标地址。这可以用于重写单个收件人或整个域的目标地址。

虚拟地址别名

为单个地址设置虚拟别名。

启用虚拟别名表

/etc/postfix/main.cf
virtual_alias_maps = lmdb:/etc/postfix/virtual

填充虚拟别名表

/etc/postfix/virtual
user@domain address

重建索引文件

# postmap /etc/postfix/virtual

重启 postfix.service

检查配置

运行 postfix check 命令。它应该输出您在配置文件中可能做错的任何事情。

要查看所有配置,请输入 postconf。要查看与默认值的差异,请尝试 postconf -n

启动 Postfix

注意: 您必须至少运行一次 newaliases 才能使 Postfix 运行,即使您没有设置任何#别名

启动/启用 postfix.service

TLS

有关更多信息,请参阅 Postfix TLS 支持

安全 SMTP (发送)

默认情况下,Postfix/sendmail 不会将电子邮件加密发送到其他 SMTP 服务器。要在可用时使用 TLS,请将以下行添加到 main.cf

/etc/postfix/main.cf
smtp_tls_security_level = may

强制 TLS(并在远程服务器不支持时失败),请将 may 更改为 encrypt。但是请注意,如果 SMTP 服务器是公开引用的,则这违反了 RFC:2487

安全 SMTP (接收)

警告: 如果您部署 TLS,请务必遵循 weakdh.org 的指南以防止 FREAK/Logjam。自 2015 年年中以来,默认设置已针对 POODLE 进行了安全防护。有关更多信息,请参阅 服务器端 TLS

默认情况下,Postfix 不会接受安全邮件。

您需要获取证书。通过将以下行添加到 main.cf,将 Postfix 指向您的 TLS 证书

/etc/postfix/main.cf
smtpd_tls_security_level = may
smtpd_use_tls = yes
smtpd_tls_cert_file = /path/to/cert.pem
smtpd_tls_key_file = /path/to/key.pem

有两种方法可以接受安全邮件。SMTP 上的 STARTTLS(端口 587(也称为“submission”端口))和 SMTPS(端口 465(也称为“submissions”端口)。后者以前已弃用,但已由 RFC:8314 恢复。

要启用 SMTP 上的 STARTTLS(端口 587),请取消注释 master.cf 中的以下行

/etc/postfix/master.cf
submission inet n       -       n       -       -       smtpd
  -o syslog_name=postfix/submission
  -o smtpd_tls_security_level=encrypt
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_tls_auth_only=yes
  -o smtpd_reject_unlisted_recipient=no
#  -o smtpd_client_restrictions=$mua_client_restrictions
#  -o smtpd_helo_restrictions=$mua_helo_restrictions
#  -o smtpd_sender_restrictions=$mua_sender_restrictions
  -o smtpd_relay_restrictions=
  -o smtpd_recipient_restrictions=permit_sasl_authenticated,reject
  -o milter_macro_daemon_name=ORIGINATING

smtpd_*_restrictions 选项保持注释状态,因为 $mua_*_restrictions 默认情况下未在 main.cf 中定义。如果您确实决定设置任何 $mua_*_restrictions,也请取消注释这些行。

要启用 SMTPS(端口 465),请取消注释 master.cf 中的以下行

/etc/postfix/master.cf
submissions     inet  n       -       n       -       -       smtpd
  -o syslog_name=postfix/smtps
  -o smtpd_tls_wrappermode=yes
  -o smtpd_sasl_auth_enable=yes
  -o smtpd_reject_unlisted_recipient=no
#  -o smtpd_client_restrictions=$mua_client_restrictions
#  -o smtpd_helo_restrictions=$mua_helo_restrictions
#  -o smtpd_sender_restrictions=$mua_sender_restrictions
  -o smtpd_relay_restrictions=
  -o smtpd_relay_restrictions=permit_sasl_authenticated,reject
  -o milter_macro_daemon_name=ORIGINATING

$smtpd_*_restrictions 行的原理与上面相同。

技巧与窍门

黑名单入站邮件

使用 Postfix 可以轻松地手动将入站电子邮件按发件人地址列入黑名单。

创建并打开 /etc/postfix/blacklist_incoming 文件并附加发件人电子邮件地址

user@example.com REJECT

然后使用 postmap 命令创建数据库

# postmap lmdb:blacklist_incoming

main.cf 中的第一个 permit 规则之前添加以下代码

smtpd_recipient_restrictions = check_sender_access lmdb:/etc/postfix/blacklist_incoming

最后重启 postfix.service

在 Received 标头中隐藏发件人的 IP 和用户代理

这主要是一个隐私问题,如果您使用 Thunderbird 发送电子邮件。Received 标头将包含您的 LAN 和 WAN IP 以及有关您使用的电子邮件客户端的信息。(原始来源:AskUbuntu)我们想要做的是从外发电子邮件中删除 Received 标头。这可以通过以下步骤完成

将以下行添加到 main.cf

smtp_header_checks = regexp:/etc/postfix/smtp_header_checks

使用以下内容创建 /etc/postfix/smtp_header_checks

/^Received: .*/     IGNORE
/^User-Agent: .*/   IGNORE

最后,重启 postfix.service

chroot jail 中的 Postfix

默认情况下,Postfix 未放入 chroot jail 中。Postfix 文档 [1] 提供了有关如何完成此类 jail 的详细信息。步骤概述如下,并基于 Postfix 源代码中提供的 chroot-setup 脚本。

首先,进入目录 /etc/postfix 中的 master.cf 文件,并将除服务 qmgrproxymapproxywritelocalvirtual 之外的所有 chroot 条目更改为“yes”(y)

其次,创建两个函数,这将帮助我们稍后将文件复制到 chroot jail 中(请参阅最后一步)

CP="cp -p"
cond_copy() {
  # find files as per pattern in $1
  # if any, copy to directory $2
  dir=$(dirname "$1")
  pat=$(basename "$1")
  lr=$(find "$dir" -maxdepth 1 -name "$pat")
  if test ! -d "$2" ; then exit 1 ; fi
  if test "x$lr" != "x" ; then $CP $1 "$2" ; fi
}

接下来,为 jail 创建新目录

set -e
umask 022
POSTFIX_DIR=${POSTFIX_DIR-/var/spool/postfix}
cd ${POSTFIX_DIR}
mkdir -p etc lib usr/lib/zoneinfo
test -d /lib64 && mkdir -p lib64

查找 localtime 文件

lt=/etc/localtime
if test ! -f $lt ; then lt=/usr/lib/zoneinfo/localtime ; fi
if test ! -f $lt ; then lt=/usr/share/zoneinfo/localtime ; fi
if test ! -f $lt ; then echo "cannot find localtime" ; exit 1 ; fi
rm -f etc/localtime

将 localtime 和其他一些系统文件复制到 chroot 的 etc 中

$CP -f $lt /etc/services /etc/resolv.conf /etc/nsswitch.conf etc
$CP -f /etc/host.conf /etc/hosts /etc/passwd etc
ln -s -f /etc/localtime usr/lib/zoneinfo

确保 resolv.conf 归 root 所有

chown root /var/spool/postfix/etc/resolv.conf

使用先前创建的函数 cond_copy 将所需的库复制到 chroot 中

cond_copy '/usr/lib/libnss_*.so*' lib
cond_copy '/usr/lib/libresolv.so*' lib
cond_copy '/usr/lib/libdb.so*' lib

并且不要忘记重载 Postfix。

DANE (DNSSEC)

资源记录

警告: 这不是一个简单的章节。请注意,您要确保您知道自己在做什么。您最好先阅读 常见错误

DANE 支持多种类型的记录,但并非所有记录都适用于 Postfix。

证书用法 0 不受支持,1 映射到 3,2 是可选的,因此建议发布“3”记录。有关资源记录的更多信息。

配置

本文或章节需要扩充。

原因: tempfail 是什么意思?(在Talk:Postfix 中讨论)

机会主义 DANE 配置如下

/etc/postfix/main.cf
smtpd_use_tls = yes
smtp_dns_support_level = dnssec
smtp_tls_security_level = dane
/etc/postfix/master.cf
dane       unix  -       -       n       -       -       smtp
  -o smtp_dns_support_level=dnssec
  -o smtp_tls_security_level=dane

要使用按域策略,例如针对 example.org 的机会主义 DANE 和针对 example.com 的强制 DANE,请使用如下内容

/etc/postfix/main.cf
indexed = ${default_database_type}:${config_directory}/

# Per-destination TLS policy
#
smtp_tls_policy_maps = ${indexed}tls_policy

# default_transport = smtp, but some destinations are special:
#
transport_maps = ${indexed}transport
transport
example.com dane
example.org dane
tls_policy
example.com dane-only
注意: 对于全局强制 DANE,请将 smtp_tls_security_level 更改为 dane-only。请注意,这会使 Postfix 在所有根本不使用 DANE 的交付中 tempfail(以 4.X.X 错误代码响应)!

完整文档位于此处

扩展功能

https://postfixadmin.sourceforge.net/ || postfixadmin

Postgrey

本文或章节需要改进语言、wiki 语法或风格。请参阅 Help:Style 以供参考。

原因: 请参阅 Help:Style(在 Talk:Postfix 中讨论)

Postgrey 可用于为 Postfix 邮件服务器启用灰名单

安装

安装 postgrey 软件包。为了快速运行它,请编辑 Postfix 配置文件并添加以下行

/etc/postfix/main.cf
smtpd_recipient_restrictions =
  check_policy_service inet:127.0.0.1:10030

然后启动/启用 postgrey 服务。之后,重载 postfix 服务。现在应该启用灰名单。

配置

配置是通过扩展单元 postgrey.service 完成的。

白名单

要添加自动白名单(成功交付的邮件将被列入白名单,不再需要等待),请添加 --auto-whitelist-clients=N 选项并将 N 替换为适当的小数字(或将其保留为默认值 5)。

/etc/systemd/system/postgrey.service.d/override.conf
[Service]
ExecStart=
ExecStart=/usr/bin/postgrey --inet=127.0.0.1:10030 \
       --pidfile=/run/postgrey/postgrey.pid \
       --group=postgrey --user=postgrey \
       --daemonize \
       --greylist-text="Greylisted for %%s seconds" \
       --auto-whitelist-clients

要除了默认客户端外还添加您自己的白名单客户端列表,请创建文件 /etc/postfix/postgrey_whitelist_clients.local 并在每行输入一个主机或域名,然后重启 postgrey.service 以使更改生效。

故障排除

如果您指定 --unix=/path/to/socket 并且未创建套接字文件,请确保已从服务文件中删除默认的 --inet=127.0.0.1:10030

有关可能选项的完整文档,请参阅 perldoc postgrey

SpamAssassin

本节介绍如何集成 SpamAssassin

SpamAssassin 独立通用设置

注意: 如果您想结合 SpamAssassin 和 Dovecot 邮件过滤,请忽略接下来的两行,而是继续向下阅读。

编辑 /etc/postfix/master.cf 并在 smtp 下添加内容过滤器。

smtp      inet  n       -       n       -       -       smtpd
  -o content_filter=spamassassin

还要为 SpamAssassin 添加以下服务条目

spamassassin unix -     n       n       -       -       pipe
  flags=R user=spamd argv=/usr/bin/vendor_perl/spamc -e /usr/bin/sendmail -oi -f ${sender} ${recipient}

现在您可以启动启用 spamassassin.service

SpamAssassin 结合 Dovecot LDA / Sieve (邮件过滤)

按照 Dovecot#Sieve 中的描述设置 LDA 和 Sieve 插件。但忽略最后一行 mailbox_command...

而是在 /etc/postfix/master.cf 中添加管道

 dovecot   unix  -       n       n       -       -       pipe
       flags=DRhu user=vmail:vmail argv=/usr/bin/vendor_perl/spamc -u spamd -e /usr/lib/dovecot/dovecot-lda -f ${sender} -d ${recipient}

并在 /etc/postfix/main.cf 中激活它

 virtual_transport = dovecot

或者,如果您不想使用虚拟传输,可以使用 mailbox_command。这以本地用户和组身份运行,而管道则以使用 user 设置的指定用户身份运行。

 mailbox_command = /usr/bin/vendor_perl/spamc -u spamd -e /usr/lib/dovecot/dovecot-lda -f "$SENDER" -a "$RECIPIENT"

SpamAssassin 结合 Dovecot LMTP / Sieve

按照 Dovecot#Sieve 中的描述设置 LMTP 和 Sieve。

编辑 /etc/dovecot/conf.d/90-plugin.conf 并添加

 sieve_before = /etc/dovecot/sieve.before.d/
 sieve_extensions = +vnd.dovecot.filter
 sieve_plugins = sieve_extprograms
 sieve_filter_bin_dir = /etc/dovecot/sieve-filter
 sieve_filter_exec_timeout = 120s #this is often needed for the long running spamassassin scans, default is otherwise 10s

创建目录并将 spamassassin 放入其中作为可由 dovecot 运行的二进制文件

 # mkdir /etc/dovecot/sieve-filter
 # ln -s /usr/bin/vendor_perl/spamc /etc/dovecot/sieve-filter/spamc

创建一个新文件,/etc/dovecot/sieve.before.d/spamassassin.sieve,其中包含

 require [ "vnd.dovecot.filter" ];
 filter "spamc" [ "-d", "127.0.0.1", "--no-safe-fallback" ];

编译 sieve 规则 spamassassin.svbin

 # cd /etc/dovecot/sieve.before.d
 # sievec spamassassin.sieve

最后,重启 dovecot.service

基于规则的邮件处理

使用策略服务,可以轻松微调 Postfix 的邮件传递行为。postfwd 提供执行此操作的服务。这允许您实现例如发件人和收件人的时间感知灰名单和黑名单,以及 SPF 策略检查。

策略服务是独立的服务,并像这样连接到 Postfix

/etc/postfix/main.cf
smtpd_recipient_restrictions =
  ...
  check_policy_service unix:/run/policyd.sock
  check_policy_service inet:127.0.0.1:10040

将策略服务放置在队列的末尾可以减少负载,因为只有合法的邮件才会被处理。请务必将其放置在第一个 permit 语句之前,以捕获所有入站消息。

发件人策略框架

要将发件人策略框架与 Postfix 一起使用,您可以安装 python-spf-engineAURpython-postfix-policyd-spfAURpostfix-policyd-spf-perlAUR

使用 spf-engine 或 python-postfix-policyd-spf

根据您的需要编辑 /etc/python-policyd-spf/policyd-spf.conf。可以在 /etc/python-policyd-spf/policyd-spf.conf.commented 中找到详细注释的版本。请特别注意 HELO 检查策略,因为标准设置会严格拒绝 HELO 失败。

main.cf 文件中,为 policyd 添加超时

/etc/postfix/main.cf
policy-spf_time_limit = 3600s

然后添加传输

/etc/postfix/master.cf
policy-spf  unix  -       n       n       -       0       spawn user=nobody argv=/usr/bin/policyd-spf

最后,您需要将 policyd 添加到 smtpd_recipient_restrictions。为了最大限度地减少负载,请将其放在限制的末尾,但在任何 reject_rbl_client DNSBL 行之上

/etc/postfix/main.cf
smtpd_recipient_restrictions=
     ...
     permit_sasl_authenticated
     permit_mynetworks
     reject_unauth_destination
     check_policy_service unix:private/policy-spf

现在重载 postfix 服务。

您可以使用以下命令测试您的设置

/etc/python-policyd-spf/policyd-spf.conf
defaultSeedOnly = 0

使用 postfix-policyd-spf-perl

使用 postfix 执行与 python-postfix-policyd-spf 相同的过程,但存在以下差异

main.cf 文件中 policyd 的超时

/etc/postfix/main.cf
policy_time_limit = 3600

传输

/etc/postfix/master.cf
policy  unix  -       n       n       -       0       spawn
     user=nobody argv=/usr/lib/postfix/postfix-policyd-spf-perl

将 policyd 添加到 smtpd_recipient_restrictions

警告:reject_unauth_destination 之后指定 check_policy_service,否则您的系统可能会变成开放中继。
/etc/postfix/main.cf
smtpd_recipient_restrictions=
     ...
     reject_unauth_destination
     check_policy_service unix:private/policy
     ...

发件人重写方案

要将发件人重写方案与 Postfix 一起使用,请安装 postsrsdAUR 并调整设置

/etc/postsrsd/postsrsd.conf
domains = { "yourdomain.tld", "yournextdomain.tld", "yournextdomain.tld" }
unprivileged-user = "postsrsd"

启用并启动守护程序,确保它在重启后也能运行。然后通过调整以下行来配置 Postfix

/etc/postfix/main.cf
sender_canonical_maps = socketmap:unix:srs:forward
sender_canonical_classes = envelope_sender
recipient_canonical_maps = socketmap:unix:srs:reverse
recipient_canonical_classes = envelope_recipient, header_recipient

重启 Postfix 并开始转发邮件。

故障排除

警告:“database /etc/postfix/*.db is older than source file ..”

如果您使用 journalctl 收到一个或两个警告

warning: database /etc/postfix/virtual.db is older than source file /etc/postfix/virtual
warning: database /etc/postfix/transport.db is older than source file /etc/postfix/transport

那么您可以根据收到的消息使用以下命令修复它

postmap /etc/postfix/transport
postmap /etc/postfix/virtual

重启 postfix.service

找不到主机名或域名。名称服务错误,名称为=...

如果您使用 journalctl 收到以下警告

Host or domain name not found. Name service error for name=...

可能是您在 chroot 中运行 Postfix 并且缺少 /etc/resolv.conf。如果是这样,您可以通过以下方式修复此问题

mkdir -p /var/spool/postfix/etc
cp /etc/resolv.conf /var/spool/postfix/etc/resolv.conf

重启 postfix.service

错误:require 命令:未知的 Sieve 功能 `vnd.dovecot.filter`

spamassassin: line 1: error: require command: unknown Sieve capability `vnd.dovecot.filter'.
spamassassin: line 2: error: unknown command 'filter' (only reported once at first occurrence).
spamassassin: error: validation failed.
sievec(root): Fatal: failed to compile sieve script 'spamassassin.sieve'

如果在按照 #SpamAssassin 结合 Dovecot LMTP / Sieve 操作后运行 sievec 时收到此错误,请将 /etc/dovecot/sieve.before.d/spamassassin.sieve 中的 sieve_extensions 替换为 sieve_global_extensions

重启 dovecot.service

参见