Postfix的投递过程详解

运维 系统运维
Smtp协议要求收下邮件的MTA,必须负责将邮件送到最终目的地--可能是本地系统的邮箱,也可能同一网络上的其他主机,这段工作过程称为投递(delivery)。本文就给大家重点讲下Postfix的投递的具体过程。

  在我们讨论本地邮件的投递过程之前,先让我们理清“本地”、“外地”、“虚拟”这三种邮件的定义以及相关的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对两种格式都支持,所以你只要考虑其他因素就行。如果你的环境让你感觉到 为难,建议你测试两种格式,尽量以接近实际的运行环境和工作量来实验,依据实验结果做出选择。

#p#

  本地邮件的投递操作

  若收件 地址的网域部分,是列在mydestination参数的所有网域之一,postfix就将其当成本地邮件交给local MDA进行投递。你可以随意在mydestination列出多个网域,但是本地的个别用户会收到所有网域的邮件。举例来说,如果 oreilly.com、ora.com和oreillymedia.com同时被列在mydestination参数,则寄给 kdent@ora.com、kdent@oreilly.com或kdent@oreillymedia.com的邮件,最后都是进入同一个本地邮箱。 为了避免收下不明用户的邮件,所有本地收件人的名称都必须列在local_recipient_maps参数所指的表中。此参数的默认值是指向unix系 统的密码文件与别名表,所以你通常不需要修改它。

  检查邮件地址的人名部分时,postfix先检查别名表。如果发现相符的别名,则以该别名对应的 名称为新的收件人,重新提交邮件,当成新邮件处理;否则,就试着将邮件传给系统上的用户。postfix先检查当地用户是否设置了自己的.forward 文件,如果有,则依据其设定内容来转寄邮件;乳沟没有,则将邮件放入用户的邮箱。

  .forward文件

  .forward 文件让用户可以设置自己的别名。.forward文件的格式与别名文件的RHS-VALUE部分的格式一样,甚至比其更宽松。比方说,别名文件的RHS- VALUE可以有多个以分号隔开的值,.forward文件也沿用相同惯例,但同时也容许你将值分别写在不同的行。

  .forward文件的拥有权 限必须是收件人的系统账户,而且通常放在用户的主目录下。你可以用forward_path参数来改变.forward文件的存放路径。postfix提 供下列8大变量让你表示.forward文件的存放路径,这些变量的实际值,由投递时的系统环境决定:

  $user 收件人得账户名称(信息来源: /etc/passwd)

  $home 收件人得主目录(信息来源: /etc/passwd)

  $shell 收件人得shell

  $recipient 收件人得完整邮件地址

  $extension 收件地址得人名部分得扩展部分(不一定有),以+之类得分隔符与人名部分风格开。以 user1+labs@example.com为例,$extension等于user1。

  $domain 收件地址的网域部分。

  $local 收件地址的完整人名部分(包括扩展部分在内--如果有的话)。以user1+ labs@example.com为例,$local等于user1+labs。

  $recipient delimiter 收件地址得人名部分与扩展部分之间得分隔符(通常是+)如果你增加对一个非标准得.forward文件得支持,可以参考下面得设定;

  forward_path = /home/$user/.forward /home/$user/other_forward

  别名投递操作

  当 别名文件指定了一个命令或文件时,postfix必须先将自己得执行身份改成别名文件拥有者,然后以该身份得权限来执行命令,或将邮件内容写入文件。唯一 的例外是别名文件拥有者为root时,这时候postfix使用default_privs参数所指定的账户(默认值为nobody)

  邮箱投递操作

  当postfix 将邮件投递给一位本地用户时,它必须将邮件内容写入该用户在系统上的邮箱。postfix默认使用的邮箱格式是mbox,当你安装postfix时,它会 依据你所用的Unix平台类型来决定邮件存储目录的位置。mail_spool_directory参数可用来指定一个默认之外的目录,而目录路径的指定 方式会影响pstfix选择何种邮件格式。举例来说,假如你这样设定:

  mail_spool_directory = /var/spool/mail

  这表示postfix应该使用mbox格式将邮件存在/var/spool/mail目录下。如果你想改用maildir格式,则必须在目录名称之后附加一个/符号:

  mail_spool_directory = /var/spool/mail/

  你也可以要求postfix将邮件放在用户的主目录下。设定一个相对路径给home_mailbox参数,表示你想要哪一个文件来作为邮箱:

  home_mailbox = mbox

  在路径名称之后附加一个/符号,表示postfix应该使用maildir格式的投递程序:

  home_mailbox = maildir/

  这会使得postfix将邮件投递到用户主目录下的maildir/子目录。

  注意: 使用maildir格式时,postfix通常会自动创建必要的子目录与文件--如果用户的身份权限足够的话。不过,基于安全上的考虑,如果上层目录的权限模式为775,则local MDA不会创建任何额外的文件或目录。

通过上面的文章详细的描述,大家都应该知道了如何用Postfix进行投递的过程。希望对你们有所帮助!
 

【编辑推荐】

  1. PostfixAdmin 配置过程讲解
  2. Postfix的邮件队列管理
  3. 如何安装PostfixAdmin
  4. Postfixadmin安装手册
  5. 如何对Postfix进行资源控制
  6. Postfix中的地址操作大全
  7. 教你如何设置Postfixadmin的自动回复

 

 

  

责任编辑:赵鹏 来源: 互联网
相关推荐

2010-05-25 18:19:41

postfix邮件

2010-06-09 18:17:20

Postfix邮件

2010-06-02 18:00:05

Postfix邮件

2011-01-19 17:30:21

Postfix邮件投递

2011-01-19 09:55:27

postfix

2010-05-14 15:43:32

MySQL数据库

2010-06-02 18:17:09

Postfix邮件

2011-02-21 10:13:38

Postfix

2011-02-21 13:26:47

Postfix邮件处理

2009-11-30 10:21:41

2009-10-10 15:54:55

RHEL 4配置Pos

2011-02-21 13:08:37

postfix配置

2011-01-19 09:16:48

Postfix配置

2011-01-18 15:00:17

Postfix安装

2011-01-18 18:52:14

Postfix结构

2010-06-02 17:07:25

Postfix 转发

2010-07-20 16:19:46

配置Telnet服务

2011-01-19 09:57:48

Postfix控制

2011-02-21 11:14:47

Postfix配置

2011-01-19 13:39:38

Postfix邮件监控
点赞
收藏

51CTO技术栈公众号