这篇文档的目的
这篇文档要求postfix 2.0及以后的版本
这篇文档总述了:postfix怎样承载多个internet域;一些域是邮件传递的最终目的域,另一些域是出于转发目的地域。
这篇文档不仅描述了postfix内建的传输机制,而且给出了使用非postfix邮件传递软件的建议。
这篇文档涉及以下主题:
权威域对宿主域对其他域
本地文件对网络数据库
共享域,Unix系统账号
postfix虚拟别名示例:独立域,unix系统账号
postfix虚拟邮箱示例:独立域,非unix账号
非postfix邮箱存储:独立域,非unix账号
邮件转发域
邮件列表
自动回复
权威域对宿主域对其他域
大部分的postfix系统都是域的最后目的地。这些域包括了postfix主机的FQDN和IP地址,有时也包括了主机名的父域。这篇文档接下来的部分将把这些域看作是权威域(即权威域是postfix主机名的域,如:postfix的FQDN为mail.linux.com,那么linux.com就是这台postfix的权威域)。
除了权威域,postfix可以被配置为非权威的额外域的最后目的地。这些域叫做宿主域,因为他们与postfix主机名无关。宿主域一般与虚拟别名域或虚拟邮箱域为同一类,具体的定义参见ADDRESS_CLASS_README文件。
postfix还可以被配置为其他域的备份mx主机。在这种情况下,postfix不是这些域的最后目的地。当postfix主mx主机down机时,它接收邮件放在队列中。这个功能与中继域地址类别相同,具体定义在ADDRESS_CLASS_README文件中。
最后,postfix被配置为传递主机,它把邮件传递到internet上。很明显,postfix不是这些邮件的最后目的地。这个功能仅对授权的客户端和用户生效;它与默认域地址类别相同,具体定义在ADDRESS_CLASS_README文件中。
本地文件对网络数据库
这里的示例使用了本地文件的表查询,如:DBM或Berkeley DB。用postmap命令很容易调试:
示例:
postmap -q info@example.com hash:/etc/postfix/virtual
用数据库来代替本地文件,参见LDAP_README, MYSQL_README 和 PGSQL_README 。强烈建议读者在先把本地文件调试正常后,在迁移到网络数据库上。使用postmap命令查询网络数据库的查询结果是否与本地文件查询结果一致。
示例:
 postmap -q info@example.com ldap:/etc/postfix/virtual.cf
共享域,unix系统帐户
宿主额外域最简单的方法是:把域名添加到postfix的mydestination参数中去,然后把用户名添加到unix密码文件中去。
权威域与宿主域之间没有区别。用户能接收没有域的邮件。
在下面的例子中,我用example.com作为这台postfix的宿主域。
/etc/postfix/main.cf:
    mydestination = $myhostname localhost.$mydomain ... example.com
 
这个方法的缺陷是:
发送给 info@my.host.name的邮件也会传递给 info@example.com
用户存放在unix密码文件中,大量用户的维护将变得困难。
下面的例子对这两个缺陷提供了解决方法。
postfix虚拟别名示例:独立域,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     postmaster@example.com postmaster
 7     info@example.com       joe
 8     sales@example.com      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的邮件产生死循环)
不要把虚拟别名域写入mydestination参数中去。
第3-8行:/etc/postfix/virtual文件包含了虚拟别名。上面的这个示例,发给 postmaster@example.com的邮件会转发给本地的postmaster,而发给 info@example.com的邮件会转发给joe系统帐户。
第10行:一个全部的(catch-all)虚拟别名接收在虚拟别名文件中example.com没有列出的地址的邮件。这存在一定的风险。垃圾邮件制造者可能给可能的用户名发邮件,所以,一个所有的(catch-all)邮箱可能会接收到许多垃圾邮件。许多垃圾邮件的反弹邮件是以 anything@example.com发送的。
在改变了virtual的内容后,执行"postmap /etc/postfix/virtual"命令,然后用"postfix reload"重载main.cf文件
注意:虚拟别名既可以解析为一个本地地址,也可以解析为一个远程地址。他们不需要一定解析到本地的unix系统帐户上
更多关于虚拟别名文件的信息参见virtual(5)手册。
虚拟别名解决了一个问题:它允许每一个域有它自己的邮件地址。但是,仍然有一个缺陷:每一个虚拟地址都会映射到unix系统帐户上。随着虚拟地址的增加,unix系统账号也会相应的增长。接下来的部分将解决这个问题。
postfix虚拟邮箱示例:独立域,非unix帐户
随着域和用户的增长,unix/linux系统不可能给每一个用户分配一个系统帐户。
通过postfix的virtual(8)邮箱投递代理,每一个接收者地址都能有它自己的虚拟邮箱。不想虚拟别名域,虚拟邮箱域不需要把每一个接收者地址笨拙的转换为一个系统帐户地址。
postfix的virtual(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     info@example.com    example.com/info
12     sales@example.com   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     postmaster@example.com postmaster
注意:
第2行:virtual_mailbox_domains设置告诉postfix:postfix是虚拟邮箱域。如果你忘了这个设置,postfix将会拒绝邮件(中继访问也拒绝),或者无法传递(发给example.com的邮件产生自循环)
不要把虚拟邮箱域名列在mydestination参数值中!
不要把虚拟邮箱域名列在virtual_alias_domains的参数值中!
第3行:virtual_mailbox_base参数为所有的虚拟邮箱路径指定了一个共同的前缀。这是一个安全的机制,以免某些人做错。这可以阻止邮件被传递到所有的文件系统上。
第4,10-15行:virtual_maibox_maps参数指定了用mailbox(或者maildir)路径名的查询表,它通过vuni邮件地址进行索引。在下面的这个示例中,发给 info@example.com的邮件将会被放到/var/mail/vhost/example.com/info,而发给 sales@example.com的邮件将会被放在/var/mail/vhosts/exampe.com/sales/目录下。
第5行:virtual_minimum_uid为mailbox/maildir所有者的UID指定了一个最小值。这是一个安全机制,以免出错。这阻止邮件写到敏感的文件中去。
第6,7行:virtual_uid_maps和virtual_gid_maps参数指定了所有虚拟邮箱的所有者的uid和gid的值为5000。如果你不希望uid和gid是固定值,可以指定一个查询表。
第14行:该注释项显示了如何使用所有的(catch-all)虚拟邮箱地址。它被用户接受垃圾邮件,也用于以 anything@example.com的名义发送垃圾邮件的反弹邮件。
不要把虚拟邮箱通配符放到虚拟别名文件中去!!
第8,17,18行:这可能是虚拟别名与虚拟邮箱的混合使用。我盟使用这个功能把发给example.com的postmaster的邮件转发到本地的postmaster。你能使用同样的机制转发一个地址到远程地址上去。
第18行:这个示例假设:main.cf中的$myorigin值列在了mydestination参数设置中。如果不是这种情形,请在虚拟别名表的右边明确的指定一个域名,否则邮件将会被投递到错误的域中。
当virtual文件的内容改变后,执行"postmap /etc/postfix/virtual"命令。当改变了vmailbox文件的内容,执行"postmap /etc/postfix/vmailbox"命令。当改变了main.cf的内容,执行"postfix reload"命令。
注意:邮件投递是以virtual_uid_maps和virtual_gid_maps中指定的接收者uid/gid身份进行的。postfix 2.0以前的版本无法在可写的父目录中创建maildir;你必须在使用前先创建这些目录。postfix在父目录可写的情况下可以自己创建mailbox,但事先创建文件更安全点。
关于虚拟邮箱投递代理的更详细的信息,参见virtual(8)手册。
非postfix邮箱存储:独立域,非unix帐户
这是在postfix虚拟邮箱基础上的进一步改进。每一个宿主邮箱地址有它自己独立的邮箱。
当非postfix软件用于最后的投递时,仍需要一些postfix概念以便邮件顺利发送。
这部分的内容描述了:从postfix的角度,这应该是什么样的。关于cyrus/courier的maildrop的信息,参见CYRUS_README 或者 MAILDROP_README
下面是宿主域example.com投递邮件给非postfix投递代理的示例:
 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     info@example.com    whatever
 9     sales@example.com   whatever
10     # Comment out the entry below to implement a catch-all.
11     # Configure the mailbox store to accept all addresses.
12     # @example.com      whatever
13     ...virtual mailboxes for more domains...
14
15 /etc/postfix/virtual:
16     postmaster@example.com postmaster
注意:
第2行:为了投递给宿主域的非postfix邮箱存储,virtual_tranport参数需要指定一个postfix的LMTP客户端,或者通过管道投递代理执行非postfix软件。下面是典型的示例(仅使用一个就可以了):
virtual_transport = lmtp:unix:/path/name (uses UNIX-domain socket)
virtual_transport = lmtp:hostname:port   (uses TCP socket)
virtual_transport = maildrop:            (uses pipe(8) to command)
postfix已经做好支持LMTP的准备了。maildrop投递方法的示例已经定义在了默认的master.cf文件中了,更详细的内容参见MAILDROP_README文档。
第3行:virtual_mailbox_domains设置告诉postfix:example.com通过virtual_transport来投递邮件。如果你忘了virtual_mailbox_domains参数的设置,postfix将拒收邮件,或者无法传递邮件。
不要把虚拟邮箱的域名列在mydestination中!
不要把虚拟邮箱的域名列在虚拟别名与中!
第4,7-13行:virtual_mailbox_maps参数指定了包含所有有效接收者地址的查询表。查询结果只被postfix忽略。在上面的例子中, info@example.comsales@example.com列在了有效地址中;其他给example.com的邮件都被postfix的smtp服务器用"未知的用户"所拒绝。这是留给非postfix投递代理用以拒绝本地提交的不存在接收者。如果你准备用LDAP,MySQL或者PgSQL来代替本地文件,请了解本文档的"本地文件对数据库"的内容。
第12行:这个注释项显示了怎样让postfix知道所有的有效邮件地址。擦汗讯结果会被postfix忽略
不要把虚拟邮箱通配符放在虚拟别名文件中!!
注意:如果你在virtual_mailbox_maps中指定了通配符,那么你需要配置非postfix邮箱存储来接收那个域的任何邮件。
第5,15,16行:同时使用虚拟别名与虚拟邮箱是可能的。我们使用这个功能把 postmaster@example.com重定向到本地的postmaster中。你也可以使用同样的机制重定向邮件到本地或远程箱
第16行:这个示例假设:main.cf中的$myorigin值列在了mydestination参数设置中。如果不是这种情形,请在虚拟别名表的右边明确的指定一个域名,否则邮件将会被投递到错误的域中。
当virtual文件的内容改变后,执行"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     postmaster@example.com postmaster
 7     joe@example.com        joe@somewhere
 8     jane@example.com       jane@somewhere-else
 9     # Uncomment entry below to implement a catch-all address
10     # @example.com         jim@yet-another-site
11     ...virtual aliases for more domains...
Notes:
第2行:virtual_alias_domains设置告诉postfix:example.com是虚拟别名域。如果你忘记这个设置,postfix将拒收邮件,或者无法投递邮件。
不要把虚拟别名的域名列在mydestination中!
第3-11行:/etc/postfix/virtual文件包含了虚拟别名。在上面的示例中,发给 postmaster@example.com的邮件会转发到本地的postmaster中去,而发给 joe@example.com的邮件转发到远程的邮件地址 --joe@somewhere;发送给 jane@example.com的邮件被转发到 jane@somewhere邮箱。发送给example.com的其他邮件都会被postfix以"未知用户"而拒绝
第10行:注释项显示了 jim@yet-another-site邮箱接收所有发给在example.com域中不存在的邮箱地址。这存在一定的风险。现在的垃圾邮件发送者尝试非可能存在的用户名发送邮件。catch-all邮箱可能接收许多垃圾邮件,许多垃圾邮件的反弹邮件会以 anything@example.com的名义发送。
当virtual的文件内容改变时,执行"postmap /etc/postfix/virtual"命令。当main.cf的文件改变时,执行"postfix reload"命令。
更多关于虚拟别名文件的信息参见virtual(5)手册。
邮件列表
前面的一些示例已经展现了如何把虚拟域的postmaster邮件转发到本地postmaster中去。你能用同样的方法把任何一个地址的邮件转发本地或远程地址
这里有一个重要的限制:虚拟别名和虚拟邮箱不能直接传递邮件列表管理器,如:majordomo。这个限制的解决办法是安装一个虚拟别名--通过它把虚拟地址导向本地传输代理:
/etc/postfix/main.cf:
    virtual_alias_maps = hash:/etc/postfix/virtual
/etc/postfix/virtual:
    listname-request@example.com listname-request
    listname@example.com         listname
    owner-listname@example.com   owner-listname
/etc/aliases:
    listname: "|/some/where/majordomo/wrapper ..."
    owner-listname: ...
    listname-request: ...
T
这个示例假设:main.cf中的$myorigin值列在了mydestination参数设置中。如果不是这种情形,请在虚拟别名表的右边明确的指定一个域名,否则邮件将会被投递到错误的域中。
更多关于postfix的本地投递代理信息,参见local(8)手册。
为什么这个示例使用一个复杂的虚拟别名来代替间接地传输映射呢?这个理由是:发送给虚拟邮件列表的邮件会以"不存在的用户"原因而被拒绝。为了确保传输映射的正常工作,postfix需要很多虚拟别名表或者虚拟邮箱表
在虚拟别名域的情形中,需要有一个从每一个邮件列表地址到自身的身份映射
在虚拟邮箱域的情形中,对每个邮件列表地址需要有个假的邮箱。
自动回复
为了给虚拟接收者配置一个自动回复,到虚拟别名表中设置一个规则:
/etc/postfix/main.cf:
    virtual_alias_maps = hash:/etc/postfix/virtual
传递邮件给接收者,同时发送一份邮件的副本给产生自动回复邮件的邮件地址。这个地址可以工作在不同的计算机上,或者通过配置一个传递映射项服务于本地系统--这个传输映射项把所有发给autoreply.mydomain.tld的邮件传递给一个自动回复的脚本。
不要把autoreply.mydomain.tld列在mydestination中!
/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
这个是用发送者地址和the user@domain.tld的接收者地址来调用/path/to/autoreply
更详细的信息查看pipe(8)手册,这内容在master.cf文件中。