refer:http://www.sme-solution.com/postfix/docs/postfix_arch.html
本文最后修改时间: 2005年10月22日 13:27
介绍
本文通过个人对Postfix的使用和官方文档的介绍,对Postfix的体系结构的一些见解,有理解不当的地方还请发邮件指正,邮件地址:。官方文档:http://www.clusting.com/postfix/docs/OVERVIEW.html。
本文主要讨论以下内容:
Postfix如何接收邮件
当一封邮件进入Postfix邮件系统后,首先被放入incoming queue(入口队列). 下图体现了处理一封新邮件涉及的主要进程和顺序。 带数字的名称代表Postfix的命令或服务程序,不带数字的名称代表Postfix的邮件队列。
trivial-
rewrite(8)网络 -> smtpd(8)
^
||
v/ 网络 -> qmqpd(8) -> cleanup(8) -> incoming / pickup(8) <- maildrop ^
|本机 -> sendmail(1) -> postdrop(1)
- 网络邮件通过 smtpd(8) 或 qmqpd(8) 服务器进入Postfix,这两个服务删除邮件的SMTP或QMQP协议封装(去掉协议头,又叫解封),并且强制进行一些邮件健康检查(sanity checks)来保护Postfix,然后将邮件的发送者、接收者地址和邮件内容交给cleanup(8)服务处理。可以通过配置 smtpd(8)服务来阻塞服务器不想接收的邮件,具体的配置方法可以参看:SMTPD_ACCESS_README 。
- 本机发送的邮件是由Postfix自带的 sendmail(1)兼容性命令来处理,并且被特权命令postdrop(1) 放入 maildrop queue队列中进行排队,这种方式使得即使Postfix邮件系统没有运行也能正常工作(本机能够发送邮件,只不过发送完的邮件必须在maildrop queue中,直到Postfix邮件系统启动才能被发送出去。但对用户来讲,不必关心邮件什么时候被发送出去。)。 本地的 pickup(8)服务从maildrop queue中读取本机发送的邮件,并且强制进行一些邮件健康检查(sanity checks)来保护Postfix,然后将邮件的发送者、接收者地址和邮件内容交给cleanup(8)服务处理。
- 内部(Postfix邮件系统本身)发送来的邮件直接被提交给cleanup(8)服务来处理,这部分没有包括在上面的图示中。所谓内部发送的邮件主要包括:被local(8)投递代理转发的邮件(参看下一小节)、被bounce(8)服务(参看下一小节)返回给发送者的邮件以及postmaster关于Postfix系统问题的通知。
- cleanup(8)服务进行邮件进入队列(incoming queue)前的最后一次处理,它将增加一些丢失的消息头、按照地址转换规则(参看 ADDRESS_REWRITING_README)重写邮件地址。另外,cleanup(8)服务可以使用正则表达式配置为轻量级的内容检查器,请参看:BUILTIN_FILTER_README 。 cleanup(8)服务将处理完的邮件以单个文件的方式放入 incoming queue队列,并通知队列管理器有新邮件到达。
- trivial-rewrite(8)服务将邮件地址(发送者)重写为标准的邮件地址格式:"user@fully.qualified.domain",参看:ADDRESS_REWRITING_README 。Postfix当前版本本身不执行地址重写语言(rewriting language),但是大多数情况下我们可以通过表查找或正则表达式来实现。
Postfix如何投递邮件
一封邮件一旦到达incoming queue队列,下一步就是进行投递。下图简要表示了Postfix投递器的主要组件。 带数字的名称代表Postfix的命令或服务程序,不带数字的名称代表Postfix的邮件队列。
trivial-
rewrite(8)smtp(8) -> Network /
^
||
v- lmtp(8) -> Network / incoming -> active -> qmgr(8) --- local(8) -> File, command
^
||
v/ - virtual(8) -> File deferred / pipe(8) -> Command
-
队列管理器(图中的qmgr(8)服务)是Postfix邮件投递的核心,它直接与smtp(8), lmtp(8), local(8), virtual(8), pipe(8), discard(8) 或 error(8)投递代理打交道,并且为一个或多个发送邮件地址发送投递请求。其中, discard(8) 和 error(8) 投递代理比价特殊:它们丢弃或弹回所有的邮件(在上图中没有别列出)。
队列管理器维护一个邮件已经被打开准备投递的active queue(活动队列)。active queue在有可能非常大的incoming queue(入口队列) 或 deferred queues(延迟队列:上未发出的邮件队列)中充当了一个限制窗口的脚色,被限制的active queue防止了在重负荷情况下队列管理器产生内存溢出。
队列管理器同时维护着一个单独的不能被立即投递出去的邮件队列:deferred queue(延迟队列),因此大量邮件在服务器上的积压(backlog)不会减慢服务器对普通队列的访问。要设置队列管理器对被延迟投递的邮件再次投递的策略,请参看文档:QSHAPE_README 和 TUNING_README 。
-
trivial-rewrite(8) 服务根据它的本地和远程地址类的定义决定每个邮件地址的格式,地址类的定义请参看文档:ADDRESS_CLASS_README。附加的邮件路由信息可以可以使用可选的 transport(5) 表来指定。对于谁的邮件地址已经被改变,trivial-rewrite(8) 服务随时查询relocated(5) ,这样的(地址被改变的)邮件地址将被返回给发送者(服务器会给发送者发送一封说明邮件)。
-
smtp(8)客 户程序查询一个目标主机的邮件交换器列表,并根据邮件交换器列表的优先级进行排序,然后从高优先级的服务器开始依次尝试以邮件交换器(目标服务器)连接, 直到其中一个服务器回应为止。然后按照SMTP协议的要求封装邮件的发送者、接收者和邮件内容,这个过程包括将8-bit的MIME邮件内容转换为7- bit的编码。
-
lmtp(8)客户程序使用一种类似SMTP的已经被优化来递送邮件给邮箱服务器(例如cyrus)的协议。使用lmtp(8)的优势是:一台Postfix主机可以通过LMTP为多个邮箱服务器(pop3或imap服务器)服务,同样的,一台邮箱服务器可以被多台Postfix主机服务(接收多台Postfix主机发送来的邮件)。LMTP_README 文档中给出了一些如何使用lmtp(8)客户程序的例子。
-
local(8)投递代理(本地投递代理程序)能够识别标准的Unix邮箱格式mailboxes,Qmail的兼容邮箱格式maildir files,Sendmail风格的aliases(5) 数据库,sendmail风格的为每个用户设置的.forward文件。多个本地投递代理可以并行运行,但是并行投递到同一个用户通常是被限制的。
local(8)投递代理有两种本地投递方式:你可以配置它将本地邮件直接投递到用户主目录下的用户邮箱文件中;你也可以配置它将本地邮件递交给一个外部的程序(例如procmail)来处理,或者你可以指派它将本地邮件递交给其它的postfix投递代理来处理。
-
virtual(8)投递代理(虚拟域投递代理程序)是一个仅能投递到Unix风格的mailbox邮箱和Qmail风格的maildir邮箱的透明代理程序。这个投递代理可以为多个域投递邮件,特别适合在单一的主机上为很多域提供邮件服务的场合。关于虚拟域投递代理的配置,请参考文档:VIRTUAL_README
-
pipe(8)信封是邮件处理系统的外部接口(Postfix的sendmail(1)是内部接口)。该接口是Unix的兼容性接口:它在命令行和输入流中提供信息,并且等待在<sysexits.h>中定义的进程状态代码。基于pipe(8) mailer的例子,请参看文档: MAILDROP_README 和 UUCP_README
Postfix的后台工作
前面两节已经对Postfix服务程序如何处理发送和接收邮件,这些服务器进程都需要依赖那些在后台工作的服务器进程。下面我们将讨论每个服务在它自己的环境中如何工作。带数字的名称代表Postfix的命令或服务程序,不带数字的名称代表Postfix的邮件队列。
-
常驻内存的服务master(8)就像一个督察员,它随时监视Postfix邮件系统的状况。一般情况下当执行“postfix start”命令时该进程就启动,直到系统关闭时才结束。要启动用于接收和投递邮件的Postfix服务器进程,它们必须依赖master(8) (必须先启动master进程),或者接收和投递的服务器进程由于某些原因需要重新启动,它们也必须依赖于master进程。在master.cf配置文件中指定的用于强制限定服务进程个数的选项(参数)也必须依赖master(8)进程。下图简单表示了Postfix启动时后台程序启动的层次关系,图中只列出了邮件处理的后台守护进程。
postfix(1) |
|postfix-script(1) / / |
|/ / postsuper(1) master(8) postlog(1) / / |
|/ / smtpd(8) qmgr(8) local(8) - anvil(8) 服务实现了客户端连接和请求所有的smtpd(8)服务的速率限制,TUNING_README 文档可以指导我们处理SMTP客户端的一些不规范行为(例如并发发送邮件等恶意行为)。anvil(8)服务是在Postfix 2.2 之后的版本中才加入的功能。
Network ->
smtpd(8)
<->
anvil(8)
- bounce(8)、defer(8) 和 trace(8) 服务安照每封邮件一个日志文件的方式分别维护着它们各自的队列目录树,这些信息将用于通知发送者(sender)邮件是否已经被投递出去。
trace(8)服务用于支持(跟踪)Postfix 的 “sendmail -bv”和 “sendmail -v”命令所产生的关于Postfix如何投递邮件的报告信息。该功能是在Postfix 2.1之后的版本中加入的。关于trace(8) 服务的更多信息,请参考:DEBUG_README 。
cleanup(8) -> qmgr(8)
Postfix
queue-> Delivery
agents^
||
v|
v(Non-)
delivery
notice<- bounce(8)
defer(8)
trace(8)<- Queue id,
recipient,
status^
||
vPer-
message
logfiles - flush(8) 服务维护每个目的地址日志,并且实现了ETRN(Extended TuRN的缩写,是SMTP协议的一个扩展,允许两台计算机在一个TCP连接中进行双向邮件传输。) 和 "sendmail -qRdestination" 两种功能,关于ENTR请参考:ETRN_README文档。 flush(8) 服务使得被选中的队列文件可以从 deferred queue (延迟队列) 返回到 incoming queue (入口队列)以便请求继续投递。flush(8) 服务在Postfix 1.0之后的版本中被加入。
incoming
^
deferred^
|smtpd(8)
sendmail(1)
postqueue(1)- Destination
to flush-> flush(8) <- Deferred
destination,
queue id- Delivery
agents,
qmgr(8)^
||
vPer-dest-
ination
logs - proxymap(8) 服务为Postfix进程提供只读表格的查询服务(以只读方式打开表格), 这一功能可以越过chroot的限制,并且在多进程中通过共享已经打开的一个表格的数据,从而减少了同一表格被打开的数量。
-
scache(8) 服务为Postfix的smtp(8)客户维护连接缓存。当一个被选中的目标的连接缓存被开启时,smtp(8) 客户不必在一封邮件传输完后立即断开连接,而是将该连接送入连接缓存服务器以便保持客户端与服务器的连接,smtp(8) 客户继续发出其它的邮件投递请求,直到限定的时间到达才被断开连接(同时该连接从连接缓存服务器中清出)。在连接缓存被保存期间内,smtp(8)进程可以随时请求scache(8)服务使用被缓存的连接进行其它的邮件投递工作,而不必从新与服务器建立连接。为安全起见,Postfix限定了连接可以被缓存(重用)的时间。
当我们投递邮件到一个多邮件服务器的目的地址时,连接缓存可以帮助我们避开那些没有响应的服务器,同时也提高了邮件的投递速度。
smtp(8)
?<->
scache(8)
?<->
smtp(8)
? - showq(8)服务列出Postfix的队列状态。该服务为 mailq(1) 和 postqueue(1) 命令工作。
Output <- mailq(1)
post-
queue(1)<- showq(8) <- Postfix
queue - spawn(8)服务在客户执行基于socket或FIFO请求时运行其它非Postfix命令,命令的标准输入、标准输出和错误输出都直接发送到通讯终端。关于spawn(8)服务的使用可以在 SMTPD_POLICY_README 文档中看到一些实例。
- tlsmgr(8) 服务在 Postfix smtp(8) 客户或 smtpd(8) 服务开启TLS功能时运行,该进程有两重责任:
- 维护 随机数(PRNG)作为 Postfix smtp(8) 客户或 smtpd(8) 服务进程的TLS引擎的种子值,PRNG的状态被定期地存入到一个文件,当 tlsmgr(8) 启动时会读取该文件。
- 维护 Postfix smtp(8) 客户或 smtpd(8) 服务器的TLS会话的密钥缓存。,被保存的会话密钥通过减少TSL会话过程中的运算量提高了系统的性能。
TSL的支持在Postfix 2.2 以后的版本中已经加入,关于Postfix TSL的实现请参考:TLS_README 文档。
Network->
smtpd(8)
?<---seed---
<-session->
tlsmgr(8)
?---seed--->
<-session->
smtp(8)
?->Network / / |
|/ / smtpd
session
cachePRNG
state
filesmtp
session
cache - verify(8)服务在smtpd(8)服务接受一封邮件前交验它的发送者(sender)和接受收者地址是否存在(可用的)。 verify(8)服务通过从投递代理或者队列管理器往Postfix 队列发送消息来校验用户是否可用。关于该程序的描述,请参:ADDRESS_VERIFICATION_README 文档。该服务在Postfix 2.1 之后的版本中加入。
Network -> smtpd(8) <-> verify(8) -> cleanup(8) -> qmgr(8)
Postfix
queue-> Delivery
agents/ / <- <- |
v/ /
Postfix 的常用命令
我们将以Postfix邮件系统的常用命令择要来结束该文档。除了Sendmail的兼容命令sendmail(1), mailq(1), 和 newaliases(1) 外,Postfix系统有自己的工具命令集,下面将列出所有以post开头的命令:
- postfix(1)命令主要控制邮件系统的的操作,使用该命令启动、停止和重新启动邮件系统。
- postalias(1)命令用于维护Postfix aliases(5)数据库。
- postcat(1)命令显示Postfix队列文件的内容。该命令只有具有相应权限的用户才能执行。
- postconf(1)命令用于显示 正在使用的或者修改过的main.cf的配置参数,同时显示系统所依赖的其它信息。
- postdrop(1)命令是当Postfix sendmail(1) 命令为了将邮件送入 maildrop queue 队列目录时运行的邮件发送命令。
- postkick(1) 主要用来产生Postfix内部通讯通道 ,例如当执行shell脚本。
- postlock(1) 命令提供在使用中对Postfix兼容邮箱的锁定(避免多个进程同时修改一封邮件)。
- postlog(1) 命令提供Postfix兼容的日志记录。
- postmap(1) 命令维护Postfix查询表格,例如:canonical(5), virtual(5) 等。该命令与UNIX 的makemap命令相似。
- postqueue(1)命令被sendmail(1) 和 mailq(1) 调用来刷新或列出邮件队列。
- postsuper(1) 命令维护Postfix队列,他删除旧的临时文件,将队列文件移动到相应的目录。该命令在邮件系统启动或从新启动时运行。