You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Postfix+Dovecot系统限制仅转发用户邮件接收范围及SPF相关配置咨询

Postfix+Dovecot系统限制仅转发用户邮件接收范围及SPF相关配置咨询

嘿,这个场景我太熟了——不少用Postfix+Dovecot搭企业邮箱的朋友都踩过类似的坑,咱们一步步拆解解决,既要满足你的核心需求,又要把SPF相关的麻烦彻底摆平。

先把核心需求掰扯明白

你要的效果其实可以拆成两条硬规则:

  1. 有本地邮箱的用户:敞开收所有来源的邮件,没任何限制
  2. 仅转发的用户:只允许接收来自你内部域名(example.com)的邮件,外部发件人的直接拒掉

之前被拉黑的问题,本质是转发了外部发件人的邮件到外部地址,导致SPF验证失败(你的服务器不在原发件人域名的SPF记录里)。现在咱们直接拦掉这类邮件,这个问题自然就消失了,根本轮不到SPF验证那一步。


第一步:给Postfix加「用户类型识别+收件范围限制」的核心规则

这部分要让Postfix能自动判断某个收件人属于哪类用户,然后执行对应的规则。咱们用数据库查询配合Postfix的访问控制来实现:

1. 写一个能识别用户类型的SQL查询

假设你的用户别名存在virtual_aliases表(字段address是收件地址,target是目标地址),咱们需要一个能递归解析别名链的查询,判断最终是否指向本地邮箱(比如target以/结尾):

WITH RECURSIVE alias_chain AS (
    SELECT address, target FROM virtual_aliases WHERE address = '%s'
    UNION ALL
    SELECT va.address, va.target FROM virtual_aliases va
    JOIN alias_chain ac ON va.address = ac.target
    WHERE va.target NOT LIKE '%/'  -- 没到本地邮箱就继续递归
)
SELECT 'OK' FROM alias_chain WHERE target LIKE '%/'
UNION
SELECT 'PERMIT_INTERNAL_ONLY' FROM dual WHERE NOT EXISTS (SELECT 1 FROM alias_chain WHERE target LIKE '%/')

这个查询的逻辑是:如果收件人的别名链最终指向本地邮箱,返回OK(允许所有来源);否则返回PERMIT_INTERNAL_ONLY(仅允许内部发件人)。

2. 把查询做成Postfix的访问映射

在/etc/postfix/mysql/目录下新建check_recipient_type.cf文件,内容如下(替换成你的数据库信息):

user = postfix_db_user
password = 你的数据库密码
dbname = postfix_db
hosts = 127.0.0.1
query = WITH RECURSIVE alias_chain AS (SELECT address, target FROM virtual_aliases WHERE address = '%s' UNION ALL SELECT va.address, va.target FROM virtual_aliases va JOIN alias_chain ac ON va.address = ac.target WHERE va.target NOT LIKE '%/') SELECT 'OK' FROM alias_chain WHERE target LIKE '%/' UNION SELECT 'PERMIT_INTERNAL_ONLY' FROM dual WHERE NOT EXISTS (SELECT 1 FROM alias_chain WHERE target LIKE '%/')

3. 定义「仅允许内部发件人」的规则类

在Postfix的main.cf里添加以下配置:

# 自定义规则类:仅允许内部域名发件人
smtpd_restriction_classes = permit_internal_only
permit_internal_only =
    check_sender_access hash:/etc/postfix/internal_senders,
    reject  -- 不符合条件直接拒绝

4. 配置内部发件人列表

新建/etc/postfix/internal_senders文件,内容就是你的内部域名:

example.com OK

然后执行postmap /etc/postfix/internal_senders生成Postfix能识别的哈希表。

5. 把规则加到Postfix的收件限制链里

在main.cf的smtpd_recipient_restrictions里,把咱们的检查规则加到合适的位置(比如在SPF/DKIM检查之后,默认拒绝规则之前):

smtpd_recipient_restrictions =
    permit_mynetworks,
    permit_sasl_authenticated,
    check_recipient_access mysql:/etc/postfix/mysql/check_recipient_type.cf,
    check_policy_service unix:private/policyd-spf,  -- 你的现有SPF检查
    check_milter inet:127.0.0.1:8891,  -- 你的现有DKIM检查
    reject_unauth_destination

记得执行postfix reload让配置生效。


第二步:搞定SPF相关的收尾工作

现在咱们已经拦掉了外部发件人给仅转发用户的邮件,之前的拉黑/SPF问题就解决了:

  1. 直接关掉SRS:如果你之前开了SRS(发件人重写服务),现在完全用不上了——因为你不再转发外部发件人的邮件,留着SRS反而可能引入不必要的复杂度。
  2. 强化内部发件人验证(可选):如果想更严谨,可以在permit_internal_only规则里加一条check_sender_spf pass,确保只有通过SPF验证的内部发件人才能给仅转发用户发邮件(不过内部发件人本来就会过SPF,这步算是双重保险):
    permit_internal_only =
        check_sender_spf pass,
        check_sender_access hash:/etc/postfix/internal_senders,
        reject
    

几个测试&排查的小技巧

  1. 用内部发件人(比如test@example.com)给仅转发用户发邮件,看是否能正常接收;
  2. 用外部发件人(比如test@gmail.com)给仅转发用户发邮件,看是否被拒绝;
  3. 查看Postfix日志/var/log/mail.log,如果有问题,日志里会明确显示是因为哪个规则被拒绝的;
  4. 测试别名链的解析:比如c.chip@example.com指向compuchip@example.com(仅转发用户),要确保Postfix能正确识别c.chip是仅转发用户。

备注:内容来源于stack exchange,提问作者CompuChip

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.20 12:49:32