Postfix的投递过程详解(1)


在我们讨论本地邮件的投递过程之前,先让我们理清“本地”、“外地”、“虚拟”这三种邮件的定义以及相关的MDA.

Postfix的投递代理程序

postfix依据来信地址来决定是否要收下邮件以及如何选择适当的MDA来执行后续的投递任务。postfix会收下三种网域的邮件,分别是本地(local)、转发(relay)以及虚拟(virtual),它们的定义与相关的MDA,如下:

本地邮件

若邮件终点站是mydestination参数所列出的网域之一,postfix就视其为本地邮件,由local MDA(或是你指定的其他程序)执行投递任务。本地邮件的收件者必须拥有本地系统(postfix server本身所在的主机)的用户账户,或是其名称被定义在别名文件(传统上是/etc/aliases)。本地邮件会被投递到系统的邮件存储目录(通 常是/var/spool/mail/),或个人主目录下的邮件文件(~/mail/)。

转发邮件

若邮件终点站是relay_domains参数所列出的网域之一,postfix就视其为转发邮件,由relay MDA来执行投递任务。一般而言,只有在postfix被当成局域网络的邮件网关使用,而同网络上还有其他网域的邮件服务器时,才会让postfix收下 转发邮件。也就是说,所谓的“转发”,通常是指同局域网络上的其他主机,而relay其实是smtp MDA的翻版,只不过被刻意设计成特别适合传信给局域网络上主机而已。

虚拟网域邮件

一台邮件服务器通常只服务一个范围网域 (canonical domain);如果要同时服务多个网域,则额外的网域称为虚拟网域(virtual domain)。虚拟网域的邮件由virtual MDA负责投递。依据用户是否有服务器的系统账号,虚拟网域的邮件还可分成“虚拟邮箱”与“虚拟别名”两种。虚拟邮箱的收件人没有系统账户,而且每一个虚 拟邮箱网域都有自己的邮箱目录(mail spool),所有虚拟邮箱网域都必须列于virtual_mailbox_domains参数。另一方面,虚拟别名网域的收件人可以拥有本地或非本地系 统账户,postfix会改写这类邮件的收件地址,然后交给smtp MDA递送出去(如果新地址是非本地网域),或重新回到收件队列(如果新地址是本地网域)。

邮箱格式

当postfix投 递本地邮件时,邮件内容会被传送到postfix系统上的适当邮箱。最常见的两种邮箱格式,分别是传统的mbox以及较新的 maildir。两者都是使用一般的文件来储存邮件内容,差别在于文件内部的组织安排有所不同。在postfix中,当你设定任何邮件文件或目录参数时, 如果在路径末端加注一个/符号,表示你想使用maildir格式的邮箱。

mbox格式

传统上,unix系统将同一位用户 的所有邮件都塞在同一个文件里,像这样的邮箱格式通常称为mbox。邮箱文件里的每一封邮件,其第一行的前五个字符必定是“from ”。习惯上,为了方便表示,我们通常将它写成“from_“,以下划线字符强调空格的存在请勿将mbox文件内用来分隔邮件的”from “字样与邮件标头里的”from:“字段混为一谈。邮件在mbox文件里的最后一行必定为空格。因此,一行空格接着一个from_字样,就可视为下一封信 的开始。

postfix将邮件写入mbox文件之前,会先使用信封上的寄件人地址与当时的日期创建好from_文本行,并将该行字符串写到 mbox文件的末端,然后才开始填入邮件内容。如果postfix发现邮件内容本身有任何以“from”开头的文本行,它会在该文本行的开头加一个 >符号,避免该文本行被误以为下一封信的开头。

当pop/imap server读取mbox文件内的邮件时,第一步是扫描文件内容,找出代表邮件开头的from文本行。在读取邮件内容时,如果遇到下一个from_文本行 (或文件结尾),就可断定当前的邮件已经读完了。有些pop/imap server会主动恢复">from"的原状,但有些不会。

由于 postfix和pop/imap server有可能会同时访问同一个mbox文件,所有它们必须使用“文件锁定机制”(file locking)来确保访问权。在local投递本地邮件之前,必须先将该文件加锁,然后才能将邮件内容写入mbox文件。postfix支持多种锁定机 制,视系统平台而定。利用postconf -l命令可查看你的系统提供了哪些锁定机制可供postfix使用:

postconf -l

如果想知道postfix在你系统上列出的各种锁定机制的详细信息,请把锁定机制的名称告诉man:

man folck

如 果你的系统平台支持flock和fcntl,应该就可以找到它们的在线说明文件,因为这两者都是操作系统或函数库提供的功能,而任何系统平台都支持的 dotlock机制,很可能找不到说明文件,因为dotlock只是程序之间一种不成文协议,不需要额外的函数库。dotlock的原理很简单,举个例子 就可以说明清楚。假设postfix要访问user1邮件文件,它必须先检查该文件的同目录下是否存在一个.user1.lock文件,如果存在,表示 user1邮件文件当前被另一个进程占用;如果.user1.lock文件步存在,postfix就自己产生一个,让其他进程知道user1文件当前正被 占用。在postfix关闭user1文件之后,要主动移除.user1.lock文件,让其他进程可以使用user1邮件文件。dotlock锁定机制 的缺点是它没有强制性(任何进程都可以不检查,user1.lock是否存在而径直访问user1文件),而且效率不佳。

通常你可以不必担心锁定机制的细节,也不必理会系统支持哪些类型的锁定机制,因为postfix能自动做出最佳选择。

maildir格式

maildir 邮箱格式不同于mbox之处,在于它使用目录结构来存储邮件。maildir的设计原意为了解决mbox格式的可能性与文件锁定问题。例如,如果在邮件内 容还没完全写入mbox文件之前,系统就死机了,这时候可能只有部分内容在邮箱里。当系统恢复运行,MDA将邮件写入邮箱时,新的内容会接在前次残缺内容 的后面,因而造成问题。

mbox格式的另一个缺点,是发生在pop/imap server与smtp server试图同时开启同一个邮箱时。如果双方没有使用相同的锁定机制,邮箱文件可能因此受损。先前说过,保护文件的锁定机制有好几种,但是并非所有邮 件程序都使用锁定机制。但如果使用maildir格式,则可以不使用文件保护锁,因为每一封邮件都是存放在单独的一个文件里。因此,不用的邮件程序,不可 能同时访问同一个文件。

一个maildir风格的目录,其下有三个子目录:tmp/、new/以及cur/。这些子目录与它们的上层目录必须位于同一个文件系统,习惯上,它们应该放在用户的主目录的邮件目录下

在new/目录下的邮件文件,是MDA已经送达但是尚未被用户阅读的信,文件本身的修改时间,就是收下邮件的时间。邮件文件通常包含RFC 2822格式的邮件,而且不需要“from_"。

用户看过邮件之后,邮件文件会被转移到cur/目录。tmp/目录供MDA将邮件内容存储成文件,在确定全部内柔都写入文件之后,邮件文件会被搬到new/目录。

应该选择mbox还是maildir?

这 个问题没有简单的答案。哪一种邮箱格式最适合你,取决于许多因素。mbox格式的好处是几乎全世界都支持,但也正是因为它有文件锁定问题,而导致了 maildir格式的出现。而maildir格式在规模适合性方面也颇受质疑,因为某些文件系统可能无法应付太多的邮件文件。在效率方面,两种格式各有各 优缺点:搜索、访问、删除特定邮件时,maildir的速度比较快;但是就MDA的投递工作效率而言,直接将邮件内容放入文本未(mbox格式)可能比较 快。实际上,你的选择可能要看你所用的POP/IMAP SERVER而定,如果你架设的POP/IMAP SERVER只支持maildir格式,很显然你没有选择的余地。postfix对两种格式都支持,所以你只要考虑其他因素就行。如果你的环境让你感觉到 为难,建议你测试两种格式,尽量以接近实际的运行环境和工作量来实验,依据实验结果做出选择。


相关内容