我们提到的所有5种Linux平台都带有一个邮件传输代理。RedHat、Fedora和SUSE提供了sendmail;Debian和Ubuntu默认包含Exim。我们会在18.15节简要介绍一下Exim。Exim的许多组成部分都和sendmail的类似。既然这一章已经写得很长了,所以我们还是只详细讲解sendmail。我们会拿sendmail和Exim等价的成分来介绍Exim。
sendmail之所以能适应标准制订者心血来潮的“奇思妙想”,部分应归功于其配置文件的灵活性,它能让sendmail满足不同用户群的需要。本章接下来的内容主要帮助读者理解和介绍这个配置文件的结构,这个文件就是“声名狼藉”的sendmail.cf。
sendmail是一个传输代理,一个在用户代理和投递代理间充当桥梁的程序。它使用SMTP协议进行通信,通过Internet把消息投递给远程机器上的对等传输代理。sendmail的任务包括:
当消息离开用户的键盘时对它们进行控制;
理解收件人的地址;
选择一个适当的投递或传输代理;
把地址重写为投递代理可理解的形式;
根据需要重新确定信头的格式;
把变换后的消息传递给投递代理。
如果消息无法投递,sendmail还会生成出错消息并把消息返回给发件人。
sendmail的版本
在撰写本书(英文版)的时候,大多数Linux发布商所带的sendmail版本都源于V8。不过在通常情况下,它们要比Sendmail,Inc.(Sendmail有限公司)的主版本号落后一到两个版本。各厂商常常定制sendmail的某个特定版本,以后就不太情愿去升级他们的基本系统,以便把当前的修订版本包括进来。
我们把对sendmail的讨论建立在8.13版的基础上,并完全忽略掉V5和IDA,它们已经被废弃了。V8使用m4宏指令处理器,在标准应用场合下可以很容易配置好。这个“简装版配置”足以满足大多数站点的需要。
很遗憾,如果您的配置有问题,您可能不得不基于对原始配置文件的了解来进行调试,而我们听到的对这个文件的描述是不易接近、使人畏缩、吹毛求疵、隐晦、繁重、无耻、无聊、虐待狂、不好理解、冗长乏味、荒谬、使人迷乱和扭曲的。我们在本书的老版中对原始配置文件的讲解不多,但是因为它和现代系统管理员的关系已经不那么密切了,所以我们现在推荐您参考sendmail软件发布中附带的SendmailInstallationandOperationsGuide一文。
有时发布sendmail的新版本是为了解决安全问题,我们建议您仔细查看www.sendmail.org上的版本说明,如果少了与安全性相关的任何一个补丁,则要进行升级。您通常可以从您的Linux发行商那里直接获得升级后的sendmail软件包,但要确保您收到的二进制软件对应当前的sendmail版本。如果您需要编译和安装从www.sendmail.org直接下载的源代码,那么需要一个C编译器和m4宏指令预处理器(它们通常都包括在标准的Linux发行版本中)。
有时很难确定真正的sendmail基本版本,但如果供应厂商还没有把事情搞得更乱,您就可以运行:
让sendmail透露其版本、编译到它内部的选项,以及读取配置文件之后它认为自己是谁。-d标志设置了一个调试级别(参考18.14.1节了解有关sendmail中调试级别的更多信息),-bt标志将sendmail置于地址测试模式,而来自/dev/null的重定向没有给它提供测试地址。下面是一些输出的例子(稍作过裁减):
sendmail始终会要用到DNSMX(mailexchanger,邮件交换器)记录,而且如果是用NAMED_BIND选项编译的(如前例所示),它就会这么做。像$w这样的单字母变量是从原始配置文件来的,或者是在运行时刻决定的。
从sendmail.org安装sendmail
截至8.12版,sendmail的安装环境稍微有点儿变化。sendmail不再setuid成root来运行,而是setgid成sendmail组—smmsp—来运行。在安装sendmail之前,您必须创建用户smmsp和用户组smmsp(这个神秘的名字代表sendmailmailsubmissionprogram)。我们使用UID和GID25来和SMTP邮件协议知名的端口号相配。这个smmsp用户应该把smmsp作为它的默认登录组,这一般在/etc/passwd文件中设置。增加一个专门的sendmail用户和用户组能够让sendmail运行的时候没有那么大的特权,从而提高了安全性。
从系统管理员的角度来看,第二个主要的变化是sendmail现在使用两个配置文件:submit.cf和sendmail.cf。submit.cf文件控制着如何处理本地主机所发出(并且正在提交给邮件系统)的邮件,sendmail.cf文件控制着传入邮件,以及在提交过程中如何把邮件排队。submit.cf是由软件发布所提供的,对于所有的站点都一样,通常不需要定制它。
本节简要地描述安装过程。详细情况,以及与特定体系结构或操作系统相关的问题,请参考sendmail软件发布中的安装说明。下一节介绍在Debian系统上用apt-get安装sendmail。如果您正在替换供应厂商的sendmail版本,某些配置工作(比如安装帮助文件)可能已经替您完成了。
成员有:
-r-xr-sr-x root smmsp /usr/sbin/sendmail
配置文件/etc/mail/sendmail.cf和/etc/mail/submit.cf(在8.12及以后的版本中),
由系统管理员安装;
-rw-r--r-- root bin /etc/mail/sendmail.cfrw-r--r-- root bin /etc/mail/submit.cf
邮件队列目录/var/spool/mqueue和/var/spool/clientmqueue(在8.12及以后的版本中),
由系统管理员或者安装过程创建;
drwxrwx---smmsp smmsp /var/spool/clientmqueuedrwx------root wheel /var/spool/mqueue
到sendmail的各种链接(newaliases、mailq、hoststat等);
sendmail的更安全的本地投递代理,smrsh和mail.local(通常安装在/usr/libexec中)。
您可以从www.sendmail.org下载sendmail的最新版本。要编译和安装此软件包,可以按照软件目录下的INSTALL文件中的指导来做。首先添加smmsp用户和用户组;不要给这个用户一个实际能用的shell。下面是一个典型的/etc/passwd配置项:
smmsp:x:25:25:Sendmail Mail Submission Prog:/nonexistent:/bin/false下面是一个典型的/etc/group配置项:
要编译这个软件,先进入到软件的sendmail目录下,运行脚本Build,然后再运行Buildinstall。文件devtools/OS/Linux包含了在Linux系统上构造sendmail时所做的假定。Linux发行版本没有对各种东西应该放在何处形成标准,所以devtools/OS/Linux的内容只是尽力所做的猜测,可能不是您发行版本上真正的情况。
不过,在开始编译之前,您必须确定一种数据库格式和一个sendmail与管理数据库(比如NIS)的接口策略。对于磁盘上的数据库,我们推荐BerkeleyDB软件包,它在Makefile中指定为NEWDB(默认情况)。
定制Makefile的时候不要编辑它,而是创建您自己站点的site.config.m4文件,把它放入devtools/Site目录,针对您的操作系统和本地环境来调整它。例如,如果您想要使用LDAP和新的垃圾邮件过滤库,那么可以在那个目录里创建site.config.m4这个文件,其中包含下面这几行:
APPENDDEF(‘confMAPDEF",‘-DLDAPMAP")APPENDDEF(‘confLIBS",‘-lldap -llber")APPENDDEF(‘conf_sendmail_ENVDEF",‘-DMILTER")
define语句会替换这个属性当前的定义,APPENDDEF宏则是追加到当前定义的后面。
编译sendmail用命令:
它将自动把站点的特定项包括进来。要把sendmail安装到正确的位置,运行命令:
$ sudo sh ./Build installsemdial一般不应该设置成由inetd/xinetd来控制,所以它必须在系统引导时由rc文件显式地启动。一般采用的命令序列类似于:
这几行检查sendmail的二进制文件及其配置文件,然后以守护进程的模式启动这个程序。用于您的Linux发行版本的sendmail软件包应该提供一个位于/etc/init.d下正确的启动脚本。
有几种用户代理在它们向邮件系统提交一则用户的消息时,要显式地运行sendmail(有时要带-bm或者-bs标志),而不是直接利用SMTP协议进行通信。在这种情况下,sendmail使用配置文件submit.cf把消息放入/var/spool/clientqueue这个排队用的目录。用-Am或者-Ac标志调用sendmail,迫使消息分别发给mqueue或者clientqueue目录。
RedHat和Fedora有一个sendmail启动脚本(/etc/init.d/sendmail),它不会清理mqueue目录下的内容(如上面的例子所示)。不过,它确实能重构这个数据库。在采用sendmail8.12及以后版本的情况下,可以将LDAP用于数据库映射,而且不必在改动之后重构映射。在/etc/sysconfig/sendmail中定义的参数决定了sendmail是否应该以守护进程模式启动,以及它应该以什么样的频度运行排队操作,所以您应该在那里针对您的站点设置sendmail启动时的行为。RedHat的发布以守护进程模式启动sendmail,而且每30分钟运行一次排队操作。
SUSE的启动脚本(/etc/init.d/sendmail)只是检查二进制和配置文件,然后用环境变量SENDMAIL_ARGS中定义的参数启动sendmail,这些都是在文件/etc/rc.config.d/sendmail.rc.config中设定的。SUSE默认也以守护进程模式运行sendmail,而且每30分钟运行一次排队操作。
如果您的发行版本没有包含一个sendmail启动脚本,那么应该在/etc/init.d/sendmail中加进上面的sh代码片段。安装指导中有一个更漂亮的脚本,它会尝试清理干净以前被中断运行的排队操作。随您高兴是否采用。历史上sendmail的支持文件已经在文件系统的各个可能之处—比如/usr/lib、/etc/usr/ucblib和/usr/share—都呆过了。从8.10版的sendmail起,所有的文件(除了队列目录)都应该保存在/etc/mail目录下。让我们寄希望于厂商能够采纳这项暗示性的建议,把它们始终都放在一个地方。
18.6.3 在Debian和Ubuntu系统上安装sendmail
您可以使用apt-get程序来安装sendmail。它既安装sendmail和m4,也要卸载Exim。在apt-get已经下载并安装完sendmail软件包之后,它就要提示配置这个软件包。选择“是(yes)”,调用一个脚本,它会问您(大约20个)有关您所需要的sendmail配置的问题。每个问题都在中括号里给出了默认的答案,并且有几个特殊的地方给出了可行的配置文件。您需要回答不同于默认值的唯一一个问题就是“mailname”,默认的回答是不全的主机名(例如,lappie),但它需要的是完整的全名(例如,lappie.toadranch.com)。
如果您熟悉sendmail的各种选项和功能(它们将在本章的后面详细介绍),那么回答由脚本提出的问题就更有意义。这个配置脚本不考虑它默认包含的普通域文件的内容。因此,您可以不要一项功能,但最后它还是打开了(例如,redirect功能)。18.6.4 开关文件
Linux系统都有一个称为“服务开关”的配置文件/etc/nsswitch.con,它会列举出可用于满足各种标准查询的方法,比如主机和用户的查找。服务开关还确定对给定类型的查询列出多种方法时,按照什么顺序尝试这些方法。服务开关在第17章中有更详细的讨论。
服务开关的操作通常对软件是透明的,但sendmail喜欢对自己的查找施加更细粒度的控制,于是忽略了系统上的开关文件,而代之以使用自己内部的一个开关配置(/etc/mail/service.switch)。
服务开关中影响邮件系统的两个字段是aliases和hosts。对于hosts来说,主机服务可能的值是dns、nis、nisplus和files。对于aliases来说,可能的值有files、nis、nisplus和ldap。必须在sendmail二进制程序中编译进去对您所用所有机制的支持(除了files之外),才可以使用相应的服务。
sendmail的内部服务开关包括:
aliases filesnisplusnis # if compiled with nis/nis+hosts dns nisplusnisfiles
运行模式
您可以在几种模式下运行sendmail,用-b标志进行选择。-b代表“be”(是)或“become”(变成),它总是和别的标志一起使用,来确定sendmail将扮演的角色。表18.4列出了合法的值。
表18.4 sendmail主要模式的命令行标志
标 志 |
含 义 |
-bd |
在守护进程模式下运行,监听端口25上的连接 |
-bD |
在守护进程模式下运行,但在前台而不是后台a |
-bh |
查看最近的连接信息(等效于hoststat) |
-bH |
清除过时的连接信息在硬盘上的副本(等效于purgestat) |
-bi |
初始化散列的别名(等效于newaliases) |
-bm |
作为邮寄程序(mailer)运行,以通常方式投递邮件(默认) |
-bp |
打印邮件队列(等效于mailq) |
-bP |
通过共享内容打印队列中的项数(8.12及以后版本) |
标 志 |
含 义 |
-bs |
进入SMTP服务程序模式(在标准输入上,不是在端口25上) |
-bt |
进入地址测试模式 |
-bv |
只验证邮件地址,而不发送邮件 |
如果传入的邮件预计是从Internet上来的,那么要在守护进程模式(-bd)下运行sendmail。在这种模式下,sendmail将监听网络端口25并等待任务。在守护进程模式下运行sendmail时,通常也会指定-q标志,它设置的是sendmail处理邮件队列的时间间隔。例如,-q30m或-q1h将每30分钟或每小时运行一次排队操作。
sendmail正常情况下会尝试立即投递消息,把它们暂时保存在队列中只是为了保证可靠性。但是如果您的主机太忙,或者无法到达目的地的机器,sendmail就会把消息排入队列,稍后再发送它。sendmail每次处理队列时会派生出子进程,所以不要把队列处理的时间间隔设置得太短了。RFC1123推荐在两次运行之间至少间隔30分钟。sendmail会进行上锁,所以多个队列同时运行也是安全的。
sendmail8.12已经增加了一种新功能,帮助处理大型的邮递列表和大型的队列:用信封划分队列组。这种功能详细介绍在18.13.2节。
sendmail只在启动的时候读取它的配置文件sendmail.cf。因此,在您改动过配置文件以后,必须杀死它再重新启动,或者向它发送一个HUP信号。sendmail创建一个sendmail.pid文件,其中包含有它的进程ID和启动它的命令。您应该用绝对路径来启动它,因为在接收到HUP信号的时候,它会再次执行这个命令。sendmail.pid文件能够让进程以下面的命令发HUP信号给sendmail:
# kill -HUP ‘head -1 sendmail.pid‘PID文件的位置以前是一个编译时刻的参数,但是它现在可以用.mc配置文件里的confPID_FILE选项来设置。
define(confPID_FILE, ‘/var/run/sendmail.pid’)默认值与OS有关,但通常不是/var/run/sendmail.pid就是/etc/mail/sendmail.pid。RedHat、Fedora、Ubuntu和Debian使用/var/run/sendmail.pid,而SUSE仍然把它保存在/var/run/sendmail目录下。
邮件队列
当机器太忙碌以致不能立即投递邮件,或者当目标机器访问不到的时候,邮件消息就会被保存在队列目录中。sendmail既能作为一个邮件提交代理,监听587端口,也能充当它通常的角色,作为一个守护进程,监听25端口并使用/var/spool/mqueue这个目录作为队列目录。有些用户代理(例如,mh和/bin/mail)使用端口587,这是邮件提交代理的端口,而其他用户代理(Eudora、Outlook等)直接使用SMTP协议和运行在25端口上的sendmail进行通信。从8.12版开始,邮件提交程序使用队列目录/var/spool/clientmqueue和配置文件submit.cf把新消息注入到邮件系统中。所有消息来的时候都暂时进入这个队列。
sendmail允许您有多个邮件队列,而且允许把这些队列的一个子集标为属于一个队列组(queuegroup)。例如,如果目录mqueue包括子目录q1、q2和q3,并且您指定队列目录是/var/spool/mqueue/q*,那么这3个队列都会被用到。sendmail可以处理多个队列的能力提高了它在高负荷下的性能。如果一个站点正在运行一个大型的邮递列表,sendmail就把信封收件人列表分成几个较小的列表,给他们指派不同的队列组。这个技巧能够大大提高性能,因为可以并行处理多个较小的收件人列表。
队列组(queuegroup)是在8.12版sendmail中新出现的功能,它能对各种类型的消息做更细粒度的控制。在队列组上也可以设置任何与队列相关的参数,包括优先级(采用系统调用nice)。邮件根据消息的第一个收件人的地址被提交给不同的队列组。默认的队列组称为mqueue,它是自动定义的,不必做任何进一步的配置就能使用它。我们将在18.13.2节详细介绍队列组。
当消息被放入队列时,它被分段保存在好几个不同文件中。各个文件名有一个两字母的前缀,用来标识其片断,接着是从sendmail进程ID来的一个随机ID。这个ID不是固定的,因为sendmail在不断派生,每个副本会获得一个新的进程ID。表18.5列出了6个可能的片段。
表18.5 邮件队列中的文件所用的前缀
前 缀 |
文件内容 |
前 缀 |
文件内容 |
qf |
消息头和控制文件 |
Tf |
表示上锁操作已经尝试过32次以上 |
df |
消息主体 |
Qf |
表示消息被弹回,不能返回 |
tf |
正在更新qf文件时,它的一个临时版本 |
xf |
邮寄程序(mailer)的出错消息的临时抄本文件 |
如果在队列目录下存在子目录qf、df或xf,那些消息片段就会被放入适当的子目录中。qf文件不仅包含消息头,还包含信封地址、消息无法投递时应该返回的日期、消息在队列中的优先级,以及消息在队列中的原因。每行由一个字母代码开头,这个字母会标识出这一行的其余部分。
每个排入队列的消息必须有qf和df文件。所有其他前缀由sendmail在尝试投递的过程中使用。当一台机器崩溃并重新启动时,sendmail的启动命令序列应该从每个队列目录中删除tf,xf和Tf文件。负责邮件的系统管理员应该经常检查一下Qf文件,以防出现本地配置导致弹回的情况。
使用邮件队列很容易导致错误发生。例如,文件系统可能被填满(请避免把/var/spool/mqueue和/var/spool/news放在同一个分区上),队列可能阻塞,孤立的邮件消息可能会困在队列中。
sendmail有一个配置选项(confMIN_FREE_BLOCKS)可以帮助管理磁盘空间。当包含邮件队列的文件系统变得太满时,邮件将被“tryagainlater(稍微再试)”错误拒绝,直到有更多可用的空间为止。这个选项会留下一小块溢出空间,这样在文件系统完全充满并使得一切都动弹不得之前,邮件就开始被拒绝了。
如果某个主邮件枢纽死机,它的MX备份站点就可能因为数以千计的消息而过载。sendmail可能会派生出过多的副本而让机器死机。有几个选项对改善非常繁忙机器上的性能有帮助,我们将在18.14.2节集中介绍它们。为了处理一个被暂时阻塞的队列,须把阻塞移到一边,像平常一样继续处理新邮件,等一切平静下来再对阻塞队列运行sendmail的一个单独副本。有关DNSMX记录的更多信息请参见15.7.6节。例如,处理单个队列目录的过程类似于下面这样:
在一切平息下来以后,用下面的标志运行sendmail:
# /usr/sbin/sendmail -oQ/var/spool/cloggedqueue -q这些标志把sendmail指向阻塞的队列目录,并指出sendmail应该立即处理它。重复这一命令直到队列为空。从8.12版开始,sendmail使用了硬链接的方式,如果移动了一个队列,那么就会破坏它。处理拥塞队列的一种更好的办法是使用故障后备的主机的MX记录,参见18.13节了解详情。
队列在什么时刻会变得拥塞取决于站点和sendmail所正在运行的硬件。您的系统和aol.com的邮件枢纽(每天要处理数百万消息)采用的拥塞队列的定义是不一样的。参考18.14节了解有关如何测量流量水平的知识。