跳转到主要内容

于 2025年04月22日 摘录自 Postfix Virtual Domain Hosting Howto

本文件的目的

本文档需要 Postfix 2.0 或更高版本。

本文档概述了 Postfix 如何用于托管多个互联网域,既可在本机进行最终投递,也可转发到其他地方。

文中不仅介绍了 Postfix 内置的投递机制,还提供了使用非 Postfix 邮件投递软件的指针。

内容包括

典型域名与托管域名及其他域名

大多数 Postfix 系统仅是少数域名的最终目的地。 这些域名包括 Postfix 运行机器的主机名和[IP 地址],有时还包括主机名的父域。 本文其余部分将把这些域称为规范域。 它们通常由 Postfix本地域地址类实现,如ADDRESS_CLASS_README文件所定义。

除了规范域外,Postfix 还可以配置为任意数量附加域的最终目的地。 这些域被称为托管域,因为它们与机器本身的名称没有直接关联。 托管域通常使用ADDRESS_CLASS_README文件中定义的虚拟别名域地址类和/或虚拟邮箱域地址类来实现。

但是,等等! 还有更多。 Postfix 可以配置为其他域的备份 MX 主机。 在这种情况下,Postfix并不是这些域的最终目的地。 它只是在主 MX 主机宕机时排队等候邮件,并在主 MX 主机可用时转发邮件。 该功能通过ADDRESS_CLASS_README文件中定义的中继域地址类实现。

最后,可以将 Postfix 配置为在互联网上发送邮件的中转主机。 显然,Postfix 并不是这些邮件的最终目的地。 该功能仅适用于授权客户和/或用户,由ADDRESS_CLASS_README文件中定义的默认域地址类实现。

本地文件与网络数据库

本文中的示例使用的是从本地文件(如 DBM 或 Berkeley DB)中查找表。 使用postmap命令很容易调试这些操作:

例如 postmap -q [email protected] hash:/etc/postfix/virtual

关于如何用数据库替换本地文件,请参阅LDAP_READMEMYSQL_READMEPGSQL_README中的文档。 强烈建议读者在迁移到网络数据库之前,先让系统使用本地文件工作,并使用postmap命令来验证网络数据库的查找结果是否与本地文件的查找结果完全相同。

示例 postmap -q [email protected] ldap:/etc/postfix/virtual.cf

简单至极:共享域、UNIX 系统账户

托管附加域的最简单方法是将域名添加到 Postfixmydestination配置参数中列出的域中,并将用户名添加到 UNIX 密码文件中。

这种方法不区分规范域和托管域。 每个用户名都可以接收每个域中的邮件。

在示例中,我们将使用 "example.com "作为本地 Postfix 机器托管的域。

/etc/postfix/main.cf:
    mydestination = $myhostname localhost.$mydomain ... example.com

这种方法的局限性在于

  • 完全没有区分:[email protected] 的邮件与 [email protected] 的邮件被发送到同一个 UNIX 系统账户。
  • 由于用户都在 UNIX 密码文件中,因此对大量用户的管理变得很不方便。

下面的示例为这两种限制提供了解决方案。

Postfix 虚拟 ALIAS 示例:独立域、UNIX 系统账户

使用本节所述方法,每个托管域都可以拥有自己的 info 等电子邮件地址。 不过,它仍然使用 UNIX 系统账户来发送本地邮箱。

通过虚拟别名域,每个托管地址都被别名为本地 UNIX 系统账户或远程地址。 下面的示例显示了如何在 example.com 域中使用这种机制。

 1 /etc/postfix/main.cf:
 2     virtual_alias_domains = example.com ...other hosted domains...
 3     virtual_alias_maps = hash:/etc/postfix/virtual
 4 
 5 /etc/postfix/virtual:
 6     [email protected] postmaster
 7     [email protected]       joe
 8     [email protected]      jane
 9     # Uncomment entry below to implement a catch-all address
10     # @example.com         jim
11     ...virtual aliases for more domains...

注释

  • 第 2 行:virtual_alias_domains设置告诉 Postfix example.com 是一个所谓的虚拟别名域。 如果省略此设置,Postfix 将拒绝邮件(拒绝中继访问)或无法投递邮件(寄往 example.com 的邮件会循环回到我自己)。

    切勿将虚拟别名域名列为我的目标域名!

  • 第 3-8 行:/etc/postfix/virtual 文件包含虚拟别名。 在上面的示例中,寄给 [email protected] 的邮件将发送给本地邮政局长,寄给 [email protected] 的邮件将发送给 UNIX 账户 joe,寄给 [email protected] 的邮件将发送给 UNIX 账户 jane。 发往 example.com 中所有其他地址的邮件都会被拒收,并显示错误信息 "用户未知"。
  • 第 10 行:注释出的条目(#后面的文字)显示了如何实现一个 "一网打尽 "的虚拟别名,接收虚拟别名文件中未列出的所有 example.com 地址的邮件。 这样做并非没有风险。 现在的垃圾邮件发送者会尝试从他们能想到的每一个可能的名称发送邮件(或将邮件发送到他们能想到的每一个可能的名称)。 一个 "一网打尽 "的邮箱很可能会收到很多垃圾邮件,也会收到很多以 [email protected] 名义发送的垃圾邮件被退回。

更改虚拟文件后执行命令"postmap /etc/postfix/virtual",更改main.cf文件后执行命令"postfix reload"。

注意:虚拟别名可以解析到本地地址或远程地址,或两者兼而有之。 它们不一定要解析到你机器上的 UNIX 系统账户。

virtual(5)手册页面提供了有关虚拟别名文件的更多细节,包括右侧的多个地址。

虚拟别名解决了一个问题:它允许每个域拥有自己的信息邮件地址。 但仍有一个缺点:每个虚拟地址都与一个 UNIX 系统账户别名。 在添加更多虚拟地址的同时,也会添加更多 UNIX 系统账户。 下一节将消除这一问题。

Postfix 虚拟 MAILBOX 示例:独立域、非 UNIX 账户

当系统中的域和用户越来越多时,为每个用户提供自己的 UNIX 系统账户就变得不那么可取了。

有了 Postfixvirtual(8)邮箱投递代理,每个收件人地址都可以拥有自己的虚拟邮箱。 与虚拟别名域不同,虚拟邮箱域不需要将每个收件人地址翻译成不同的地址,虚拟邮箱地址的所有者也不需要拥有 UNIX 系统账户。

Postfixvirtual(8)邮箱投递代理通过与收件人邮件地址一起搜索的单独表格查找用户邮箱路径名、uid 和 gid。 邮箱路径名以"/"结尾,可开启 Maildir 式投递。

如果你觉得多表的概念令人烦恼,请记住,你可以将信息迁移(一旦成功)到 SQL 数据库。 如果采用这种方法,请务必查看本文档顶部的"本地文件与数据库 "部分。

下面是虚拟邮箱域"example.com "的示例:

 1 /etc/postfix/main.cf:
 2     virtual_mailbox_domains = example.com ...more domains...
 3     virtual_mailbox_base = /var/mail/vhosts
 4     virtual_mailbox_maps = hash:/etc/postfix/vmailbox
 5     virtual_minimum_uid = 100
 6     virtual_uid_maps = static:5000
 7     virtual_gid_maps = static:5000
 8     virtual_alias_maps = hash:/etc/postfix/virtual
 9 
10 /etc/postfix/vmailbox:
11     [email protected]    example.com/info
12     [email protected]   example.com/sales/
13     # Comment out the entry below to implement a catch-all.
14     # @example.com      example.com/catchall
15     ...virtual mailboxes for more domains...
16 
17 /etc/postfix/virtual:
18     [email protected] postmaster

备注:

  • 第 2 行: virtual_mailbox_domains设置告诉 Postfix,example.com 是所谓的虚拟邮箱域。 如果省略这一设置,Postfix 就会拒绝邮件(拒绝中继访问)或无法投递邮件(寄往 example.com 的邮件会循环回到我自己)。

    切勿将虚拟 MAILBOX 域名列为我的目标域名!

    切勿将虚拟 MAILBOX 域名列为虚拟 ALIAS 域名!

  • 第 3 行 virtual_mailbox_base参数指定了所有虚拟邮箱路径名的前缀。 这是一种安全机制,以防有人出错。 它可以防止邮件被传送到文件系统的各个角落。
  • 第 4 行,第 10-15 行: virtual_mailbox_maps参数指定了包含邮箱(或 maildir)路径名的查找表,并以虚拟邮件地址为索引。 在本例中,寄往 [email protected] 的邮件会进入位于 /var/mail/vhosts/example.com/info 的邮箱,而寄往 [email protected] 的邮件会进入位于 /var/mail/vhosts/example.com/sales/ 的邮件目录。
  • 第 5 行 virtual_minimum_uid指定了邮箱或 maildir 所有者 UID 的下限。 这是一种安全机制,以防有人犯错。 它可以防止邮件被写入敏感文件。
  • 第 6、7 行:virtual_uid_mapsvirtual_gid_maps参数指定所有虚拟邮箱都由固定的 uid 和 gid 5000 所拥有。 如果这不是你想要的,可指定按收件人邮件地址搜索的查找表。
  • 第 14 行:已注释的条目(#后面的文字)显示了如何实现一网打尽的虚拟邮箱地址。 请做好收到大量垃圾邮件以及被退回的以 [email protected] 名义发送的垃圾邮件的准备。

    切勿在虚拟 ALIAS 文件中添加虚拟 MAILBOX 通配符!!

  • 第 8、17、18 行:正如您所看到的,虚拟别名和虚拟邮箱是可以混合使用的。 我们使用这一功能将 example.com 的邮局管理员地址的邮件重定向到本地邮局管理员。 您也可以使用同样的机制将地址重定向到远程地址。
  • 第 18 行:本例假定在main.cf 中,$myorigin 已列在mydestination参数设置下。 如果不是这种情况,则应在虚拟别名表项的右侧指定一个明确的域名,否则邮件将发送到错误的域名。

更改虚拟文件后执行"postmap/etc/postfix/virtual"命令,更改vmailbox文件后执行"postmap/etc/postfix/vmailbox"命令,更改main.cf文件后执行 "postfix reload"命令。

注意:邮件发送时,收件人的UID/GID权限是通过virtual_uid_mapsvirtual_gid_maps指定的。 Postfix 2.0 及更早版本不会在世界可写入的父目录中创建 mailDIR,必须事先创建后才能使用。 Postfix 可能会根据父目录的写入权限自行创建 mailBOX 文件,但提前创建 mailBOX 文件更为安全。

有关虚拟邮箱投递代理的更多详情,请参阅 virtual(8)手册页面。

非 Postfix 邮箱存储:独立域、非 UNIX 账户

这是 Postfix虚拟邮箱示例的变体。 同样,每个托管地址都可以拥有自己的邮箱。 不过,控制virtual(8)发送代理的大多数参数已不再适用:只有virtual_mailbox_domainsvirtual_mailbox_maps仍然有效。 需要使用这些参数来拒收未知收件人的邮件。

在使用非 Postfix 软件进行最终投递时,仍然需要一些 Postfix 概念,以便将所有内容粘合在一起。 有关这种粘合的更多背景信息,您可能需要查看ADDRESS_CLASS_README文件中定义的虚拟邮箱域类

本节中的文字描述了从 Postfix 的角度来看事情应该是怎样的。 有关 Cyrus 或 Courier maildrop 的具体信息,请参阅CYRUS_READMEMAILDROP_README

下面是一个向非邮递区号投递代理投递的托管域example.com 的示例:

 1 /etc/postfix/main.cf:
 2     virtual_transport = ...see below...
 3     virtual_mailbox_domains = example.com ...more domains...
 4     virtual_mailbox_maps = hash:/etc/postfix/vmailbox
 5     virtual_alias_maps = hash:/etc/postfix/virtual
 6 
 7 /etc/postfix/vmailbox:
 8     [email protected]    whatever
 9     [email protected]   whatever
10     # 注释下面的条目,以实施一网打尽。
11     # 配置邮箱存储以接受所有地址。
12     # @example.com      whatever
13     ...更多域名的虚拟邮箱...
14 
15 /etc/postfix/virtual:
16     [email protected] postmaster

备注:

  • 第 2 行: 在向托管域的非 Postfix 邮箱存储空间发送邮件时,virtual_transport参数通常指定 Postfix LMTP 客户端,或通过管道发送代理执行非 Postfix 软件的master.cf条目名称。 典型示例(仅使用一个):
  • virtual_transport = lmtp:unix:/path/name (使用 UNIX 域套接字)
    virtual_transport = lmtp:hostname:port   (使用 TCP 套接字)
    virtual_transport = maildrop:            (使用 pipe(8) 连接命令)
    
  • Postfix 已支持 LMTP。 默认的 Postfixmaster.cf文件中已经定义了 maildrop 发送方法示例。 更多详情,请参阅MAILDROP_README文件。
  • 第 3 行: virtual_mailbox_domains设置告诉 Postfix,example.com 将通过上一段讨论过的virtual_transport发送。 如果省略了virtual_mailbox_domains设置,Postfix 要么拒收邮件(拒绝中继访问),要么无法投递邮件(example.com 的邮件会循环回到我自己)。

    切勿将虚拟邮箱域名列为我的目标域名!

    切勿将虚拟 MAILBOX 域名列为虚拟 ALIAS 域名!

  • 第 4、7-13 行:virtual_mailbox_maps参数指定了包含所有有效收件人地址的查找表。 Postfix 会忽略查找结果值。 在上述示例中,[email protected][email protected] 被列为有效地址;其他寄往 example.com 的邮件会被 Postfix SMTP 服务器以 "用户未知 "为由拒收。 由非 Postfix 发送代理来拒绝本地提交或本地别名扩展中不存在的收件人。 如果您打算使用 LDAP、MySQL 或 PgSQL 代替本地文件,请务必查看本文档顶部的"本地文件与数据库 "部分!
  • 第 12 行:注释项(#后面的文字)显示了如何通知 Postfix 存在一个总括地址。 同样,Postfix 会忽略查询结果。

    切勿在虚拟 ALIAS 文件中加入虚拟 MAILBOX 通配符!

    注意:如果在virtual_mailbox_maps 中指定了通配符,则仍需配置非 Postfix 邮箱存储,以接收该域中任何地址的邮件。

  • 第 5、15 和 16 行:如上所述,可以将虚拟别名与虚拟邮箱混合使用。 我们使用这一功能将 example.com 的邮局管理员地址的邮件重定向到本地邮局管理员。 您可以使用相同的机制将任何地址重定向到本地或远程地址。
  • 第 16 行:本例假定在main.cf 中,$myorigin 已列在mydestination参数设置下。 如果不是这种情况,则应在虚拟别名表项的右侧指定一个明确的域名,否则邮件将发送到错误的域名。
  • 更改虚拟文件后执行"postmap/etc/postfix/virtual"命令,更改vmailbox文件后执行"postmap/etc/postfix/vmailbox"命令,更改main.cf文件后执行 "postfix reload"命令。

邮件转发域

有些提供商托管的域没有(或只有几个)本地邮箱。 这些域的主要用途是将邮件转发到其他地方。 下面的示例显示了如何将 example.com 设置为邮件转发域:

 1 /etc/postfix/main.cf:
 2     virtual_alias_domains = example.com ...other hosted domains...
 3     virtual_alias_maps = hash:/etc/postfix/virtual
 4 
 5 /etc/postfix/virtual:
 6     [email protected] postmaster
 7     [email protected]        joe@somewhere
 8     [email protected]       jane@somewhere-else
 9     # 取消对以下条目的注释,以执行一网打尽地址
10     # @example.com         jim@yet-another-site
11     ...virtual aliases for more domains...

备注:

  • 第 2 行: virtual_alias_domains设置告诉 Postfix example.com 是所谓的虚拟别名域。 如果省略此设置,Postfix 将拒绝邮件(拒绝中继访问)或无法投递邮件(寄往 example.com 的邮件会循环回到我自己)。

    切勿将虚拟别名域名列为我的目标域名!

  • 第 3-11 行:/etc/postfix/virtual 文件包含虚拟别名。 在上面的示例中,寄给 [email protected] 的邮件将发送给本地邮政局长,寄给 [email protected] 的邮件将发送给远程地址 joe@somewhere,寄给 [email protected] 的邮件将发送给远程地址 jane@somewhere-else。 寄往 example.com 中所有其他地址的邮件都会被拒收,并显示错误信息 "用户未知"。
  • 第 10 行:注释出的条目(#后面的文字)显示了如何实现一个 "一网打尽 "的虚拟别名,接收虚拟别名文件中未列出的所有 example.com 地址的邮件。 这样做并非没有风险。 现在的垃圾邮件发送者会尝试从他们能想到的每一个可能的名称发送邮件(或将邮件发送到他们能想到的每一个可能的名称)。 一个 "一网打尽 "的邮箱很可能会收到很多垃圾邮件,也会收到很多以 [email protected] 名义发送的垃圾邮件被退回。

更改虚拟文件后执行命令"postmap /etc/postfix/virtual",更改main.cf文件后执行命令"postfix reload"。

关于虚拟别名文件的更多详情,请参阅 virtual(5)手册页面,其中包括右侧的多个地址。

邮件列表

上面的示例已经说明了如何将虚拟邮局管理员地址的邮件发送给本地邮局管理员。 您可以使用相同的方法将任何地址的邮件直接发送到本地或远程地址。

有一个主要限制:虚拟别名和虚拟邮箱不能直接投递到邮件列表管理器(如 majordomo)。 解决方法是设置虚拟别名,将虚拟地址直接发送到本地投递代理:

/etc/postfix/main.cf:
    virtual_alias_maps = hash:/etc/postfix/virtual
/etc/postfix/virtual:
    [email protected] listname-request
    [email protected]         listname
    [email protected]   owner-listname
/etc/aliases:
    listname: "|/some/where/majordomo/wrapper ..."
    owner-listname: ...
    listname-request: ...

本例假定在main.cf 中,$myorigin 已列在mydestination参数设置下。 如果不是这种情况,请在虚拟别名表项的右侧指定一个明确的域名,否则邮件就会发送到错误的域名。

有关 Postfix 本地投递代理的更多信息,请参阅local(8)手册页面。

为什么这个示例使用了笨拙的虚拟别名,而不是更优雅的传输映射? 原因是虚拟邮件列表的邮件会以 "用户未知 "被拒收。 为了使传输映射正常工作,仍然需要大量的虚拟别名或虚拟邮箱表项。

  • 如果是虚拟别名域,每个邮件列表地址都需要有一个身份映射。
  • 如果是虚拟邮箱域,则需要为每个邮件列表地址设置一个虚拟邮箱。

自动回复

为了在正常发送邮件的同时为虚拟收件人设置自动回复,可在虚拟别名表中设置一条规则:

/etc/postfix/main.cf:
    virtual_alias_maps = hash:/etc/postfix/virtual
/etc/postfix/virtual:
    [email protected] [email protected], [email protected]@autoreply.mydomain.tld

Tautoreply.mydomain.tld 会将邮件发送给收件人,并将邮件副本发送到产生自动回复的地址。 该地址可以在另一台机器上提供服务,也可以在本地提供服务,方法是设置一个传输映射条目,将所有发往 autoreply.mydomain .tld 的邮件导入某个脚本,该脚本会将自动回复发送给发件人。

请勿将 autoreply.mydomain.tld 列在mydestination.tld 中!

/etc/postfix/main.cf:
    transport_maps = hash:/etc/postfix/transport
/etc/postfix/transport:
    autoreply.mydomain.tld  autoreply:
/etc/postfix/master.cf:
    # =============================================================
    # service type  private unpriv  chroot  wakeup  maxproc command
    #               (yes)   (yes)   (yes)   (never) (100)
    # =============================================================
    autoreply unix  -       n       n       -       -       pipe
        flags= user=nobody argv=/path/to/autoreply $sender $mailbox

这将调用 /path/to/autoreply,并在命令行中输入发件人地址和 [email protected] 收件人地址。

更多信息,请参阅pipe(8)手册页面和 Postfixmaster.cf文件中的注释。