Life with qmail -- 中文版(英文版本2 Jan 2006)

原(英)文作者: Dave Sill
本中文版发布时间:14 Apr, 2006
原文web地址: http://www.lifewithqmail.org/

翻译:Jerry Zhou (Jerry underline ZhiJun(@)21cn.com)
原始版权由作者Dave Sill拥有
中文翻译版使用权由原作者和翻译者共同所有, 请不要用于商业用途.
转载, 刊登, 摘录请首先取得原作者和译者的同意

中文版上一版为2003年8月16日, 这个旧版本的讨论和取得请访问这里:lwq2003.justso.cn,
这个版本的讨论主页设在linuxforum 的邮件和DNS服务器版面,可以访问这里到达 lwq2006.justso.cn.
本文为完整的中文版本. 这个版本由Dave Sill收藏于http://www.lifewithqmail.org/.


谨以此翻译的劳动致谢我的父母, 姐姐一家以及很多朋友和同事.
也可以通过我的blog地址找到我: www.justso.cn


紫色小字号为译者注, 包括英文原文考量和一些基础知识.
文中将统一应用英文逗号(,) 和句号(.) 以及引号(")等英文标点符号.

如果哪位港台同胞乐意制作Big5码的版本, 请和我联系.Jerry underline ZhiJun(@)21cn.com. 如果你对里面翻译的文字有任何意见和商榷, 请e-mail译者, 我们一起来把LWQ翻译的更好! 给译者信箱发送邮件, 请指定标题为"For Translations of LWQ". 否则将被作为垃圾邮件处理, 不情之请, 希望见谅.

中文翻译 版本: 2006-4-14
下面是这个版本和2003-8-16版本相比的更新修正:

  • 本版本安装部分完全迁移到netqmail, 相应有比较大的修改;
  • 和2003-8-16相比, 目录和内容中增加了5.12, 5.13 两节; 附录G17, G18 两节; 其他增加的小节和内容不一一赘述;
  • 修改了附录H9的部分赞助连接和文字;
  • 修改了附录H10所有文字, 增加修改了H.10.1 - H.10.7 的内容;
  • 修改了很多翻译BUGs和笔误, 润色了一些语句, 纠正了矛盾的语句;
  • 核对了所有增加的和修改的链接和文字, 重新核对了全文;
  • 核对了所有代码, 是否是<pre></pre>结构, 便于直接复制;
  • 以下为Life with qmail 中文版正文


    目录


    1. 介绍

    1.1. 适合阅读本文的读者

    Life with qmail 的目标读者是那些对qmail有兴趣, 却被归类于业余爱好者, 新手的人, 那些在一台空闲(原文为: a spare PC 译者注)PC机上操作Linux, 希望日后成为经验丰富的系统管理员或邮件系统管理员的人写作的. 如果你发现文章中有缺陷或者不清楚的地方, 请用电子邮件告诉我. (英文) lwq at sill dot org. (译者的电子邮件: Jerry underline ZhiJun(@)21cn.com 译者注).

    各种不同的来源存在着丰富的 qmail相关信息. 其中一些是以新手为目标, 另外一些假定读者具有比较多的经验, Life with qmail 就是一篇试图成为"胶水"性质的文章, 集合这些信息为一体, 不过读者必须首先掌握下面这些基础知识:

    1.2. 什么是 qmail?

    qmail是一个因特网邮件传送代理, (英文: Mail Transfer Agent, 简写为MTA, 译者注) 它运行在UNIX兼容系统下, 是一个直接代替UNIX下 Sendmail软件的邮件传送程序. qmail 使用简单报文传送代理协议 SMTP 传输邮件(Simple Mail Transfer Protocol).


    注意: 它的名字是 "qmail" , 而不是 "Qmail".

    1.3. 为什么用 qmail?

    你的操作系统如果包含一个MTA, 那很有可能是Sendmail, 而你阅读了下面的文档之后, 你可能想(抛弃Sendmail, 另外)找一个更好的MTA了.

    1.3.1. 安全

    qmail 是面向安全而设计的. Sendmail 的历史上出现过很多严重的安全问题. 在编写Sendmail的时代, 网络是非常友好的地方, 每个在网上交流的人都能够很容易的了解对方, 几乎没有必要为了安全而设计软件, 编写代码. 而现在的因特网对于网络服务器却是险象丛生. Eric Allman, Sendmail的作者, 和目前的维护者Claus Assman 为了加强Sendmail的安全做了很多工作, 但是无论如何, 除了重新设计, 怎样的修正也不能让Sendmail达到真正的安全.

    1.3.2. 性能

    qmail 并行处理邮件传送, 缺省配置情况下, 能够达到20个并行邮件同时传送.

    1.3.3. 可靠性

    qmail保证已经接收的新邮件不被丢失, qmail使用一种新的邮箱格式, 其可靠性超过了没有文件锁的NFS存储系统.

    1.3.4. 简单Simplicity

    qmail 比其他实现同样功能的MTA都要小.


    注意: qmail 的正式主页, http://cr.yp.to/qmail.html 有更多的 qmail 特色介绍.

    1.4. 发展历史

    qmail由 Dan Bernstein (DJB)编写, 关于他可以参考这里http://en.wikipedia.org/wiki/Daniel_J._Bernstein. 他现在任职于 Illinois 大学 Chicago 分校数学教授. 它在密码术研究方面的工作, 以及他关于密码术源代码的出版问题对美国政府的诉讼也是很有名的, 关于这次诉讼的情况详见 http://en.wikipedia.org/wiki/Bernstein_v._United_Stateshttp://cr.yp.to/export.html 查看关于诉讼的信息. (可能wikipedia在中国大陆无法访问, 请参考使用代理或其他方式. 译者注)

    第一个公开发行的 qmail 版本是1996年1月24日发表的 0.70 beta 版. 第一个 gamma 发行版是在1996年8月1日的0.90版.

    第一个常规发行版本是1.0, 时间是1997年2月20日. 现在使用的1.03版本, 发行于1998年6月15日.

    预期下一个版本将是2.0评估版, 即将在2.0版里面出现的一些新功能可以在http://cr.yp.to/qmail/future.html 找到.

    1.5. 特点

    qmail 的web页 http://cr.yp.to/qmail.html 列出了非常全面的qmail的特点. 本节即针对这个页面列出的特点予以着重介绍.

    1.5.1. 安装

    1.5.2. 安全

    1.5.3. 邮件结构

    1.5.4. SMTP 服务

    1.5.5. 队列管理

    1.5.6. 邮件反弹

    1.5.7. 基于域名的邮件路由

    1.5.8. SMTP 传输

    1.5.9. 转发和邮件列表

    1.5.10. 本地(邮件)传送

    1.5.11. POP3 服务

    1.6. 相关的软件包

    qmail遵循经典UNIX哲学: 每个软件工具都要有专一的, 规范良好的功能; 而复杂的功能应该由一系列多个独立的简单工具联合完成, 形成一个"流水线"模式. 另外一种方式是在更为简单的工具上不断的建立和丰富越来越复杂的的功能来完成大量的复杂的功能.

    qmail并没有拥有所有人要求的任意功能, 这点并不令人惊讶惊讶. 相反的, qmail拥有的是一些实现那些功能的流行的插件(add-ons). 当然了, 许多标准UNIX实用工具也都可以作为插件和qmail协同工作. 下面介绍一些插件:

    1.7. 体系结构

    附录 D 介绍了qmail的功能和结构. 简单的说, qmail包含了一系列的程序(模块)来完成不同的任务.

    1.8. 版权许可信息

    qmail的版权由作者Dan Bernstein所有, qmail没有和用户权利声明一同发布. 在web页面 http://cr.yp.to/softwarelaw.html 上, 作者Dan Bernstein概要陈述了他认为用户在美国版权法下拥有的权利和义务. 在web页 http://cr.yp.to/qmail/dist.html 上描述了作者授权给qmail的源代码分发用户的权利和义务. 二进制发行遵循条款在下面这个web页面上可以找到 http://cr.yp.to/qmail/var-qmail.html, 也可以参考这里: http://en.wikipedia.org/wiki/License-free_software.

    发行权限的最底线: 你可以将qmail用于任何用途, 你可以再次分发未修改的qmail源代码和有资格的var-qmail二进制发行包, 你也可以发行qmail补丁程序. 但是你不能发行修改过的qmail源代码和non-var-qmail二进制发行包.

    1.9. 和其他MTA相比较

    这个题目完全可以写一本书啦. 不过可能是很单调乏味的一本. 这里给出一个qmail和其他最常见的UNIX MTA的快速比较表格(中: medium, 高: high, 低: low, 是: yes, 否: no, 插件: addons, 可选的: optional. 译者注)

    MTA 成熟度 安全性 特色 性能 是否兼容Sendmail 模块化
    qmail 插件
    Sendmail -
    Postfix
    exim
    Courier 可选的

    兼容Sendmail意思是MTA运转是否类似于Sendmail, 从而可以在某种用户透明度上从此MTA和Sendmail之间过渡和切换, 比如.forward控制文件, /etc/aliases文件以及是否传送邮件到目录 /var/spool/mail等等行为.

    Jonathan de Boyne Pollard 曾经回顾了很多UNIX下的MTA, web页面在http://homepages.tesco.net/~J.deBoynePollard/Reviews/UnixMTSes/ . 另外一个很详细的的比较文章请参考http://www.geocities.com/mailsoftware42/. (geocities可能在国内无法直接访问. 译者注)

    1.10. 文档

    1.10.1. man 帮助手册

    qmail发行包包含了完整的man手册. 安装qmail之后, 他们通常位于 /var/qmail/man. 你可能需要自己手动增加这个手册目录路径到你的环境变量MANPATH里面.

    Shell 解释器 命令行
    Bourne (/bin/sh) MANPATH=$MANPATH:/var/qmail/man; export MANPATH
    bash, Korn export MANPATH=$MANPATH:/var/qmail/man
    C Shell setenv MANPATH $MANPATH:/var/qmail/man

    (上面表格为各个不同shell下运行的增加环境变量的命令行格式, 故不予翻译, 用户也可以参考man man来查阅直接指定man的指定目录开关的设定, 在Bourne下, 这个开关一般是 -M.译者注) (修改环境变量之后) 用型如"man name-of-qmail-man-page"的命令格式即可调出相关的手册页面.

    也可以访问man手册页面的在线web页面形式, 地址是:


    注意: qmail的man手册页面承载了大量的信息, 它的写作语言偏重技术术语, 可能相当晦涩难懂, 必须仔细加以研读. 你可能需要通读一遍来熟悉它. 因为很少有重复性的内容, 你必须首先知道里面都写了哪些内容,以及你感兴趣的那些内容在哪里, 否则你可能根本找不到你要的东西.

    1.10.2. 文档

    qmail发行版包含了一系列文档, 通常安装在/var/qmail/doc目录下. 它们包括以下内容: (本文中默认的两个位置,一个就是文档的根位置/var/qmail/doc, 这个位置的文档也通常被作者描述为qmail源代码文件目录下的doc文档, 内容是一致的. 还有一个就是qmail 的安装后的主目录下的控制文档, 通常为/var/qmail/control下面, 在很多情况下, 作者并不明确指出这两个具体位置. 译者注)

    这些文档也可以在线查看, 请到web页面:

    1.10.3. 常见问题 FAQs

    有两个正式的常见问题(Frequently Asked Questions, FAQ. 附相关回答)文档:

    web页面的FAQ更完整一些.

    1.10.4. 书籍

    1.10.4.1. qmail 手册 (英文书名: The qmail Handbook)

    作者Dave Sill, 也是本文Life with qmail的作者, 曾经为Apress(http://www.apress.com/)出版社撰写了一本qmail书籍. 这本qmail 手册 (英文书名: The qmail Handbook), 包括了本文所有内容, 某些方面更为详细, 同时也介绍了大量的新领域.

    更多信息, 请参看 http://www.apress.com/catalog/book/1893115402/. 需要在我的书店定购本书, 请到我和Amazon.com合作书店 http://www.amazon.com/exec/obidos/ASIN/1893115402/davesill.

    1.10.4.2. qmail (英文书名: qmail)

    据报道, John Levine为O'Reilly & Associates (http://www.oreilly.com/)出版社写作的一本qmail书籍.

    1.10.4.3. Running qmail (英文书名: Running qmail)

    作者Richard Blum, Sams出版. 这本书被认为接受了qmail邮件列表里面的各种观点.

    定购本书, 请参看 http://www.amazon.com/exec/obidos/ASIN/0672319454/davesill.

    1.10.4.4. qmail: Yuksek Performansli E-Posta Sunucu

    Ismail Yenigul, 以及其他人著作的qmail 书籍. 参见 http://www.acikakademi.com/catalog/qmail/.

    1.10.5. 邮件列表文档

    qmail的邮件列表, 由Dan Bernstein 维护, 极为有价值的信息来源. web文档保存在以下位置:

    这个文档的一个搜索引擎位置在:

    其他web文档可以在以下地址访问到:

    大多数关于qmail的问题的答案都可以首先在这个邮件列表的文档里面搜索到.

    1.10.6. 其他Web站点

    1.11. 技术支持

    1.11.1. 邮件列表

    下面的这些列表位于主机 list.cr.yp.to. 为了防止被发送垃圾邮件者获取地址, 我没有使用完整有效的邮件地址, 以及"mailto"格式的URL.(这里隐去了真实的listname, 具体请参看qmail的正式主页介绍或者查看1.11.1.节, 也就是本节的几个小节的带有下划线的英文标题名字, 译者注)

    这些邮件列表由ezmlm管理, 使用不同的地址实现不同的功能.

    举例, 一个订阅或者退订地址, 比如 joe@example.com, 发送邮件到这个地址订阅列表:

    1.11.1.1. qmail

    这是一个主要的qmail邮件列表.讨论和提问/回答很多有关于qmail的问题. 不过不包括有关于他们自己的列表的问题. 在这个列表提问之前请阅读Charles Cazabon的"12 Steps to qmail List Bliss" web页面位置http://pyropus.ca/personal/writings/12-steps-to-qmail-list-bliss.html .同时请首先阅读FAQ或者在这里搜索列表的过去的文章. 提问的时候, 请尽量包含充分详尽的细节, 便于其他人回答. 请注意以下这些提问要点:


    注意: qmail的邮件列表使用了一个叫做qsecretary的工具来校验投递到列表的邮件是否是垃圾邮件. 每封到达列表的邮件都会首先由qsecretary返回一个确认邮件. 用户阅读确认邮件并且按照返回邮件上的指令确认你的邮件--通常就是回复qsecretary的确认信息就可以了. 经常在列表投递的订户一般使用类似Charles Cazabon编写的pymsgauth (在这里http://pyropus.ca/software/pymsgauth/.) 的自动回复程序来自动完成邮件确认. pymsgauth 校验发往列表的邮件的确是你发出的, 所以它不会确认那些冒充你的名字发送到列表的邮件.


    1.11.1.2. qmailannounce

    qmail的公告邮件列表. 没有投稿地址, 这是个只读的列表.

    1.11.1.3. serialmail

    讨论serialmail 软件的列表.

    1.11.1.4. ezmlm

    ezmlm 邮件列表管理器的的讨论列表.

    1.11.2. 咨询者

    参看 http://www.qmail.org/top.html#paidsup 的商业支持提供者名单.

    1.11.3. FAQTS 知识库

    http://qmail.faqts.com/ 一个qmail相关问题的数据库, 包括问题解答.如果你在FAQ里面找不到回答, 试试搜索这个知识库. 它的专长在于回答"如何去作"的问题.


    2. 安装

    这一节介绍qmail的安装. 如果你是个经验丰富的系统管理员, 你完全可以按照qmail的发布源文件里面的INSTALL文件的指导完成安装. INSTALL文件是正式的安装指导. 这个指导比 Life with qmail, 也就是本文的指导复杂很多. INSTALL文件假定读者是一个经验丰富的系统管理员或者邮件管理员. 而且INSTALL这个文件也比较陈旧, 反映不了Bernstein(qmail作者)最近的操作规程建议.


    注意: 如果你选择使用下面的安装指导, 请你一定要通读下面整个小节以熟悉全部安装过程.

    2.1. 不同的安装发布形式以及相互的比较

    2.1.1. 二进制安装对比源代码安装

    由于qmail对于预先编译的二进制代码包的发行有限制性的许可, 通常qmail都是由源代码安装的.

    如果你不是很熟悉源代码和二进制的区别, 想像一下你订了一个pizza饼. "二进制"形式的pizza饼送来了立刻就能吃, 而"源代码"pizza饼就像全部制作pizza的材料, 面粉, 发酵粉, 干酪, 沙司还有浇头调料, 以及烹饪pizza的指导, 你必须自己作pizza. 虽然有点费劲, 不过如果你仔细的按照指导来作, 结果是一样的, 甚至更好. 自己作的pizza更新鲜, 你也可以按照自己的配置调整浇头调料, 并且你更多的了解了你的pizza以及它是如何"工作"的.

    安全的运行一个因特网服务并不容易. 一个不适当配置的服务可能给你的主机系统带来被攻击以及被用来攻击其他站点的风险--有可能让管理员承担法律责任的安全风险. 更多的知道你的网络服务如何运行的, 就更有可能让他们正确和安全的工作.

    2.1.2. Tarball 对比 特定操作系统安装包 (Tarball vs. OS-specific package)

    一些操作系统提供一种自动源代码安装机制. 回到上文我们的pizza制作分析里面. 这就好像把所有的pizza的成分和制作指导都打包到一起, 这样你简单的按一下按钮pizza就能把自己烤好啦.

    觉得这样作很不错, 是吧?

    实际上, 那可不是一个想当然的好主意. 组装这些包是个相当困难的工作, 它们有时并不是按照假定的方式工作的. 这是软件, 而且和其他软件一样, 他们会有bugs. 即使不提那些bugs, 那些安装的方便也是用牺牲你自己烤的pizza饼的很多优点来达到的. 比如你自己调整浇头调料的的能力, 还有知道怎么作pizza饼, 以及pizza如何工作等等.

    如果qmail仅仅是一个pizza, 哪自安装方式还是可以接受的. 不过qmail可是个相当复杂的系统. 安装和维护qmail的人都需要对它相当的了解才能平稳的运行它. 自安装方式的qmail更容易安装, 不过用户手动安装方式更容易调整配置和查找故障. 你可能就安装一次qmail, 但是你可能要几次才能调整好它, 或者当邮件并不是按照你想要的方式运行的时候, 设法找出并解决问题.

    由于这些原因, 我建议使用源代码的tarball方式安装, 而不是Red Hat RPM或者其他自安装包方式.

    2.2. 准备工作

    安装qmail之前, 尤其如果是你第一次安装qmail, 有几个需要注意的地方.

    2.3. 系统要求

    qmail 必须安装在UNIX或者类UNIX系统上, 一些系统要求:


    注意: 邮件队列所在的文件系统必须允许使用可执行文件和设置setuid()文件. 一些操作系统自动挂载(mount) /var 目录选项为非suid 和非可执行.这种情况下, 必须在 /var/qmail/bin 内禁止这些选项, 或者, 将这个文件夹放置在其他没有这两项限制的文件系统上. 稍后我将在建立目录小节提到如何使用符号链接来解决这个问题. 如果/var 挂载为非suid, 你可能在qmail-send 日志内看到如下的错误消息:

    delivery : deferral: Sorry,_message_has_wrong_owner._(#4.3.5)


    注意: 本文或者INSTALL 文件的说明, 是不能作为qmail 在苹果X 操作系统上的安装指导的, Eben Pratt 存档了如何在苹果X 系统上安装qmail 的文档, 参考这里 http://netdevice.com/qmail/#osx.

    2.4. 下载源代码

    好了, 你已经准备好安装qmail的系统了. 第一步就是下载qmail和插件的源代码. 当然了, 你需要qmail, 还有ucspi-tcp和daemontools.

    用你的web浏览器, 或者web客户端(比如wget), FTP客户端下载这些源代码.


    注意: 如果这些链接的其中任何一个失效, 都有可能由于他们已经升级了, 如果是这种情况, 你需要到http://cr.yp.to/software.html 查找相应软件包的链接下载最新版本. 有可能升级版本不兼容下面的指导内容, 所以请一定阅读这些发行版本的"Upgrading from previous version..."小节中的注意事项.

    注意: 本文安装指导使用netqmail 发行版, netqmail 包含了qmail 1.03 tarball版和一个补丁, 这个补丁修正了一些漏洞, 不足和兼容性问题. 在这里访问netqmail http://www.qmail.org/netqmail/ netqmail 的CHANGES 文件内有更多的相关信息.


    2.5. 编译源代码

    2.5.1. 检验编译(源代码)环境

    首先你要确定的是你有编译程序的必要的工具. 如何确定取决于你使用的UNIX变种. 虽然不能保证可靠, 但最简单的断定方式就是去试.


    注意: 下面任何一个测试通过了, 你都可以停下来直接跳到下一节.

        $ cc
        cc: No input files specified
        $
    

    这节我们将要实现编译qmail的步骤. 剪切/粘贴(意思是复制或者粘贴脚本和命令行. 译者注) 会很方便, 不过也不是必须的.

    2.5.2. 解压发行包

    如果你一直按照这个指导来作, 那么现在你已经有了一个C编译器, 以及源代码的tarball副本. 下一步, 拷贝或者移动tarball包到工作目录. 目录/usr/local/src 对于qmail 和ucspi-tcp安装是个不错的位置. 而daemontools 应该建立在/package下.

    现在你需要成为root用户, 如果你还没有, 那就成为root吧.

        su      
    umask 022
    mkdir -p /usr/local/src
    mv netqmail-1.05.tar.gz ucspi-tcp-0.88.tar.gz /usr/local/src
    mkdir -p /package
    mv daemontools-0.76.tar.gz /package
    chmod 1755 /package

    现在你可以解开软件包了.

        cd /usr/local/src
    gunzip netqmail-1.05.tar.gz
    tar xpf netqmail-1.05.tar
    cd netqmail-1.05
    ./collate.sh # 在这儿要注意错误信息
    cd ..
    gunzip ucspi-tcp-0.88.tar.gz
    tar xpf ucspi-tcp-0.88.tar
    rm *.tar # 此步骤可选, 除非硬盘空间很紧张
    cd /package
    gunzip daemontools-0.76.tar.gz
    tar xpf daemontools-0.76.tar
    rm *.tar # 此步骤可选, 除非硬盘空间很紧张

    那么, 现在应该有下面几个目录 /usr/local/src/netqmail-1.05, /usr/local/src/ucspi-tcp-0.88, and /package/admin/daemontools-0.76.

    2.5.3. 建立目录

    qmail安装程序会自行创建需要的子目录, 你只需要创建qmail的"home"目录.

        mkdir /var/qmail
    

    然后直达下一节.


    注意: 如果你想把qmail的全部或者部分文件安装到除了/var的其他地方, 可以在/var/qmail下建立软链接到其他位置.

    举个例子, qmail配置文件可以存放在/etc/qmail下面, 如下操作:

        mkdir /etc/qmail
        ln -s /etc/qmail /var/qmail/control
    


    2.5.4. 创建用户和组

    最容易的创建用户和组的方式是创建一个小脚本文件然后执行它. 在源代码目录下你可以找到一个名字是INSTALL.ids的文件, 它包括了在你的系统平台下创建用户和组的命令行. 复制这个文件并命名另外一个名字, 编辑它来运行命令既快捷又简单.

        cd /usr/local/src/netqmail-1.05/netqmail-1.05
    cp INSTALL.ids IDS

    接下来, 用你最顺手的编辑器, 删除文件其余部分, 除了保留你的平台需要的命令部分. 举个例子, 下面是为FreeBSD平台编辑之后留下的部分:

        pw groupadd nofiles
    pw useradd qmaild -g nofiles -d /var/qmail -s /nonexistent
    pw useradd alias -g nofiles -d /var/qmail/alias -s /nonexistent
    pw useradd qmaill -g nofiles -d /var/qmail -s /nonexistent
    pw useradd qmailp -g nofiles -d /var/qmail -s /nonexistent
    pw groupadd qmail
    pw useradd qmailq -g qmail -d /var/qmail -s /nonexistent
    pw useradd qmailr -g qmail -d /var/qmail -s /nonexistent
    pw useradd qmails -g qmail -d /var/qmail -s /nonexistent

    然后运行这个脚本, 用chmod将脚本设置为可执行或者用sh来运行它.

    第一种方法:

        chmod 700 IDS
        ./IDS
    

    第二种方法:

        /bin/sh IDS
    

    这个脚本运行完毕, 你的所有的用户和组就已经添加完毕, 你可以继续下一节的安装了.

    可是如果你的系统在INSTALL.ids 上没有提到怎么办? 那你就必须手动创建用户和组了. 使用你比较顺手的编辑器编辑这个文件/etc/group, 增加下面两行:

        qmail:*:2107:
        nofiles:*:2108:
    


    注意: 首先确定2107和2108没有被使用, 如果已经被占用, 选择2个文件中未用的数字.

    下一步, 使用vipw(大多数系统都有这个命令, 如果没有你就必须用编辑器手动编辑, 不过这次可是/etc/passwd文件)在文件尾部增加下面这些行:

        alias:*:7790:2108::/var/qmail/alias:/bin/true
        qmaild:*:7791:2108::/var/qmail:/bin/true
        qmaill:*:7792:2108::/var/qmail:/bin/true
        qmailp:*:7793:2108::/var/qmail:/bin/true
        qmailq:*:7794:2107::/var/qmail:/bin/true
        qmailr:*:7795:2107::/var/qmail:/bin/true
        qmails:*:7796:2107::/var/qmail:/bin/true
    


    注意: 首先确定7790-7796这些未被占用以及和刚才上面编辑的2107, 2108是同一个组id. 如果任意一个用户ID(UID)被占用, 必须选用其他未被占用的用户id.
    你不必一定把这些行加到文件尾部, 这样作只是最容易说明问题的方式.

    你现在已经可以进入下一节了.

    2.5.5. 编译

    现在你可以开始编译qmail了. 进入/usr/local/src/netqmail-1.05/netqmail-1.05 目录, 我们开始吧!

        cd /usr/local/src/netqmail-1.05/netqmail-1.05
    

    检验编译环境小节, 你定位了你的C编译器. 如果它的名字不是cc或者不在你访问的环境变量PATH定义的任何目录下, 你必须修改conf-cc和conf-ld. 假设你的编译器名字是gcc, 并且gcc在你的环境变量PATH内可见, 那么简单来说, 编辑conf-cc和conf-ld然后置换所有"cc"为"gcc"就可以了.

    现在敲入下面的命令:

        make setup check
    

    这个编译完成之后, 你需要作一些安装后配置工作. 运用下面两个脚本用来让工作更简单.

    如果你的DNS配置恰当, 运行这个脚本:

        ./config
    

    如果由于某些原因config 脚本不能在DNS找到你的主机名, 你就必须运行config-fast脚本: (这个原因一般来说是由于config在dns反查主机IP对应的规范的主机名时候没有记录或者出错造成的. 现代商业dns一般都不提供IP反查. 所以安装过程可能更多机会是直接使用config-fast 脚本, 而不是config 脚本. 译者注)

        ./config-fast the.full.hostname
    

    举个例子, 如果你的域名是example.com, 你的计算机的主机名是dlphin, 你的config-fast 命令行应该这样写:

        ./config-fast dolphin.example.com
    


    注意: 你可能计划在小型本地局域网使用伪域名比如".local", 举例来说, 如果你的主机名是"mash", 你可能要用 ./config-fast mash.local , 如果你这样作了, 要确定配置qmail在返回地址上使用了合乎逻辑的因特网域名. (参见第3节, 配置.)

    qmail现在已经安装到你的系统内, 并且准备运行了! 下一节将要介绍运行和测试qmail.

    2.6. 安装 ucspi-tcp

    刚才你解压了qmail, ucspi-tcp, 和daemontools 的tarball包, 现在进入ucspi-tcp目录.

        cd /usr/local/src/ucspi-tcp-0.88
    

    刚才在编译一节, 如果你修改了conf-cc和conf-ld文件, 你必须在这个目录作同样的修改.

    然后, 运行:

        patch < /usr/local/src/netqmail-1.05/other-patches/ucspi-tcp-0.88.errno.patch
    make
    make setup check

    ucspi-tcp安装完毕.

    2.7. 安装 daemontools

    进入daemontools安装目录

        cd /package/admin/daemontools-0.76
    

    再说一次, 如果你在编译qmail和ucspi-tcp的时候修改了conf-cc和conf-ld文件, 你必须在在src目录作同样的修改.

    然后, 运行:

        cd src
    patch < /usr/local/src/netqmail-1.05/other-patches/daemontools-0.76.errno.patch
    cd ..
    package/install

    在BSD系统上(没有 /etc/inittab), 你必须重新启动计算机再运行svscan, 这是后台服务器的管理服务程序.

    使用 "ps -ef | grep svscan" 或者"ps waux | grep svscan" 检查svscan是否在运行.


    注意: 在Solaris下, 你必须修改/etc/inittab中关于svscan的启动条目, 将

      SV:123456:respawn:/command/svscanboot
    

    改为:

      SV:123456:respawn:/command/svscanboot </dev/null >/var/log/svscan 2>&1
    

    或者改为:

      SV:123456:respawn:/command/svscanboot </dev/null >/dev/msglog 2>&1
    

    选择那种方式, 这取决于你是想把启动svscan的出错消息记录到log文件里面还是显示到控制台上. 这样作的必要性请参考下面的文章:

    http://marc.theaimsgroup.com/?l=log&m=100327801309834&w=2



    注意: 一个Slackware的用户报告x1之前的SV /etc/inittab条目必须被移动, 否则启动后无法运行svscan.

    2.8. 运行 qmail

    2.8.1. /var/qmail/rc

    /var/qmail/boot 目录包含了不同配置的qmail启动脚本示例: /var/spool/mail 方式和$HOME/Mailbox 方式, 使用procmail或者.forward 控制文件, 以及这些方式的不同组合配置. 你可以随意考查这些方式, 不过这里我们选用下面的脚本:

    #!/bin/sh
    
    # Using stdout for logging
    # Using control/defaultdelivery from qmail-local to deliver messages by default
    
    exec env - PATH="/var/qmail/bin:$PATH" \
    qmail-start "`cat /var/qmail/control/defaultdelivery`"
    

    注意: 这个脚本使用了反引号(`), 而不是单引号('). 最好拷贝和粘贴上文的脚本而不是自己键盘输入, 后者容易出错. (反引号非常小,请仔细看. 译者注)

    用你的编辑器将上面的脚本保存为 /var/qmail/rc, 然后执行下面这些命令:

        chmod 755 /var/qmail/rc
        mkdir /var/log/qmail
    

    现在你需要决定一下, 除了由.qmail 文件指示传送的邮件外, 其他邮件将采用何种默认传输方式, (.qmail 文件是指示文件传送路径的重要文件, 后面还会讨论. 译者注)下面的列表大致阐述了几种一般性的选择:

    邮箱格式 名称 保存位置 缺省的传输方式 注释
    mbox Mailbox $HOME ./Mailbox 最常见的格式, 大多数MUA都可以正确识别
    maildir Maildir $HOME ./Maildir/ 更可靠, 少数MUA支持的格式
    mbox  username /var/spool/mail 参见 INSTALL.vsm文件 传统的UNIX邮箱

    更多信息请参考 INSTALL.mbox, INSTALL.maildir 和 INSTALL.vsm 文件.

    选择缺省的邮箱格式, 只要选择上表里面的"缺省传输方式"的值, 填写到/var/qmail/control/defaultdelivery里面就可以了. 例如, 如果选择标准的qmail /Mailbox 传送格式, 这样作就行了:

        echo ./Mailbox >/var/qmail/control/defaultdelivery
    


    注意: defaultdelivery并不是标准的qmail控制文件. 而是上文/var/qmail/rc 文件的要素. 对于qmail-start来说, defaultdelivery 变量只是在没有实际的 .qmail 文件指定传送指令的情况下作为 .qmail 文件的内容出现的. 把这个指令加入到单独的控制文件内, 就不必再在指令内重复引用shell元字符, 避免了出现多行杂乱的命令参数.

    2.8.2. 系统启动文件

    2.8.2.1. qmailctl 脚本

    如果你手动执行/varqmail/rc 脚本, qmail只会部分被运行起来. 可是我们希望希望每次系统启动后, qmail都能自动被启动; 每次系统停止时候qmail自动被关闭.

    创建一个如下的 /var/qmail/bin/qmailctl 文件可以完成这个愿望:

    #!/bin/sh
    
    # description: the qmail MTA
    
    PATH=/var/qmail/bin:/bin:/usr/bin:/usr/local/bin:/usr/local/sbin
    export PATH
    
    QMAILDUID=`id -u qmaild`
    NOFILESGID=`id -g qmaild`
    
    case "$1" in
      start)
        echo "Starting qmail"
        if svok /service/qmail-send ; then
          svc -u /service/qmail-send /service/qmail-send/log
        else
          echo "qmail-send supervise not running"
        fi
        if svok /service/qmail-smtpd ; then
          svc -u /service/qmail-smtpd /service/qmail-smtpd/log
        else
          echo "qmail-smtpd supervise not running"
        fi
        if [ -d /var/lock/subsys ]; then
          touch /var/lock/subsys/qmail
        fi
        ;;
      stop)
        echo "Stopping qmail..."
        echo "  qmail-smtpd"
        svc -d /service/qmail-smtpd /service/qmail-smtpd/log
        echo "  qmail-send"
        svc -d /service/qmail-send /service/qmail-send/log
        if [ -f /var/lock/subsys/qmail ]; then
          rm /var/lock/subsys/qmail
        fi
        ;;
      stat)
        svstat /service/qmail-send
        svstat /service/qmail-send/log
        svstat /service/qmail-smtpd
        svstat /service/qmail-smtpd/log
        qmail-qstat
        ;;
      doqueue|alrm|flush)
        echo "Flushing timeout table and sending ALRM signal to qmail-send."
        /var/qmail/bin/qmail-tcpok
        svc -a /service/qmail-send
        ;;
      queue)
        qmail-qstat
        qmail-qread
        ;;
      reload|hup)
        echo "Sending HUP signal to qmail-send."
        svc -h /service/qmail-send
        ;;
      pause)
        echo "Pausing qmail-send"
        svc -p /service/qmail-send
        echo "Pausing qmail-smtpd"
        svc -p /service/qmail-smtpd
        ;;
      cont)
        echo "Continuing qmail-send"
        svc -c /service/qmail-send
        echo "Continuing qmail-smtpd"
        svc -c /service/qmail-smtpd
        ;;
      restart)
        echo "Restarting qmail:"
        echo "* Stopping qmail-smtpd."
        svc -d /service/qmail-smtpd /service/qmail-smtpd/log
        echo "* Sending qmail-send SIGTERM and restarting."
        svc -t /service/qmail-send /service/qmail-send/log
        echo "* Restarting qmail-smtpd."
        svc -u /service/qmail-smtpd /service/qmail-smtpd/log
        ;;
      cdb)
        tcprules /etc/tcp.smtp.cdb /etc/tcp.smtp.tmp < /etc/tcp.smtp
        chmod 644 /etc/tcp.smtp.cdb
        echo "Reloaded /etc/tcp.smtp."
        ;;
      help)
        cat <<HELP
       stop -- stops mail service (smtp connections refused, nothing goes out)
      start -- starts mail service (smtp connection accepted, mail can go out)
      pause -- temporarily stops mail service (connections accepted, nothing leaves)
       cont -- continues paused mail service
       stat -- displays status of mail service
        cdb -- rebuild the tcpserver cdb file for smtp
    restart -- stops and restarts smtp, sends qmail-send a TERM & restarts it
    doqueue -- schedules queued messages for immediate delivery
     reload -- sends qmail-send HUP, rereading locals and virtualdomains
      queue -- shows status of queue
       alrm -- same as doqueue
      flush -- same as doqueue
        hup -- same as reload
    HELP
        ;;
      *)
        echo "Usage: $0 {start|stop|restart|doqueue|flush|reload|stat|pause|cont|cdb|queue|help}"
        exit 1
        ;;
    esac
    
    exit 0
    
    这个脚本可以在线下载, 地址是http://www.lifewithqmail.org/qmailctl-script-dt70.  

    (建议所有直接使用, 或者拷贝-粘贴web页面指令和文件格式脚本指令的读者, 都要注意脚本编码转换的问题. 本文讲到的qmail 是在Unix/Linux 类型服务器上运行的, 而UNIX 的回行和DOS/Windows的回车在脚本内表示的ACSII码是完全不同的, 如果遇到这个问题, 在之后的脚本执行中, 可能出现非常奇怪的错误信息. 有兴趣的读者可以在搜索引擎上查找深入介绍内容. 细心的读者还会注意到, 英文原文和翻译版本, 在代码前后都加上了<PRE></PRE>格式符, 其目的就是为了保证指令代码不会被web页面的格式代码"污染". 译者注)

    你可以自己输入这个脚本, 不过我推荐你用浏览器下载上面链接的文件.

    将上面这个qmailctl 脚本设置为可执行脚本, 然后链接到你的用户执行程序目录:

        chmod 755 /var/qmail/bin/qmailctl
        ln -s /var/qmail/bin/qmailctl /usr/bin
    

    2.8.2.2. supervise 脚本

    为 qmail 的服务创建 supervise 目录

        mkdir -p /var/qmail/supervise/qmail-send/log
        mkdir -p /var/qmail/supervise/qmail-smtpd/log
    

    建立 /var/qmail/supervise/qmail-send/run 文件

    #!/bin/sh
    exec /var/qmail/rc
    

    建立 /var/qmail/supervise/qmail-send/log/run 文件:

    #!/bin/sh
    exec /usr/local/bin/setuidgid qmaill /usr/local/bin/multilog t /var/log/qmail
    

    建立 /var/qmail/supervise/qmail-smtpd/run 文件:

    #!/bin/sh
    
    QMAILDUID=`id -u qmaild`
    NOFILESGID=`id -g qmaild`
    MAXSMTPD=`cat /var/qmail/control/concurrencyincoming`
    LOCAL=`head -1 /var/qmail/control/me`
    
    if [ -z "$QMAILDUID" -o -z "$NOFILESGID" -o -z "$MAXSMTPD" -o -z "$LOCAL" ]; then
        echo QMAILDUID, NOFILESGID, MAXSMTPD, or LOCAL is unset in
        echo /var/qmail/supervise/qmail-smtpd/run
        exit 1
    fi
    
    if [ ! -f /var/qmail/control/rcpthosts ]; then
        echo "No /var/qmail/control/rcpthosts!"
        echo "Refusing to start SMTP listener because it'll create an open relay"
        exit 1
    fi
    
    exec /usr/local/bin/softlimit -m 2000000 \
        /usr/local/bin/tcpserver -v -R -l "$LOCAL" -x /etc/tcp.smtp.cdb -c "$MAXSMTPD" \
            -u "$QMAILDUID" -g "$NOFILESGID" 0 smtp /var/qmail/bin/qmail-smtpd 2>&1
    
    


    注意: concurrencyincoming并不是标准的qmail控制文件. 它是上面脚本的一个要素. 并且, 第一个LOCAL 行上面的是"破折号 + 数字1", 下面的tcpserver行上的参数是"破折号 + 小写字母l" . (由于英文小写字母l和数字1容易混淆, 原作者特意补充的注意事项. 由译者将被提到两行修改成为红色. 这也是为什么作者希望读者直接拷贝脚本而不是自行输入避免脚本出错的主要原因之一. 另外注意这个脚本中很多字体很小的引号和反引号. 译者注)


    注意: Solaris系统下一般位置的id程序不能正常工作, 请使用这个位置的 /usr/xpg4/bin/id:

        QMAILDUID=`/usr/xpg4/bin/id -u qmaild`
        NOFILESGID=`/usr/xpg4/bin/id -g qmaild`
    



    注意: 根据你的操作系统和硬件平台的不同, 可能需要调整softlimit命令的的内存限制参数. 如果你的系统出现连接25端口失败和无法接收远程系统发送的邮件, 或者看到了类似下面这样的错误消息:
      /usr/local/bin/tcpserver: error while loading shared libraries:
      libc.so.6: failed to map segment from shared object: Cannot
      allocate memory
    
    试一下把这个参数调整到3000000到4000000.

    建立concurrencyincoming 控制文件.

        echo 20 > /var/qmail/control/concurrencyincoming
        chmod 644 /var/qmail/control/concurrencyincoming
    

    建立 /var/qmail/supervise/qmail-smtpd/log/run 文件

    #!/bin/sh
    exec /usr/local/bin/setuidgid qmaill /usr/local/bin/multilog t /var/log/qmail/smtpd
    

    将各个run文件设置为可执行文件:

        chmod 755 /var/qmail/supervise/qmail-send/run
        chmod 755 /var/qmail/supervise/qmail-send/log/run
        chmod 755 /var/qmail/supervise/qmail-smtpd/run
        chmod 755 /var/qmail/supervise/qmail-smtpd/log/run
    

    然后建立log文件目录:

        mkdir -p /var/log/qmail/smtpd
        chown qmaill /var/log/qmail /var/log/qmail/smtpd
    

    最后, 建立 supervise 目录到 /service 目录的链接:

        ln -s /var/qmail/supervise/qmail-send /var/qmail/supervise/qmail-smtpd /service
    

    /service 目录是 daemontools 安装时建立的目录.


    注意: 建立这个链接之后 qmail 系统会很快自动被启动起来, 如果你还不想立刻运行qmail, 运行下面这个,命令来停止qmail:

        qmailctl stop
    


    2.8.2.3. SMTP 访问控制

    允许本地主机通过SMTP方式发送邮件:

        echo '127.:allow,RELAYCLIENT=""' >>/etc/tcp.smtp
        qmailctl cdb
    

    2.8.3. 停止并且禁用(其他)已经安装的MTA

    虽然有可能同时运行qmail 和现存的MTA, 比如Sendmail, 不过我建议你除非你知道自己到底在干什么, 否则可不要这么干. 说实话, 如果你正在读我这段话, 你可能也不知道自己在干嘛. :-)

    如果现存的MTA是Sendmail, 你应该能利用运行Sendmail的init.d脚本的"stop"参数来停止它的运行. 例如下面命令中的一个可能是有效的:

        /etc/init.d/sendmail stop
        /sbin/init.d/sendmail stop
        /etc/rc.d/init.d/sendmail stop
    

    如果你找不到任何一个init.d/sendmail 下的脚本, 你可以用 "ps -ef|grep sendmail" 或者 "ps waux|grep sendmail" 命令找出 sendmail 的PID, 然后用下面的命令来停止Sendmail: (kill 命令加上Sendmail的PID作参数, 译者注)

        kill PID-of-sendmail
    

    如果你的MTA不是Sendmail, 检查相关文档找出正确的停止MTA的方法.

    你应该考虑一下把旧的MTA彻底的从你的系统里面删除. 至少禁用它的 init.d 脚本, 防止下一次系统重启动的时候旧的MTA也被试图重启.

    对于使用rpm方式安装Sendmail的 Red Hat Linux, 执行下面的命令来删除Sendmail:

        rpm -e --nodeps sendmail
    


    注意: 如果你使用基于RPM方式的Linux, 比如 Red Hat, 删除MTA可能带来进一步的问题. 系统的某些应用程序将会试图重新安装Sendmail, 一些MUA程序将无法安装, 因为他们找不到安装好的MTA. Mate Wierdl 提供了一个占位程序, 称作 "fake_mta", 安装这个程序之后可以防止出现以上的问题. 简单的RPM安装包可以在下面的地址取得 http://www.csi.hu/mw/fake_mta-1-1memphis.noarch.rpm.


    检查一下没有其他程序在监听SMTP服务端口(25). 旧的MTA, inetd, 或者 xinetd 等程序都有可能造成问题. (按照以上步骤执行后, 再) 运行下面的命令应该是没有输出结果的(除非这个时候 qmail-smtpd 服务也在运行).

        netstat -a | grep smtp
    

    如果有什么程序在运行, 首先确定不是qmail, 那么先运行下面的命令:

        qmailctl stop
    

    然后重复 netstat 检查:

        netstat -a | grep smtp
    

    如果你还是能看到这个命令有一些输出, 你就必须在qmail 的SMTP服务运行起来之前把肇事程序找出来.

    最后, 将现存的 /usr/lib/sendmail 替代为 qmail 版本.

        mv /usr/lib/sendmail /usr/lib/sendmail.old                  # 忽略错误提示  ignore errors
        mv /usr/sbin/sendmail /usr/sbin/sendmail.old                # 忽略错误提示  ignore errors
        chmod 0 /usr/lib/sendmail.old /usr/sbin/sendmail.old        # 忽略错误提示 ignore errors
        ln -s /var/qmail/bin/sendmail /usr/lib
        ln -s /var/qmail/bin/sendmail /usr/sbin
    


    注意: 创建 sendmail 的链接是很重要的, 即使不管以前的MTA, sendmail 命令也是一个会被很多程序调用来发送邮件的重要命令.

    最后步骤是建立两个系统别名.

    2.8.4. 建立系统别名

    在所有 qmail 安装上面都要建立四个系统别名:

    别名 目的
    postmaster RFC 2821 标准要求, 指向邮件系统管理员(也就是你)
    mailer-daemon 反弹邮件事实上的标准接收者
    root 转发特权用户, 根(root)用户的邮件给系统管理者
    abuse 事实上的邮件滥用(垃圾邮件)举报地址

    建立这些系统别名, 取决于你想让这些邮件发送到哪里(一个本地用户或者一个远程地址)并且适当的创建一个.qmail 文件集合. 举个例子, 加入你想让本地用户 dave 接收发给系统管理员和邮件管理员的邮件, 就这么作:

        echo dave > /var/qmail/alias/.qmail-root
        echo dave > /var/qmail/alias/.qmail-postmaster
        ln -s .qmail-postmaster /var/qmail/alias/.qmail-mailer-daemon
        ln -s .qmail-postmaster /var/qmail/alias/.qmail-abuse  
        chmod 644 /var/qmail/alias/.qmail-root /var/qmail/alias/.qmail-postmaster
    

    在 INSTALL.alias 文件里面有更详细的细节.

    2.8.5. 运行 qmail

    如果依照上文, 你创建 /service 之后就停止了qmail, 你现在应该重新启动 qmail:

        qmailctl start
    

    2.9. 测试安装

    qmail 现在应该是正在运行的状态. 首先运行 qmailctl stat 来检验那些服务启动并运行中:(下面命令后部分为演示结果, 并不是必然如此的系统输出. 译者注)

        # qmailctl stat
        /service/qmail-send: up (pid 30303) 187 seconds
        /service/qmail-send/log: up (pid 30304) 187 seconds
        /service/qmail-smtpd: up (pid 30305) 187 seconds
        /service/qmail-smtpd/log: up (pid 30308) 187 seconds
        messages in queue: 0
        messages in queue but not yet preprocessed: 0
    

    所有的四个服务都应该是"up"(启动了)1秒钟以上. 如果不是这样, 你可能就是在写脚本的时候写错了一些东西或者你漏过了创建一个甚至多个必要的文件, 目录或者链接. 返回上面的安装指导, 一步一步的再检查一下你的工作. 你也可以下载并运行 inst_check 脚本, 在这里下载 http://lifewithqmail.org/inst_check. 举个例子:

        # sh inst_check
        ! /var/log/qmail has wrong owner, should be qmaill
        ...try: chown qmaill /var/log/qmail
        #
    

    如果 inst_check 发现了问题, 解决问题后重新运行这个检查脚本. 当所有情况被判断为正确的时候, inst_check 将会报告:

        Congratulations, your LWQ installation looks good!
    

    readproctitle 程序维持着由svscan 管理的各个服务的错误消息的日志. 使用 ps 或者其他进程列表命令. 举个例子, 你可以看到类似下面这样的输出:

        # ps -efl | grep "service errors" | grep -v grep
        000 S root      1006  1001  0  76   0    -   334 pipe_w Mar31 ?        00:00:00
        readproctitle service errors: ...unable to start qmail-smtpd/run: exec format error
        #
    

    这个例子里面, 问题出在 /service/qmail-smtpd/run 这个脚本的第一行--很有可能由于脚本文件是 DOS 格式 (DOS使用回车符-换行符结束一行的方式和Unix的仅仅用换行符方式不同).

    有时候为了检验配置错误, 手动运行一下服务也会很有帮助的. 举个例子, 如果你的 qmail-smtpd/log 服务没有运行, 那么执行下面的命令:

        cd /service/qmail-smtpd/log
        svc -d .
        ./run
        如果没有错误, 输入一行字符然后按回车键
        如果还是没有错误, 输入CTRL-D (文件结束符)
    

    这个时候, 你应该能够识别问题所在并且解决它了. 这个做完之后, 返回服务目录, 如果有必要, 运行命令:

        svc -u .
    

    一旦那些服务的启动时间都大于1秒钟后, 依照 TEST.deliver 和 TEST.receive 文件里面的指令去校验服务是否正确的工作. 注意, 应用这些指令, 日志将由multilog 程序记录到 /var/log/qmail 下, 而不是 splogger 记录到类似 /var/log/maillog 的文件里面.


    注意: 如果你选择了 maildir 邮箱格式作为默认的传送方式, 在运行这些指令之前, 你必须在你的主目录和别名的主目录创建 Maildir 目录. 参见 maildir 小节查找如何恰当的创建这个目录.


    3. 配置

    你已经从源代码tarball方式, 或者自编译包方式, 或者var-qmail包方式安装了 qmail. 这一节的内容就是按照你的需要配置qmail.

    3.1. 配置文件

    所有的qmail系统配置文件, 除了在~alias下的 .qmail 文件, 都位于 /var/qmail/control 目录下. qmail-control 的man手册页包括了一个像下面这样的表:

    控制文件 默认值 被用于 使用目的
    badmailfrom none qmail-smtpd From 地址黑名单
    bouncefrom MAILER-DAEMON qmail-send 反弹邮件的发送者
    bouncehost me qmail-send 反弹邮件的发送者主机名
    concurrencyincoming none /service/qmail-smtpd/run 最大并行 SMTP 连接数
    concurrencylocal 10 qmail-send 最大并行本地传送数
    concurrencyremote 20 qmail-send 最大并行远程传送数
    defaultdelivery none /var/qmail/rc 默认的 .qmail 文件
    defaultdomain me qmail-inject 默认的域名
    defaulthost me qmail-inject 默认的主机名
    databytes 0 qmail-smtpd 邮件最大字节数 (0 等于无限)
    doublebouncehost me qmail-send 双重反弹的发送者的主机名
    doublebounceto postmaster qmail-send 接收双重反弹邮件的用户
    envnoathost me qmail-send 对缺少"@"符号的地址配置的缺省域名
    helohost me qmail-remote 在SMTP HELLO命令里面使用的主机名
    idhost me qmail-inject 在Message-ID 里面使用的主机名
    localiphost me qmail-smtpd 替代本地 IP 地址的名字
    locals me qmail-send 进行本地传送的域
    me 系统的正式域名 FQDN various 许多控制文件的默认要求
    morercpthosts none qmail-smtpd 二级rcphosts(接收主机)数据库
    percenthack none qmail-send 可以使用"%"模式转信的域
    plusdomain me qmail-inject "+"加号拖尾地址替代的域
    qmqpservers none qmail-qmqpc QMQP 服务器IP地址
    queuelifetime 604800 qmail-send 邮件在队列内可保留秒数
    rcpthosts none qmail-smtpd 我们的主机接收邮件的域
    smtpgreeting me qmail-smtpd SMTP 问候信息
    smtproutes none qmail-remote 人为指定的SMTP路由
    timeoutconnect 60 qmail-remote SMTP连接超时秒数
    timeoutremote 1200 qmail-remote 远程服务器连接超时秒数
    timeoutsmtpd 1200 qmail-smtpd SMTP客户端超时秒数
    virtualdomains none qmail-send 虚拟域和用户

    查找这些特殊控制文件的更多信息, 请参考上面表格 "被用于" 列下的各个模块的 man 手册页.

    3.2. 中继转信

    3.2.1. 介绍

    什么是转信? 转信是 MTA 通过SMTP接收到一封既不是发给本地地址也不是本地发送者发来的邮件之后, MTA转发这个邮件的动作就是转信.

    在垃圾邮件时代之前, MTA被配置为开放转信是很常见的: 各种各样的服务器接受来自任何人的邮件, 转发给任何人.

    现代的绝大多数 MTA 都被配置为或者完全禁止转信, 或者只允许某些被信任的用户或者系统使用中继转信功能.

    Chris Johnson 为qmail 的用户写了一个非常好的文档. 我鼓励你去看一看: http://www.palomine.net/qmail/relaying.html.

    3.2.2. 禁止转信

    如果你是按照 qmail 的正式安装指导安装的话, 那么转信在默认情况下已经被关闭了. 这个功能是通过把local和virtualdomains(指本地主机)文件里面列出的有充分资格的域名写入 /var/qmail/control/rcpthosts 文件来完成的. rcpthosts 这个文件名是来源于SMTP对话中的的RCPT(接收者)命令. 在SMTP对话里面, RCPT是用来确认邮件接收者地址的, 然后, rcpthosts 列出可以出现在RCPT地址里面的有效的主机名.

    3.2.3. 允许有选择的转信

    大多数单用户和小型工作组服务器可以完全禁止转信, 可是如果你维护的是一个分布式的用户社区, 你就必须有一个方式能够允许你的用户, 而且只能是你的用户通过的你的系统转信. 本文是通过使用 tcpserver 来设置RELAYCLIENT 环境变量, 使 qmail-smtpd 重载 rcpthosts 文件完成这个功能的.

    如果你是按照这个文档的指导安装的话, 有选择的转信已经在默认情况下安装好了. 如果需要给客户端转信权利, 首先在 /etc/tcp.smtp 文件里面增加类似下面的行:

        IP address of client:allow,RELAYCLIENT=""
    

    (斜体IP address of client代表客户端的IP地址. 译者注) 然后重建SMTP的访问许可数据库:

        qmailctl cdb
    

    或者运行下面的命令(重建数据库):

        tcprules /etc/tcp.smtp.cdb /etc/tcp.smtp.tmp < /etc/tcp.smtp
        chmod 644 /etc/tcp.smtp*
    

    如果你是按照正式安装指导安装的, Chris Johnson写了另外一个非常好的如何配置qmail允许选择主机转发邮件的文档, 参见: http://www.palomine.net/qmail/selectiverelay.html.

    3.2.4. 使用smart host中继转信

    如果在一个典型的家庭宽带上网条件下建立邮件服务器, 那么将有非常大的可能, 这个服务器的IP地址会被列入黑名单, 比如SORBS(http://www.dnsbl.sorbs.net/lookup.shtml)的黑名单, 这样作是为了防止垃圾邮件. 绝大多数ISP都给他们的用户提供SMTP服务器用来转信, 这些服务器通常不在黑名单内. 举个例子, Road Runner(美国某ISP. 译者注)在辛辛那提(美国地名. 译者注)使用smtp-server.cinci.rr.com 这个服务器来为她的用户提供SMTP转信服务. 你可以让qmail 将所有向外传送的SMTP 访问都通过这个服务器, 你可以这样作:

      echo ":smtp-server.cinci.rr.com" > /var/qmail/control/smtproutes  

    smtproutes 文件可以提供更多的路径选择功能, 请参考qmail-remote 的man 帮助文档.

    3.3. 多主机名

    如果你的主机名已知配置了多个名字, 例如, 所有的来自user@host1.example.com 的地址也可以被写成 user@example.com 或者 user@mail.example.com, 那么你就必须告诉 qmail 哪一个地址是它应该本地传送的地址, 哪一个地址是它应该接受的远程主机发送的地址.

    如果要这样作, 只要把所有的名字加入下面两个控制文件就行了:

    给 qmail-send 发送一个HUP(挂起)信号来通知它重新读取 locals文件. 如果你使用的是本文的 qmailctl 脚本, 那么运行下面的命令就可以了:

        qmailctl reload
    

    3.4. 虚拟域

    虚拟域和上节提到的多主机名类似, 不过这里面有一些很重要的不同之处. 首先如果 example.net 是 virtual.example.net 虚拟域的宿主主机, 那么一个发送给 joe@virtual.example.net 的邮件将会被发送给即使是同一个邮箱的 joe@example.net, 这里虚拟域的名字空间是冲突的.

    使用 qmail, 虚拟域将在 virtualdomains 文件里面配置, 文件内由型如下面这行的条目构成:

        user@domain:prepend
    

    qmail 转换 user@domain prepend-user@domain 并且将这个转换后的名字作为本地域一样对待. user@ 这个部分是可选的, 如果缺少这个部分, 这个名字将匹配所有 @domain 域下面的地址.

    回到上文的 example 剧情里面, 如果 example.net 邮件管理员希望创建 virtual.example.com 虚拟域, 并且将这个域置于用户 john 的管理之下, virtualdomains 文件下面的虚拟域条目应该这样写:

        virtual.example.com:john
    

    这样, 发往 joe@virtual.example.com 的邮件将会被修改为发往 john-joe@virtual.example.com , 然后进行本地传送. 更多信息, 请参见 .qmail 小节, 以及 扩展地址 细目. 那里将介绍 john 如何管理他的虚拟域.

    使用多主机名的时候, 所有的虚拟域都必须在rcphosts列出, 这样 qmail-smtpd 才会知道那些地址的邮件才应该被接受. 但是不像多主机名方式, 虚拟域不可以在locals里面设置相应条目.

    修改 virtualdomains文件之后, 发送给 qmail-send 一个 HUP (挂起) 信号, 通知它重新读取配置文件. 如果你使用本文的 qmailctl 脚本, 你可以运行如下命令:

        qmailctl reload
    

    同时, 不要忘了在 rcpthosts 里面增加虚拟域条目.


    注意: 必须设置域名服务器(DNS)的邮件交换器(MX)记录, 以使虚拟域指向正确的邮件服务器. 这是名字服务器管理员的工作, 超出了本文讨论的范围.

    3.5. 别名

    qmail的标准别名机制是由qmail的本地传送机制自然派生出来的.qmail-local 试图传送地址为 localpart@host 的邮件给本地叫做 localpart 名字的用户. 如果没有匹配这个名字的用户存在, 邮件将会被发送给别名 alias 用户, 别名用户是qmail系统里面通常主目录位于 /var/qmail/alias 的伪用户.

    举例, 如果你想要创建一个叫做 info@example.com 的别名, 这个别名用户将把上文收到的所有无主邮件转发给用户 tom, 在我们举例的 example.com 上, 这样作的方式是: 作为 root 用户, 运行下面的命令:

        echo \&tom > /var/qmail/alias/.qmail-info
    

    .qmail 小节, 以及 扩展地址 细目介绍了如何创建 .qmail文件, 这些文件确定了那些别名存在, 以及如何处理哪些发给他们的邮件的.

    附录 新手常见问题 介绍了两个关于别名应用的复杂案例. 那些别名使用了大写字母和小数点("."), 以及 .qmail 文件的 man 手册页面, 其中包含了完整的关于 .qmail 文件用法的文档.

    注意由于别名在 qmail 里面的实现方式, 别名是不能够优先与一个已知用户的传送的. 例如, 如果 rachel 是一个普通用户, 那么~alias/.qmail-rachel 别名是无效的.

    fastforward 软件包另外提供了一个可行的别名机制, 它将多个别名放入单独一个和Sendmail别名数据库兼容的文件里面.

    下一节, qmail-users, 描述了其他实现别名的机制.

    3.6. 关于 qmail-users

    qmail-users 是一个分发地址给用户的系统. 由 /var/qmail/users 下的一系列文件构成. assign 文件是一个分配表. 有两种分配表的格式: 单体方式和通配符方式.


    注意: assign 文件包含了一系列分配表, 每行一个, 后面接一个包含了一个单独的小数点(.)的行. 如果你手动创建assign文件, 不要忘记小数点那一行.

    3.6.1. 单体分配表

    一个单体分配表看起来是这个样子的:

    =address:user:uid:gid:directory:dash:extension:
    

    这个表的含义是: 作为 address 地址接收的邮件将会被使用用户 user 来传送, 使用指定的 uidgid, 并且由 directory/.qmaildashextension 这个文件决定邮件如何被传送.

    3.6.2. 通配符分配表

    通配符分配表看起来是这个样子的:

    +prefix:user:uid:gid:directory:dash:prepend:
    

    这个表的含义是: 作为 prefixrest 地址里面匹配的邮件地址接收的邮件, 将会被使用用户 user 来传送, 使用指定的 uidgid, 并且由 directory/.qmaildashextension 这个文件决定邮件如何被传送.

    3.6.3. qmail-user 程序

    qmail-user 有两个辅助程序: qmail-newu 和 qmail-pw2u.

    qmail-newu 程序处理 assign 文件并且在 /var/qmail/users 下生成一个名为 cdb 的静态数据库(CDB)文件. CDB是二进制格式, 所以在内含数千条分配表的情况下, 仍然可以被 qmail-lspawn 快速访问.

    qmail-pw2u 把系统用户数据库 /etc/passwd 转换为一系列适于assign 使用的分配表. qmail-pw2u 使用一组文件来修改翻译规则.


    注意: 如果你使用qmail-pw2u, 不要忘记在增加和删除用户, 或者改变UID和GID之后, 重新运行一下qmail-pw2u和qmail-newu. 标准的运行次序如下所示:

        qmail-pw2u </etc/passwd >/var/qmail/users/assign
        qmail-newu
    


    3.7. 反垃圾邮件

    Chris Hardie 写了一个极好的的qmail反垃圾邮件 HOWTO. 可以在这个地址访问到它: http://www.summersault.com/chris/techno/qmail/qmail-antispam.html.

    3.8. 病毒扫描

    Jason Haar编写了 Qmail-Scanner, 一个为qmail设计的内容扫描装置. 更多信息请参见 http://qmail-scanner.sourceforge.net/.

    Qmail-Scanner 包括了一个简单策略阻止组件(例如, 阻止*.scr文件, 或阻止"Yellow!"这样的标题), 同时也直接支持许多不同的防病毒"插件", 包括ClamAV Antivirus扫描器 http://www.clamav.net/.


    4. 使用方法

    这一节介绍了qmail 针对普通用户的使用方法. 如果你在 qmail 系统上读信和发信, 那么你阅读本节就可以找到如何用qmail 达成你的目的了.

    4.1. .qmail 文件

    传送用户邮件通常是由一个或者几个 ".qmail"(发音 dot kyoo mail) 文件控制的. 这些文件位于用户的主目录, 文件名由 .qmail 开头. .qmail 的man 手册页面描述了 .qmail 文件使用方法.

    .qmail 文件包括了一个传送指令清单, 每行一个指令. 每行的第一个字符决定了选择那种传送方式.

    字符 传送类型
    # (注释) 忽略
    | 程序 由shell 执行的命令
    / 或者 . mbox邮箱格式 (如果路径最后一个字符不是一个斜杠)

    mbox 的路径名 (包括斜杠"/"或者 点".")

    / 或者 . maildir邮箱格式 (如果路径最后一个字符是一个反斜杠) maildir 的路径名 (包括斜杠"/"或者 点".")
    & 转发 转发邮件的地址
    字母或者数字 转发 转发邮件的地址 (包括第一个字符)

    4.1.1. 程序传送

    如果.qmail 文件内指令由程序传送, qmail 将启动一个 shell (/bin/sh) 来执行这个命令, 然后使用标准把邮件的一个副本传送给这个命令. qmail-command 的man 帮助文档对这个过程有详细描述.

    程序传送是非常强大的, 被用来实现的功能范围非常广阔, 例如邮件过滤, 自动回复, 以及通过第三方传送代理比如procmail来传送邮件.

    例如:

        |preline /usr/ucb/vacation djb
    

    这个指令操作qmail 启动preline, 将 /usr/ucb/vacation 和 djb 作为参数传送给 preline, 并且使用标准输入将邮件的副本传送给这个命令.

    4.1.2. mbox 格式邮箱的邮件投递

    mbox 是标准的UNIX邮箱格式, 在一个独立文件内存放多个邮件, 每个邮件由一个"From" 的开头的行开始. 这一行看起来像一个邮件头字段, 不过那不是邮件头, 那仅仅是传送代理添加的, 作为一个标记,便于找到每个邮件的开始部分.

    例如:

        ./Mailbox
    

    这个设置表示邮件将被追加到 $HOME/Mailbox 文件上, 每个邮件由"From"开头的行引领. 一个只存放了一个邮件的, 简单的mbox 的邮箱看起来是下面这个样子的:

        From user1@example.net Thu May 13 18:34:50 1999
        Received: (qmail 1287205 invoked from network); 13 May 1999 18:34:49 -0000
        From: user1@example.net
        To: user2@example.com
        Subject: hey
    
        What's up?
    

    第一行是 qmail 传送邮件时添加的.

    4.1.3. maildir 格式邮箱的邮件投递

    maildir 是 Dan Bernstein 为了表明 mbox 邮箱格式的缺陷而创造的格式. 一个 maildir 邮箱包含三个子目录, new, cur, 和 tmp. 在各个子目录下的每个邮件根据状态的不同分别存储在各个子目录下独立的文件中. 未读邮件存储在new中, cur存储已读邮件, tmp 是为那些正在传送过程中的邮件使用的. maildir 的man手册页详细描述了maildir格式的细节.

    maildir 格式的优点之一就是保证邮件传输的安全, 即使在不锁定情况下, 不同邮件代理同时更新邮件, 也能保证传输的可靠. 这意味着maildir 邮箱可以安全的建立在以NFS性质挂接的文件系统上.

    例如:

        ./Maildir/
    

    这个设置表示将把邮件存储在 $HOME/Maildir 下面的 maildir 格式的邮箱.


    注意: qmail-local 可以将邮件传送到 maildir 格式邮箱, 但是不能创建这种邮箱. 你需要使用qmail 附带的maildirmake 程序来创建 maildir 格式邮箱. 例如: "maildirmake ~/Maildir". 不过要确定你使用maildir的拥有者运行maildirmake, 而不是 root 用户. 另外的方式, 你的 useradd 和 adduser 命令可能支持"skeleton"骨架目录, 例如: /etc/skel, 然后可以直接复制这个目录给所有新用户.

    4.1.4. 转发邮件

    转发邮件就是将邮件重发到指定地址. 这些写入.qmail文件内的地址不能包含注释部分和多余的空格.

    下面的写法是错的:

        &<user@example.com>
        & user@example.com
        &Joe User <user@example.com>
    

    下面的是正确的写法:

        &user@example.com
        user@example.com
        &user
    

    前两个将邮件副本转发给 user@example.com, 最后一个将邮件副本转发给本地用户 user.

    4.1.5. 扩展地址

    qmail 支持用户控制扩展地址. 在基本地址 username@hostname.domain 上扩展的扩展地址为: username-extension@hostname.domain ,用户同样可以接收发往扩展地址的邮件. 在本节其余部分, 我们讨论的范围都是在本地系统上, 所以我们将不再使用"@hostname.domain" 部分.

    给用户 username 的邮件传送指令由 ~username/.qmail 文件指定. 对于型如username-extension 的扩展地址的传送指令由用户目录下的~username/.qmail-extension 文件指定.

    举一个例子, dave-lwq@sparge.example.com 这个扩展地址的传送将由文件 ~dave/.qmail-lwq 来控制.

    扩展地址可以拥有多个字段, 例如 dave-list-qmail 这个扩展地址, 由 ~dave/.qmail-list-qmail 来控制. 在这个例子里面, dave-list-qmai 这个地址被用来订阅 qmail 的邮件列表, ~dave/.qmail-list-qmail 则负责归档这个列表的邮件到单独的邮箱里面.

    .qmail 文件可以用-default 后缀进行匹配。 所以 dave-list-qmail 可以由 ~dave/.qmail-list-default 操作. 这个文件可以一对多方式用一个.qmail文件控制所有型如 dave-list-加上任何后缀的地址. 注意 dave-list 不能由 ~dave/.qmail-list-default 控制, 因为在"list"后面没有"-".

    qmail 会使用最接近的匹配方式. 例如, qmail在传送一个标志着送给dave-list-qmail这个地址的邮件时, 会按照下面顺序查找.qmail控制文件, 并按照最先匹配的.qmail文件传送这个邮件.

        .qmail-list-qmail
        .qmail-list-default
        .qmail-default
    

    如果没有找到相匹配的.qmail文件, 传送失败, 并且将邮件反弹给发送者.

    4.2. 发送邮件

    邮件用户通常并不直接发送邮件. 典型的方式是利用邮件用户代理(Mail User Agent, MUA)程序, 例如 pine 或者 mutt 编写并发送邮件. MUA程序调用MTA传送邮件. 这个处理邮件到MTA的调用过程称为注入(injection).

    有两种方式完成注入, 一种利用SMTP协议(Simple Mail Transfer Protocol, SMTP), 或者利用MTA提供的的特定程序.

    4.2.1. SMTP 方式

    MUA程序可以使用TCP协议连接到标准的SMTP协议端口25, 可以是本地主机或者指定的邮件服务器. MUA和MTA后续进行的回话导致两个结果:

    SMTP没有身份认证的机制, 所以发送邮件的过程是不要求用户名和密码的. 但是, 大多数MTA拒绝接收既不是来自本地用户也不是发送给本地用户的邮件的. 如果一个恰当的格式的邮件被MTA拒绝, 最大的可能就是转信限制造成. 参见转信小节查看更多的如何配置转信的信息.

    4.2.2. /var/qmail/bin/sendmail 文件

    很多年以来, UNIX MTA一直都是Sendmail. 由于Sendmail的应用十分普遍, 许多程序员假定它是默认的MTA. 结果, Sendmail的本地注入机制成为标准的本地邮件注入的应用编程接口(Application Programmer's Interface, API). qmail 以及其他非Sendmail的MTA因此也提供一个sendmail程序应用于本地注入方式上, 它的工作方式和真正的Sendmail 的 sendmail程序一样.

    qmail 的用于替换Sendmail相应部分的 sendmail 程序, 通常位于 /var/qmail/bin/sendmail, 典型的Sendmail的程序位于下面这些位置:

    在qmail系统里面, 使用命令"ls -l path-to-sendmail"将会显示出, sendmail实际上是一个指向/var/qmail/bin/sendmail 的符号连接.

      $ ls -l /usr/lib/sendmail
      lrwxrwxrwx   1 root     root           29 Feb 19 11:04 /usr/lib/sendmail -> /var/qmail/bin/sendmail
    

    4.2.3. qmail-inject

    除了模仿 sendmail 的 API之外, qmail 也拥有自己的注入程序: qmail-inject. 实际上, qmail提供的sendmail 程序只是一个qmail-inject的外壳程序.

    作为一个API标准, sendmail可能更好用, 因为它使用广泛. qmail的API由qmail-inject提供, 只能在qmail系统下运行, 而sendmail接口几乎是全球通用的.

    举一个例子, 可以这样发送一个空白邮件给 joe@example.com:

     echo To: joe@example.com | /var/qmail/bin/qmail-inject
    

    4.3. 环境变量

    一些qmail程序设定和使用环境变量, 下面的表格列出了这些变量并且描述了他们的用法.

    名字 Man 帮助页 设置/使用 使用目的
    DATABYTES qmail-smtpd 使用 重载control/databytes文件
    DEFAULT qmail-command 设置 在.qmail文件名中匹配"-default"的地址部分
    DTLINE qmail-command 设置 邮件头Delivered-To部分
    EXT qmail-command 设置 地址扩展
    EXT2 qmail-command 设置 第一个破折号后面的EXT的一部分
    EXT3 qmail-command 设置 第二个破折号后面的EXT的一部分
    EXT4 qmail-command 设置 第三个破折号后面的EXT的一部分
    HOME qmail-command 设置 用户的主目录
    HOST qmail-command 设置 接收地址的域名部分
    HOST2 qmail-command 设置 在最后的点前面的HOST部分
    HOST3 qmail-command 设置 在倒数第二个的点前面的HOST的一部分
    HOST4 qmail-command 设置 在倒数第三个的点前面的HOST的一部分
    LOCAL qmail-command 设置 接收地址的local部分
    LOGNAME qmail-inject 使用 在邮件头From中的用户名(4)
    MAILHOST qmail-inject 使用 在邮件头From中的主机名(2)
    MAILNAME qmail-inject 使用 在邮件头From中的个人姓名(2)
    MAILUSER qmail-inject 使用 在邮件头From中的用户名(2)
    NAME qmail-inject 使用 在邮件头From中的个人姓名(3)
    NEWSENDER qmail-command 设置 转发的发送人地址(参考帮助文档"man dot-qmail")
    QMAILDEFAULTDOMAIN qmail-inject 使用 重载ontrol/defaultdomain 文件
    QMAILDEFAULTHOST qmail-inject 使用 重载control/defaulthost 文件
    QMAILHOST qmail-inject 使用 在邮件头From中的主机名(1)
    QMAILIDHOST qmail-inject 使用 重载control/idhost 文件
    QMAILINJECT qmail-inject 使用 指定几个选项(参见下面的表格)
    QMAILMFTFILE qmail-inject 使用 包含下一级跟踪的邮件地址列表的文件
    QMAILNAME qmail-inject 使用 在邮件头From中的个人姓名(1)
    QMAILPLUSDOMAIN qmail-inject 使用 重载 control/plusdomain 文件
    QMAILSHOST qmail-inject 使用 信封上发送者地址中的主机名
    QMAILSUSER qmail-inject 使用 信封上发送者地址中的用户名
    QMAILUSER qmail-inject 使用 在邮件头From中的用户名(1)
    RECIPIENT qmail-command 设置 信封上接收者的地址
    RELAYCLIENT qmail-smtpd 使用 忽略 control/rcpthosts 文件然后在接收地址后添加值
    RPLINE qmail-command 设置 邮件头返回路径
    SENDER qmail-command 设置 信封上发送者地址
    UFLINE qmail-command 设置 UUCP风格的"From"行
    USER qmail-command 设置 当前的用户
    USER qmail-inject 使用 邮件头From中的用户名 (3)
    QMAILINJECT 标志位 QMAILINJECT Flags
    字母 使用目的
    c 为From部分使用地址注释风格
    s 不考虑任何传入邮件的返回路径部分
    f 删除所有传入邮件的From部分
    i 删除所有传入邮件的Message-ID部分
    r 使用每接收者VERP
    m 使用每邮件VERP

    5. 高级话题

    5.1. 关于 procmail

    procmail 是一个流行的邮件传送代理( Message Delivery Agent , MDA). MDA的功能是从MTA为特定用户或者邮箱接收邮件, 然后按照用户的要求传送邮件的程序. procmail 可以用来针对邮件主体或者不同的邮件头内容过滤邮件. 举一个例子, 从某个特定的人发来的邮件可以被定向传送到某个专门为这个人准备的邮箱.

    在qmail上应用procmail有两个技巧. 第一个, procmail 通常被配置成传送邮件到/var/spool/mail 下的mbox 格式的邮箱. 你可以重新设置安装procmail到缺省的$HOME 路径下, 或者指导用户不要依赖procmail 将邮件投递到默认的mbox位置. 除非你为$HOME 邮件投递方式打补丁, 否则, procmail依然会使用/var/spool/mail 作为临时文件.

    另外一个问题是qmail-command和procmail使用的退出码是不同的. procmail使用的是标准UNIX退出码: 零代表成功, 非零代表失败, 失败的原因由/usr/include/sys/errno.h 定义. qmail-command 使用某个非零码指示永久错误, 其余作为临时码. 解决方式可以应用一个小的shell脚本为 qmail-command 翻译退出码. 这样的一个shell脚本曾经在qmail 邮件列表刊登, 现在被存档在这个位置http://www.ornl.gov/lists/mailing-lists/qmail/1998/04/msg00487.html.

    同样的情况, 旧版本的procmail(3.14之前)不能直接传送邮件给maildir格式的邮箱. 最好的办法是升级你的procmail到最新版本. 另外一个解决办法是使用safecat, 这个程序将标准输入的邮件写入指定的maildir格式的邮箱. 用户可以使用 procmail 处方(传送指令)来使用safecat 保存邮件. 也可以完全跳过procmail, 使用maildrop.

    最后, procmail 认为邮件将被接收到mbox格式的邮箱, 常规的qmail传送程序仅仅包括实际的邮件, 而不包括"From"起始行. 这里可以使用preline 命令来格式化邮件, 以保证procmail的要求. 上面链接提到的脚本就包括了 preline.

    举一个例子, 假设用户"dave"希望用procmail来处理他的邮件. 他的系统管理员设置procmail来传送邮件到默认的$HOME, 并且已经配置好了上面的退出码翻译脚本程序, 假设名字是 /usr/local/bin/qmail-procmail, 那么他的.qmail文件应该是这个样子的:

        |/usr/local/bin/qmail-procmail
    

    5.2. POP 和 IMAP 服务器

    qmail包括一个POP服务器, qmail-pop3d, 不过并没有作为qmail 安装过程的一部分. 你可以选用其他POP或者IMAP服务器, 尽管他们大多数都是为Sendmail编写的, 在qmail下运行这些服务器时, 需要作一些额外的修改工作.

    5.2.1. qmail-pop3d

    qmail-pop3d 是qmail自带的很不错的POP服务器. 很多qmail站点都使用它作为POP服务器. 它是模块化的, 可以通过不同的认证模块支持多种认证方案.


    注意: qmail-pop3d支持maildir格式的邮箱, 所以如果你的用户登录到POP服务器并且在本地运行MUA程序, 这些程序必须支持maildir格式的邮箱. 如果所有用户都是通过POP来读取邮件, 那么服务器端的邮箱格式就不是什么问题了.

    5.2.1.1. qmail-pop3d的结构

    qmail-pop3d服务器包括三个模块:

    典型的, qmail-popup由inetd 或者 tcpserver运行, 在110端口监听, 一旦有连接, 它将提示输入用户名和密码, 然后它调用checkpassword来校验用户名/密码, 通过校验后调用qmail-pop3d.

    5.2.1.2. 安装 qmail-pop3d

    1. 完整安装并测试qmail. 如果你希望所有用户都可以用 POP 方式访问邮箱, 那么首先确定 defaultdelivery 文件内容已经设置为 ./Maildir/. 如果你是按照本文的安装小节安装的qmail, /var/qmail/rc脚本已经被安装到恰当位置, 那么在文件 control/defaultdelivery 中已经配置了这个参数. 如果不是这样安装的, 则这个参数可能是在/var/qmail/rc 的 qmail-start 命令行上实现的.

    2. 从http://www.qmail.org/top.html#checkpassword下载checkpassword 程序. 如果你不需要其他特别的东西, 也可以在http://cr.yp.to/checkpwd.html 下载标准的checkpassword程序.

    3. 按照安装指导编译并安装checkpassword程序. 确定你安装程序到 /bin/checkpassword 下.


    注意: 如果你安装的是标准checkpassword, 解开源代码之后别忘记打修补错误返回码的补丁:
    patch < /usr/local/src/netqmail-1.05/other-patches/checkpassword-0.90.errno.patch  


    4. mkdir /var/qmail/supervise/qmail-pop3d

    5. 创建一个/var/qmail/supervise/qmail-pop3d/run 脚本, 包括如下内容:

    
    #!/bin/sh
    exec /usr/local/bin/softlimit -m 2000000 \
        /usr/local/bin/tcpserver -v -R -H -l 0 0 110 /var/qmail/bin/qmail-popup \
            FQDN /bin/checkpassword /var/qmail/bin/qmail-pop3d Maildir 2>&1
    
    

    这里 FQDN 是你建立的POP服务器的完整的有资格的正式域名, 例如, pop.example.net.


    注意: 由softlimit命令 指定的内存使用限度是可以依赖于你是用的的硬件平台和操作系统作适当提高的. 当连接到110端口失败或者POP3连接以难以理解的方式失败情况下, 或者你查看到如下错误信息:

      /usr/local/bin/tcpserver: error while loading shared libraries:
      libc.so.6: failed to map segment from shared object: Cannot
      allocate memory
    

    试着将这个参数提高到3000000或者5000000.


    6. mkdir /var/qmail/supervise/qmail-pop3d/log

    7. 创建包括以下内容的/var/qmail/supervise/qmail-pop3d/log/run 文件.

    #!/bin/sh
    exec /usr/local/bin/setuidgid qmaill /usr/local/bin/multilog t \
        /var/log/qmail/pop3d
    

    8. 建立log日志文件夹并且设置相应的run脚本, 将脚本链接到 /service 目录:

        chmod +t /var/qmail/supervise/qmail-pop3d   # if daemontools < 0.75
        mkdir /var/log/qmail/pop3d
        chown qmaill /var/log/qmail/pop3d
        chmod 755 /var/qmail/supervise/qmail-pop3d/run
        chmod 755 /var/qmail/supervise/qmail-pop3d/log/run
        ln -s /var/qmail/supervise/qmail-pop3d /service
    

    9. 将下面内容加入qmailctl脚本的"start"部分

        if svok /service/qmail-pop3d ; then
          svc -u /service/qmail-pop3d /service/qmail-pop3d/log
        else
          echo qmail-pop3d supervise not running
        fi
    

    10. 将下面内容加入qmailctl脚本的"stop"部分

        echo "  qmail-pop3d"
        svc -d /service/qmail-pop3d /service/qmail-pop3d/log
    

    11. 将下面内容加入qmailctl脚本的"stat"部分

        svstat /service/qmail-pop3d
        svstat /service/qmail-pop3d/log
    

    12. 将下面内容加入qmailctl脚本的"pause"部分

        echo "Pausing qmail-pop3d"
        svc -p /service/qmail-pop3d
    

    13. 将下面内容加入qmailctl脚本的"cont"部分

        echo "Continuing qmail-pop3d"
        svc -c /service/qmail-pop3d
    

    14. 将下面内容加入qmailctl脚本的"restart"部分

        echo "* Restarting qmail-pop3d."
        svc -t /service/qmail-pop3d /service/qmail-pop3d/log
    

    5.2.2. Qpopper

    如果你需要一个在mbox格式邮箱下工作的的POP后台服务程序, 你可以选用 Qualcomm的 Qpoper. 可以在这里找到 http://www.eudora.com/products/unsupported/qpopper/.

    5.2.3. Binc IMAP

    Andreas Hanssen 编写了 Binc IMAP服务器, Binc IMAP被设计为和qmail-pop3d使用相同的认证机制(checkpassword), 所以它很适合于qmail 邮件服务器. 和qmail-pop3d一样, 它只支持maildir格式的邮箱. 参见http://www.bincimap.org/.

    5.2.4. Dovecot

    Timo Sirainen 编写了Dovecot, 这是一个mbox 和 maildir 格式邮箱都予以支持的 IMAP 和 POP 服务器. 以安全为设计目标. 可以在这里访问到它 http://dovecot.procontrol.fi/.

    5.2.5. imap-maildir

    David R. Harris 整理了有关 University of Washington IMAP 服务器的关于 maildir 格式支持的补丁, 并且存档了安装过程. 参见http://www.davideous.com/imap-maildir/ .

    5.2.6. Courier-IMAP

    Sam Varshavchik 编写了一个支持maildir邮箱的IMAP 服务器. 可以在这里 http://www.courier-mta.org/imap/ 访问.

    5.2.7. Cyrus

    Carnegi Mellon 大学的Cyrus 项目包含了一个IMAP 服务器, 可以在这里找到它 http://asg.web.cmu.edu/cyrus/imapd/. Rick Updegrove 写了一个qmail到cyrus的脚本用来将邮件传送给Cyrus 存储, 这个http://msgs.securepoint.com/cgi-bin/get/qmail0308/41/1/1.html.

    5.3. POP 和 IMAP 客户端

    5.3.1. fetchmail

    fetchmail 是一个从POP或者IMAP服务器接收邮件并且再次本地注入的程序. fetchmail从qmail服务器接收邮件是没有问题的, 不过作为qmail的客户端, 要让它良好的工作, 有两个技巧.

    这里是一个在qmail系统上为某个用户配置的.fetchmailrc例子:

    poll mail.example.net proto pop3 nodns
        user dsill with password flubgart is dave here
        fetchall forcecr
    

    这个文件指示fetchmail 通过POP3协议连接mail.example.net服务器, 使用账户dsill , 密码flubgart, 登录并接收所有邮件, 然后传送这些邮件到 dave@localhost. forcecr 标志使fetchmail将每个邮件通过SMTP方式注入本地系统前对邮件的每行以回车符结束. qmail要求如此.

    5.3.2. getmail

    getmail 从POP服务器接收邮件然后传送到maildir格式的邮箱. 实际上它是个Python 脚本, 所以你在使用getmail之前需要安装Python解释器.

    getmail 由 Charles Cazabon 编写, 他在这个位置 http://pyropus.ca/software/getmail/ 为getmail维护了一个网页.

    5.4. Multi-RCPT 与 Single RCPT 传送方式的比较

    假如你是一个MTA, 你的一个用户发送一封邮件给 hostx.example.com上的三个人. 那么你有以下几种方式可以达成目标.

    1. 你可以建立一个连接到hostx主机, 发送邮件的一个拷贝给第一个用户, 发送一个拷贝给第二个用户, 发送一个拷贝给第三个用户, 然后关闭连接.
    2. 你可以开始三个进程, 每一个都建立一个和hostx的SMTP连接, 给每个用户发送一份邮件的副本, 然后关闭连接.
    3. 你可以建立一个SMTP连接, 然后发送一个标志着传送给所有三个用户的副本, 然后关闭连接.

    第一个方法明显劣于第三个. 甚至邮件很小的情况下, 整个邮件传送也需要最长的时间. 如果邮件很大, 那么将会使用很长时间并且浪费大量网络带宽.

    所以, 划掉第一个.

    第二个和第三个方法有点意思.

    第三个方法仅仅建立一个连接到hostx, 而且只发送一个邮件的副本, 这个方式取得了最有效的带宽利用率.

    第二种方式建立多个连接, 并且传送了邮件的多个副本, 这是非常浪费带宽的, 不过由于SMTP协议的现状, 这个方式可以得到更少的来回往返延迟, 从而比第三中方式更快. 而且比第三种方式更简单, 进而MTA可以被编写使用一个更直接了当的方式来传送邮件. 最后, 由于每个接收者接收到属于他自己的哪一份邮件副本, 这样才有可能让MTA实现VERPs(参见下一节)

    qmail 总是使用第二种方式(single RCPT). 而且没有补丁让qmail实现第三种方式(multiple RCPT)的传送-- 因为那将是一个非常大的修补工作.

    虽然有些病态的案例表明第二种方式比第三种方式更慢, 整体上, 系统的简单性和VERP取得的优势比这个更为重要.

    Single RCPT 传送方式比multiple RCPT方式的确使用了更多的带宽, 不过差别常常是被夸大了的. 绝大多数邮件至多只有两个接收者, 而他们通常是本别两个主机上的用户, 对于这样的情形, multi-RCPT没有任何优势. 甚至情况特殊些, 在一个邮件列表服务器上, 相对来说, multi-RCPT看起来会有很大帮助可是潜在的增益是非常微小的, 因为SMTP利用的往往只是带宽的很细碎的份额, 在绝大多数连接上, HTTP通常占用了最大的部分.

    举一个例子, 如果你的上行带宽的10%用于SMTP, 假设你的SMTP带宽由于使用multiple RCPT被降低了25%, 那么实际上应用multiple RCPT仅仅让你的SMTP需求的总带宽需求降低到了7.5%.

    5.5. 关于 VERP

    一旦一个邮件未能被传送, MTA的反应应该是按照信封上的返回路径(envelope return path, ERP)发送一个反弹邮件. 反弹邮件应该包括接收者的地址, 未能发送的原因, 以及故障是暂时的还是永久的信息. 尽管某些MTA做的不是正确的事情, 他们发送反弹邮件给邮件头的From区域标志的地址, 或者反弹邮件干脆不能识别接收者.

    对于大多数用户到用户的邮件, 这种问题没什么大不了. 人们可以按照反弹定时和邮件内容来处理. 可是对于邮件列表, 糟糕的反弹将会严重的多. 订阅者移动, 转发邮件到他们的新地址, 如果新地址发生传送问题, 并且反弹邮件只包含了新地址, 那就无法知道到底是哪个订户的邮件被反弹了.

    Dan Bernstein 为这个问题提出一个解决方案称为VERP(Variable Envelope Return Path). 使用VERP, 发送给每个邮件列表订户的邮件都拥有唯一的返回路径. 这让反弹控制可以控制查找有问题的订阅者.

    举一个例子, 一个典型的非VERP邮件列表拥有的返回地址型如listname-owner@domain. 而对于VERP类型的邮件列表, 返回地址型如listname-owner-subscriber=sdomain@ldomain, 这里订户的地址 subscriber@sdomain被嵌入到列表拥有者"owner"和符号"@"之间了. (订阅者邮件地址的"@"符号被置换成等号"=".)

    ezmlm邮件列表管理器使用VERP来自动控制反弹. 对于列表暂时的传送问题造成的某些邮件丢失, 这个管理器也提供让订阅者从列表存档文件中单独接收的功能. T

    Russell Nelson 为qmail下的Majordomo写了一个反弹控制器, 不过他没有再继续维护这个软件. 可以在这里http://www.qmail.org/bounceman-0.4.shar 访问到它.

    5.6. 故障处理

    5.6.1. 进程

    一个恰当运行着的, 完整的, 最小化安装的qmail 应该拥有下面的四个进程.

    取决于你使用的何种UNIX, 下面两个命令的一个可能列出这些进程, 而且可能还要多一点:

        ps -ef | grep qmail
        ps waux | grep qmail
    

    举个例子:

    [dave@sparge dave]$ ps waux|grep qmail
    dave      2222  0.0  0.8   836   348  p4 S    10:25   0:00 grep qmail
    qmaild     351  0.0  1.0   840   400  ?  S N  12:43   0:00 /usr/local/bin/tcpserver -v -x /etc/tcp.smtp.cdb -u 49491 -g 31314 0 smtp /var/qmail/bin/qmail-smtpd-
    qmaild    2220  0.0  1.0   844   420  ?  S N  10:25   0:00 /usr/local/bin/tcpserver -v -x /etc/tcp.smtp.cdb -u 49491 -g 31314 0 smtp /var/qmail/bin/qmail-smtpd-
    qmaill     365  0.0  0.8   748   344  ?  S N  12:43   0:00 splogger qmail
    qmailq     368  0.0  0.7   736   292  ?  S N  12:43   0:00 qmail-clean
    qmailr     367  0.0  0.6   732   272  ?  S N  12:43   0:00 qmail-rspawn
    qmails     350  0.0  0.8   776   336  ?  S N  12:43   0:00 qmail-send
    root       340  0.0  0.6   724   252  ?  S N  12:43   0:00 /usr/local/sbin/supervise /var/supervise/qmail-send /var/qmail/rc
    root       341  0.0  0.6   724   252  ?  S N  12:43   0:00 /usr/local/sbin/supervise /var/supervise/tcpserver-qmail /usr/local/bin/tcpserver -v -x /etc/tcp.smtp
    root       366  0.0  0.7   736   276  ?  S N  12:43   0:00 qmail-lspawn ./Mailbox
    [dave@sparge dave]$
    

    如果你在supervise下运行qmail或qmail-smtpd, 像上面的例子那样, 你应该能看到上面那些进程. 如果你在tcpserver下运行qmail-smtpd, 你将看到一个父tcpserver进程加上每个活动的SMTP访问建立的连接的tcpserver进程.

    如果你使用splogger (或者 multilog 或者 cyclog) 来控制日志, 你应该还有一个 splogger(或者 multilog 或者 cyclog) 进程由用户qmaill运行着.

    同时, 如果qmail忙于传送本地和远程邮件, 你将会看到最高上限为 concurrencylocal 个数的qmail-local进程, 或者最高上限为 concurrencyremote 个数的qmail-remote 进程.

    5.6.2. 日志

    5.6.2.1. multilog

    multilog, 是daemontools 软件包内的一部分, 功能是将日志记录到指定文件夹内一系列文件上.

    日志文件夹将在multilog命令行上指定, 所以你可以检查你的qmail运行脚本来确定文件夹的位置.

    log文件夹内文件数量以及每个log文件的最大长度, 是由multilog的选项决定的. log日志文件名是以文件开始记录时刻的TAI (Temps Atomique International) 时间戳命名的. daemontools里面的另外一个命令 tai64nlocal , 可以转换TAI时间戳为易读的本地时间戳.

    一个标准的multilog日志条目看起来是下面这样的:

    @4000000038c3eeb104a6ecf4 delivery 153: success: did_1+0+0/
    

    "@4000000038c3eeb104a6ecf4"是TAI时间戳, 为可选部分, 不过推荐在日志条目里面加上这个段, "delivery 153: success: did_1+0+0/" 是日志消息本身.

    5.6.2.2. splogger

    splogger 使用syslog 日志记录系统给消息打时间戳, 然后将消息送往syslog后台服务程序. Syslog的配置文件为 /etc/syslog.conf. 发送给syslog的消息拥有功能和优先级属性. syslog按照定义在/etc/syslog.conf里面的条目过滤消息, 并依据功能和优先级将消息发往以下目标: log日志文件, 远程日志主机, 或者控制台. splogger 默认情况下将记录到mail 功能下面, 所以用grep命令在syslog.conf文件里面查找"mail"可以显示出qmail的日志消息的配置.

    典型的位置包括:

    典型的syslog日志条目看起来是这样的:

    Jun  3 11:35:23 sparge qmail: 928424123.963558 delivery 153: success: did_1+0+0/
    

    "Jun 3 11:35:23" 是syslog时间戳

    "sparge" 是发送这条消息的系统名子.

    "qmail:" 是splogger 放置在所有qmail日志条目前的标签.

    "928424123.963558" 是一个可选的TAI 时间戳 (参看下一节)

    "delivery 153: success: did_1+0+0/" 是日志消息本身.

    5.6.2.3. 日志消息

    下面是一段从本地系统发送一个邮件到远程系统的日志片断:

    1 @4000000038c3eeb027f41c7c new msg 93869
    2 @4000000038c3eeb027f6b0a4 info msg 93869: bytes 2343 from <dave@sill.org> qp 18695 uid 49491
    3 @4000000038c3eeb02877ee94 starting delivery 2392: msg 93869 to remote lwq@w3.to
    4 @4000000038c3eeb0287b55ac status: local 0/10 remote 1/20
    5 @4000000038c3eeb104a13804 delivery 2392: success: 209.85.127.177_accepted_message.
       /Remote_host_said:_250_CAA01516_Message_accepted_for_delivery/
    6 @4000000038c3eeb104a4492c status: local 0/10 remote 0/20
    7 @4000000038c3eeb104a6ecf4 end msg 93869
    

    第 1 行指出qmail接收到一条新邮件, 邮件的队列ID是93869. 队列ID是 /var/qmail/queue/mess/NN/ 包含这个邮件的队列文件的 i-node 节点值. 队列ID将在这个消息存在于队列的过程中保持全局唯一.

    第 2 行表明邮件来自 dave@sill.org, 并且大小为2343字节.

    第 3 行表明qmail-remote开始传送这个邮件到lwq@w3.to, 并且为这个传送指定了ID 2392.

    第 4 行指出 0 个本地传送和 1 个远程传送处于等待状态.

    第 5 行显示出 ID 2392 这个传送已经成功完成, 并且返回远程主机的回应, 这个回应里面常常包含了远程邮件管理员对于跟踪这个传送的有用信息. 在我们这个例子里面, "CAA01516"是远程系统的传送ID.

    第 6 行指出 0 个本地传送和 0个远程传送处于等待状态. 也就是传送已经完成了.

    第 7 行指出这个消息已经被传送完毕并且被移出队列. 这个时候, 队列ID 93869, 已经可以重用于其他传送ID了.

    5.7. 大型服务器

    同时参考 qmail-ldap

    5.7.1. 可伸缩的并行运算

    使用快速NFS网络文件服务器储存用户文件夹. 在文件服务器上建立多个平等优先级SMTP服务器传送maildir格式邮箱.

    5.8. 从 Sendmail 转移到 qmail

    查看Dan Bernstein 的 Sendmail->qmail 网页 http://cr.yp.to/qmail/sendmail.html.

    5.9. 邮件列表管理器

    邮件列表管理器(MLM)是帮助邮件列表所有者运行邮件列表的的程序. 它的功能由两部分组成: 管理订阅者列表, 还有就是控制对订阅者的邮件再发.

    大多数(全部?)UNIX邮件列表管理器都可以和qmail 合作运行.

    5.9.1. ezmlm

    ezmlm 是qmail的作者Dan Bernstein为qmail编写的邮件列表管理器. 它依赖于qmail服务器的几个特点工作, 最显著的, 就是它使用VERPs 来可靠的处理反弹邮件. ezmlm 在众多邮件列表管理器(MLM)中显得有点独特, 它不是处理传送到中央MLM地址的命令, 而是将命令附加在列表名字后面. 例如, 发送邮件到"foo-subscribe@list.example.net" 来订阅 "foo@list.example.net" 的邮件列表, .

    关于ezmlm的更多信息, 参见 http://www.ezmlm.org/, 这是ezmlm的非正式web站点. ezmlm-idx的正式站点, 介绍了这个非常棒的add-on插件ezmlm-idx, 它包括了很多有用的特色.

    5.9.2. Majordomo

    Majordomo 是最受欢迎的UNIX MLM之一. 只要作很少的简单修改就可以使它和qmail很好的合作了. Russ Allbery曾经写了一个关于qmail和Majordomo的FAQ, 可以在这个位置访问http://web.archive.org/web/20050308091420/http://www.eyrie.org/~eagle/faqs/mjqmail.html.

    5.10. 补丁 Patches

    qmail拥有各种各样的源代码补丁. 为了安装补丁, 下载补丁并且进入qmail源代码目录树, 使用patch 命令施加补丁.

        cd /usr/local/src/qmail/qmail-1.03
        patch -p0 </tmp/patchfile
    


    注意: 参考 patch 的 man 帮助页取得更多信息. 这仅仅是个例子. 你可能需要使用最新版本的GNU patch 来施加补丁, 参见http://www.gnu.org/software/patch/patch.html.


    终止 qmail-send 来停止qmail, 或者如果你安装了 qmailctl 脚本, 那么这样:

        qmailctl stop
    

    然后重新编译和安装新的二进制代码:

        make setup check
    

    然后重新启动:

        qmailctl start
    

    最后测试qmail, 尤其是你打补丁的部分.


    注意: 虽然http://www.qmail.org/列出了qmail的大量补丁, 但是他们中的任何一个都没有得到qmail作者的认可. 这些补丁可能引入qmail原本没有的安全, 可靠性, 效率以及功能性问题. 绝大多数qmail安装只是要求某些推荐的补丁. 请不要安装任何你不是明确需要的补丁.


    5.10.1. 推荐的补丁

    qmail.org 有一个"Recommended Patches"小节 http://qmail.org/top.html#patches . 这些补丁用于几个已知的qmail的bug.


    注意: 所有推荐补丁都已经包括在 netqmail发行版中. 请参考http://www.qmail.org/netqmail/.

    5.10.1.1. errno.h 补丁

    这个补丁修复 errno.h 头文件缺失问题. 参考http://article.gmane.org/gmane.mail.qmail.general/13960 查看这个补丁, 以及的详细的解释.

    Mate Wierdl 为所有 Dan Bernstein 的软件, 其中包括 qmail, daemontools 和 ucspi-tcp 编写了关于 errno.h 的补丁. 可以在这里找到这些补丁文件: http://www.thedjbway.org/patches/djb_errno_patches.tgz.

    5.10.1.2. qmail-local TAB 补丁

    这个补丁修补处理.qmail文件内对TAB 字符开头命令解析的小bug. 参见http://www.ornl.gov/lists/mailing-lists/qmail/2000/10/msg00696.html

    5.10.1.3. IP 0.0.0.0 补丁

    这个补丁将使qmail把 0.0.0.0 这个IP地址作为本地主机处理. http://www.suspectclass.com/~sgifford/qmail/qmail-0.0.0.0.patch .

    5.10.2. DNS

    在历史上, DNS 的回答被限制在512字节以内. 一些大型站点返回的 MX 记录要长于这个限度. 这样qmail和其他很多程序都会遇到这个DNS返回查询记录过长的问题. 有两种种方式来修补qmail, 其中任何一个都够用了.

    5.10.2.1. Christopher K. Davis 的补丁程序, http://www.ckdhr.com/ckd/qmail-103.patch

    Chuck Foster 写了一个补丁修正, 可以配合任何一种DNS 解析库工作, 无论多老的库, 这个补丁使用一个保护字节来避免"置于缓冲区中的字节数"这个库bug. 通过一次性重分配缓冲区为65536大小, 而不是申请分配恰好合适的缓冲区大小来解决问题, 所以它可能要比Chuck 的补丁内存使用效率低. (尽管如此, 这个补丁也只是当返回大小大于PACKETSZ 情况下才进行缓冲区重分配, PACKETSZ 的默认大小为512字节). 缓冲区重分配后, 将强制一次TCP查询, 而不是要求DNS 解析库去作解析(这样避免了qmail 和名字服务器之间的额外来回交互过程, 尽管qmail 和名字服务器可能都在一个服务器上, 或者都在本地网络内, 这些来回交互过程并不是什么问题).

    5.10.2.2. 提高包缓存长度到65536

    如果DNS反馈设置有切断位, 在近来的BIND解析库下工作时, 解析器编码为自动进行TCP查询. 虽然取决于你的系统如何管理系统内存页的情况下, 内存的最大浪费成为潜在存在的可能性, 不过这却是最简单的修补. 作这个修补, 只需要替换 dns.c 文件内的PACKETSZ为 65536, 然后重新编译安装qmail就行了.

    5.10.2.3. 从djbdns 运行 dnscache

    dnscache 顾名思义, 是一个DNS的缓存服务器. 它知道如何掌握很长的DNS 返回记录, 去掉不必要的查询信息, 所以通过它返回的结果通常比直接查询更小, 并且通常可以为所有服务提高DNS查询性能. 由于它不用给qmail打补丁, 这是一个可以接受的方式, 遗憾的是, 它并不能完全解决问题, 通过它返回可能对qmail 还是过大. 参见 相关软件包 下的 djbdns 节取得更多信息.

    5.10.3. qmail-ldap

    这个补丁, 由 Andre Oppermann等人编写, 实现了qmail的Lightweight Directory Access Protocol (LDAP)支持. LDAP像一个网络电话簿. 使用 qmail-ldap, 它可以使一个POP服务器支持数千计的众多用户. 参见http://www.nrg4u.com/.

    5.11. QMTP

    QMTP 是 Quick Mail Transfer Protocol 的缩写, 由Dan Bernstein设计的用来替代SMTP的协议. 这个协议定义在 http://cr.yp.to/proto/qmtp.txt . QMTP比SMTP更简单, 更快速以及兼容SMTP. qmail包含一个QMTP服务器, qmail-qmtpd, 它运行起来非常类似于 qmail-smtpd. QMTP通常使用端口209.

    qmail并不包括QMTP的客户端, 不过 serialmail 软件包包括一个客户端. maildirqmtp 命令接收maildir格式邮箱并以QMTP协议传送邮箱内的邮件到指定的QMTP服务器.

    QMTP不是一个drop-in方式的SMTP的替代品, 在因特网上的使用也不是很普遍.

    Russ Nelson 为qmail-remote写了一个支持QMTP的补丁. 可以在 这里 http://www.qmail.org/qmail-1.03-qmtpc.patch 取得这个补丁. 他也编写了一个tarball安装方式的程序, 可以展开到 /service 目录下进行QMTP服务. 可以在这里http://www.qmail.org/qmtpd-service.tar.gz 取得这个tarball包.

    5.12. 在SMTP对话过程中拒绝无效接收者

    当一个远端服务器连接到 qmail-smtpd服务并提交了一个邮件时, qmail-smtpd服务会依据 control或 rcpthosts的内容来检查收件人的地址. 如果接受者的服务器名或域名(就是邮件地址在@符号后面的部分)在这两个列表内存在,qmail-smtpd 会接受这封邮件, 并将邮件放置于发送队列内, qmail-send 将开始尝试传送邮件. 如果通过名字在本地接收者内查找不到接收用户或者别名, 即本地接收者无效, qmail-send 会生成一个反弹邮件并将邮件传送到回复地址, 这个回复地址在SMTP对话过程中确定.

    在一个秩序并礼貌的世界, 任何策略或计谋都是有好的结果的. 但很不幸, 除此之外, 还有很多行为恶劣的垃圾邮件制造者. 一些垃圾制造者试图把邮件发送到你服务器上"可能"存在的用户邮箱, 他们使用常用名字字典或数据库, 甚至他们穷举所有可能的字母组合来构成一本名字字典, 向整个字典或数据库内所有"可能"存在的人发送垃圾邮件.

    在qmail 系统内, 这种垃圾邮件行为会造成巨大的系统负担, 邮件队列内充斥垃圾, 并且耽搁了合理合法邮件的传送.

    一些MTA 在SMTP 对话过程中对本地邮件接收者进行确认并对不匹配的邮件予以拒绝, 这免去了邮件服务器大量的不必要工作, 但也带来了负面影响, 使用这种校验方式, 垃圾邮件制造者可以迅速确定那些邮件地址在你的服务器上是存在的.

    有几种方式可以在qmail 上实现在SMTP 对话过程中校验用户名是否存在. Eben Pratt 建立了一个列表, 在这里http://netdevice.com/qmail/rcptck/ . 绝大多数这种解决方案都要求提供一个有效或无效接收者的数据库或者相应模式. 其中一个不使用数据库的解决方式是Paul Jarc 的qmail-realrcptto, 可以在这里找到它http://code.dogmap.org./qmail/.

    5.13. TLS and STARTTLS

    关于在qmail 上使用传输层加密(TLS), Scott Gifford 写了一个非常详细彻底的一步一步介绍文档, 包括在SMTP 上使用STARTTLS 和在POP3D 上使用STLS, 专门用于netqmail , 可以在这里访问这个文档: http://www.suspectclass.com/~sgifford/ucspi-tls/ucspi-tls-qmail-howto.html.

     


    附录 A. 致谢

    首先, 感谢Dan Bernstein 编写了这样一个强大而优雅的系统. 经过近十年的使用, qmail依然给我深刻的印象.

    我也感谢那些qmail 邮件列表的成员. 作为最有帮助的, 最有耐心的, 以及最知识渊博和有趣的撰稿人之一, Russell Nelson 应该被特别提及, 他对于qmail 社区的贡献仅次于DJB. 其次是Charles Cazabon, 他紧接着Russ 之后, Charles 是最近邮件列表的主要撰稿者, 比其他人更多的给出正确答案. Charles 还写了两个非常有用的实用程序--getmail 和pymsgauth, 同时还是The qmail Handbook 的技术编辑, 他的文章被认为是此书成功的重要原因, 因此他也得到了不少奖赏和赞誉.

    感谢每一个评论或者对这个文档作出贡献的人, 他们包括:

    特殊感谢Henning Brauer捐赠了lifewithqmail.org 域名, 并维护服务器!

    Life with qmail 使用Simple Document Format (SDF) 编写, SDF是一个非常酷的基于Perl 的标记语言, 可以产生HTML, 纯文本, PostScript, POD以及其他格式. 这个工具使工作变得特别容易, 参见http://search.cpan.org/author/IANC/sdf-2.001/ 查找关于这个工具的更多信息.


    附录 B. 相关软件包介绍

    B.1. dot-forward

    Sendmail 使用.forward(发音 dot forward)文件来允许用户控制传输他们收到的邮件. qmail使用一种类似的机制: .qmail文件. dot-forward软件包给予qmail使用.forward文件的能力. 那些使用Sendmail和其他使用.forward控制文件的系统可以利用dot-forward程序来避免使用.forward文件的等效物.qmail文件, 在转移到qmail 品太过程中不用将.forward 文件转换为.qmail 文件, 或者简单地对于用户来说, 在使用qmail平台时尽量少的改变用户原来使用Sendmail时看得到的东西., 比如直接使用. forward文件的习惯.

    dot-forward程序是一个小软件包, 很容易安装配置. 源代码可以在http://cr.yp.to/software/dot-forward-0.71.tar.gz.这里取得.

    dot-forward 由Dan Bernstein编写, 他为这个软件维护了一个web页面http://cr.yp.to/dot-forward.html.

    B.2. fastforward

    fastforward是另一个Sendmail兼容插件. Sendmail使用保存在一个单一文件内的中心别名数据库, 通常是 /etc/aliases. qmail使用/var/qmail/alias下的一系列文件, 一个别名一个文件. 如果你要从Sendmail迁移到qmail, dot-qmail文件还不想转换Sendmail格式的的别名文件, 那么fastforward赋予qmail按照原样使用Sendmail别名文件的能力.

    源代码可以在 ftp://cr.yp.to/software/fastforward-0.51.tar.gz 这里取得.

    fastforward 由Dan Bernstein 编写, 他在 http://cr.yp.to/fastforward.html 这里维护了一个web页面.

    B.3. ucspi-tcp

    qmail的SMTP服务器并不是按照一个独立的后台服务程序运行的, 必须依靠例如 inetd, xinetd 或者 tcpserver 这些助手程序运行. 当这些助手程序接受一个到达25端口, SMTP端口, 的TCP连接之后, 将执行一个qmail-smtpd的副本.

    inetd 是标准网络服务器"super-server". 可以通过配置/etc/inetd.conf 来运行qmail-smtpd, 不过推荐的工具是tcpserver, 它是ucspi-tcp软件包的一部分. ucspi-tcp是UNIX Client-Server Program Interface for TCP的缩写, 发音是 ooks-pie tee see pee.

    tcpserver 优于 inetd的几条原因:

    源代码可以在这里ftp://cr.yp.to/ucspi-tcp/ucspi-tcp-0.88.tar.gz取得.

    Gerrit Pape 为ucspi-tcp作为 man 帮助页分发的文档可以在这里http://smarden.org/pape/djb/ 访问到.

    ucspi-tcp由Dan Bernstein编写, 他在这里http://cr.yp.to/ucspi-tcp.html维护了一个web页.

    B.4. daemontools

    daemontools软件包包含了一系列控制和监视服务的实用工具. 不强制使用, 但高度推荐, 特别是对于比较繁忙的系统. 它包括:

    daemontools的源码可以在这里http://cr.yp.to/daemontools/daemontools-0.76.tar.gz取得.

    Gerrit Pape 为daemontools作为 man 帮助页制作的发行文档可以在这里http://smarden.org/pape/djb/访问到.

    daemontools 由Dan Bernstein编写, 他在这里http://cr.yp.to/daemontools.html 维护了一个web页面.

    B.5. qmailanalog

    qmailanalog处理qmail的日志文件并且生成一系列的报告. 报告指示出系统正在工作的类型和工作量. 如果你需要有多少邮件被发送和接收的统计, 以及他们有多大, 他们被处理的有多快, qmailanalog都能显示出来.

    作为一个意外收获, matchup 程序合并qmail 的每个邮件投递的多个日志行为一行 -- 有点类似于Sendmail的日志.

    qmailanalog的源代码可以在这里http://cr.yp.to/software/qmailanalog-0.70.tar.gz取得.

    qmailanalog 由Dan Bernstein编写, 他在这里http://cr.yp.to/qmailanalog.html维护了一个web页面.


    注意: qmailanalog 依赖于由accustamp 使用的小数秒格式的日志条目时间戳. 为了使用它和multilog生成的TAI64N格式的日志, 你必须将他们转换成旧格式. 一个完成这个转换工作的程序可以在这里http://www.qmail.org/tai64nfrac取得.

    B.6. rblsmtpd

    如果你从未被垃圾邮件骚扰, 可以说你太幸运了. 绝大多数的电子邮件用户都太熟悉Unsolicited Bulk E-mail (UBE)了, UBE也被称为"spam". 绝大多数垃圾邮件都是色情站点的广告, 邮件锁链或其他诡计. 回到过去的的旧时光, 直到1998年左右, 绝大多数因特网上的MTA都是开放转信的, 也就是说, 他们将会接收任何人给人和人的邮件, 甚至没有发信人也没有本地收信人的邮件. 垃圾邮件发送者利用这些开放转信服务, 尽可能找到他们能找的服务器传送他们的垃圾邮件. 这样就隐藏了他们的踪迹, 栽赃给那些"无罪的"开放转信站点, (通过浪费开放转信站点的资源) 为垃圾邮件制造者节省了大量的CPU和带宽.

    从那个时期开始, 这样的开放转信的站点被认为是非常糟糕的, 几个反垃圾邮件义务组织创造了一个机制来识别开放转信和其他垃圾邮件的通常来源, 这样他们就能够避免来自垃圾邮件商的SMTP连接.

    rblsmtpd 是一个 RBL SMTP后台服务程序. 它位于tcpserver和qmail-smtpd之间, 并且拒绝系统认定的那些列表里面系统的连接.

    举一个例子, 在tcpserver下运行rblsmtpd, 试试下面这样的写法:

    #!/bin/sh
    QMAILDUID=`id -u qmaild`
    NOFILESGID=`id -g qmaild`
    MAXSMTPD=`cat /var/qmail/control/concurrencyincoming`
    exec /usr/local/bin/softlimit -m 2000000 \
      /usr/local/bin/tcpserver -v -R -H -l 0 -x /etc/tcp.smtp.cdb -c "$MAXSMTPD" \
        -u "$QMAILDUID" -g "$NOFILESGID" 0 smtp /usr/local/bin/rblsmtpd\
        -r relays.ordb.org /var/qmail/bin/qmail-smtpd 2>&1
    
    

    rblsmtpd 以前是作为一个分立的软件包, 现在被捆绑在ucspi-tcp 里面.

    rblsmtpd 由Dan Bernstein 编写, 他在这里http://cr.yp.to/ucspi-tcp/rblsmtpd.html 维护了一个web页面.

    RBL 硬编码不再free 之后, Charles Cazabon 制作了一个补丁用来移去默认的RBL 硬编码, 替换为为rblsmtpd 程序, 这个程序可以在这里访问到 http://pyropus.ca/software/misc/rblsmtpd-nodefaultrbl.patch.

    B.7. serialmail

    qmail 是为高速连接, 不间断运行设计的. serialmail 这个工具集让qmail更好的适用于断断续续的, 低速的连接. 在这样的系统上使用serialmail, qmail被配置为传送所有远程邮件到一个单独的maildir文件夹. 一旦网络连通, serialmail的maildirsmtp 命令将用来上传这个maildir到ISP的邮件中心. 如果ISP支持QMTP(参看 高级话题 下的 QMTP), maildirqmtp也能用得上.

    serialmail 可以被用于ISP方面, 用来实现 AutoTURN, 这是一个 由客户端发起的SMTP 连接, 导致服务器开始反向连接到客户端 , 然后发送服务器端的邮件队列给客户端的过程. 这个和ETRN SMTP机制很相似.

    serialmail的源代码可以在这里http://cr.yp.to/software/serialmail-0.75.tar.gz 得到.

    serialmail 由Dan Bernstein编写, 他在这里http://cr.yp.to/serialmail.html维护了一个web页面.

    B.8. mess822

    mess822 是一个处理 RFC822兼容邮件的库和一系列应用程序. 这些程序包括:

    mess822的源代码可以在这里 http://cr.yp.to/software/mess822-0.58.tar.gz取得.

    mess822 由Dan Bernstein编写, 他在这里http://cr.yp.to/mess822.html维护了一个web页面.

    B.9. ezmlm

    ezmlm 是一个为qmail设计的高效, 易用的邮件列表管理器(MLM). 如果你熟悉 LISTSERV 或者 Majordomo, 你会知道邮件列表管理器能作什么. 更多在qmail下的关于邮件列表的信息可以在高级话题 下面的 邮件列表管理器 找到.

    ezmlm的源代码可以在http://cr.yp.to/software/ezmlm-0.53.tar.gz这里取得.

    ezmlm 由 Dan Bernstein编写, 他在这里http://cr.yp.to/ezmlm.html维护着一个web页面.

    Fred Lindberg 和 Fred B. Ringel 为ezmlm开发了一个扩展, 叫做ezmlm-idx, 后者增加了大量的有用特色, 我特别推荐使用它. 可以在 http://www.ezmlm.org/ 这里访问 ezmlm-idx, 这个页面现在有Bruce Guenter 维护.

    B.10. safecat

    safecat 将文件可靠的写入maildir 邮箱中. 在使用procmail 处方时候有个特别的用处, 用来将邮件填入 procmail. 举一个例子, 下面的处方将所有Maildir中的邮件存档.

    :0w
    |safecat Maildir/tmp Maildir/new
    

    safecat 由 Len Budney 编写, 他在这里http://jeenyus.net/~budney/linux/software/safecat.html.为safecat 维护了一个web页面.

    B.11. djbdns

    djbdns 是qmail作者编写的DNS服务器. 它包括 tinydns, 一个DNS内容服务器, 和 dnscache, 这是一个 DNS 缓冲服务器.

    djbdns的正式页面在 http://cr.yp.to/djbdns.html.

    B.12. maildrop

    maildrop是一个和procmail类似的邮件过滤器.

    maildrop 由 Sam Varshavchik 编写, 他在这里http://www.courier-mta.org/maildrop/.为maildrop维护了一个web页面.

    B.13. syncdir

    syncdir 是一个小型库, 可使 link() 系统调用同步. 在一个不能同步执行 link() 的文件系统上运行qmail队列时, syncdir是必要的. 例如 Linus的 ext2fs, Reiserfs, SGI的 XFS以及BSD的使用softupdates的FFS系统.

    syncdir 由 Bruce Guenter编写, 可以在这个web页面http://untroubled.org/syncdir/访问. 安装指导在这个位置http://www.ornl.gov/lists/mailing-lists/qmail/2001/12/msg00949.html.


    附录 C. 因特网邮件工作原理

    C.1. 邮件如何从A点到达B点

    当一个主机上的用户想要发送一个邮件给另一个主机上的用户时, 许多事情发生了, 这个场景后面的东西很多是不必要知道的那么确切的.

    假设一个用户 Alice, alice@alpha.example.com 想要发送一个邮件给 Bob, bob@beta.example.com, 下面是发送接收过程:

    1. Alice 用她的邮件用户代理(MUA)编写邮件, 比如使用 mutt 或者 pine. 她在 To 这一栏指定接收者, Subject 这一栏填写邮件主题, 加上邮件本身的文本部分. 整个邮件看起来是下面这样的:

        To: bob@beta
        Subject: lunch
    
        How about pizza?
    

    2. 当她觉得这封邮件已经满意之后, 她指示 MUA 发送邮件.

    3. 这时候, MUA 会加上附加的邮件头部分, 比如日期 Date 和邮件ID(Message-Id) 并且修改Alice输入的值(例如, 将 bob@beta 替换为"Bob <bob@beta.example.com>") 下一步, MUA 将邮件注入邮件系统. 有两种方式进行注入: MUA 运行一个由邮件系统提供的为注入邮件为目的的程序; 或者使用SMTP协议和本地或者远程邮件服务器建立连接, 在本例内, 我们假定 MUA 使用本地注入程序将邮件传送给 MTA, 对于不同的MTA, 注入细节都是不同的, 不过对于UNIX系统, 使用sendmail 程序注入已经成了事实上的标准. 使用这种方式, MUA 可以将邮件头和邮件主体放置在一个文件内, 由空行分隔, 然后传递这个文件到 sendmail 程序.

    4. 如果注入成功--邮件句法正确, 并且 sendmail 调用适当--那么现在邮件由 MTA 负责. 不同的 MTA 细节是完全不同的, 通常MTA首先检查邮件头决定邮件将发往何处. 然后建立一个到主机beta的SMTP连接, 转发邮件给 beta 系统上的MTA. SMTP对话要求邮件被分成两部分发送: 第一部分是信封, 这个部分确定了接收者的地址(bob@beta.example.com)和返回地址(alice@alpha.example.com), 以及第二部分邮件本身, 包括邮件头和邮件主体.

    5. 如果beta主机的MTA拒绝这个邮件, 可能原因是在beta系统上没有这个bob用户, 在alpha 上的MTA发送一个反弹邮件给返回地址, 也就是 alice@alpha, 通知她邮件发送出现了问题.

    6. 如果 beta主机上的 MTA接收了邮件, 它查看接收者地址, 决定是发送给本地local 还是远程 remote系统的邮件. 这个例子里面, 接收者是本地用户, 然后MTA或者传送邮件给 mail delivery agent (MDA), 比如 /bin/mail或者传送给 procmail.

    7. 如果传输失败了, 可能是Bob的邮箱超过了使用限额, beta 主机上的 MTA 将发送一个反弹信息给信封上的返回地址, 即 alice@alpha.

    8. 如果传输成功, 邮件将在Bob的邮箱中等待, 直到他使用MUA来阅读和显示邮件.

    C.2. 其他资料 C.2. More information

    关于因特网邮件工作方式的更多信息, 请查看下面的信息:

    C.2.1. 因特网的RFC文档

    Internet Requests for Comment, 缩写为Internet RFC是关于因特网标准的正式文档. 大部分Internet RFC 文档已经度过了评论阶段, 进入稳定状态, 他们定义了包括诸如 TCP, FTP, Telnet和各种各样得邮件标准和协议.

    一个综合性的邮件相关RFC列表可以在Internet Mail Consortium的web网站上找到 http://www.imc.org/mail-standards.html.


    附录 D. 体系结构

    D.1. 模块化系统结构

    因特网MTA可以完成多种任务. 早期如 Sendmail和 smail的设计是整体式的, 换句话说就是他们是一个大而复杂的程序, 其中一部分是SMTP服务器, 另一部分是SMTP客户端, 另外的是本地邮件注入, 还有管理邮件队列的部分,等等.

    qmail是模块化的, 每个功能都是由单独的程序执行的, 结果程序更小, 更简单, 而且更不容易出现功能和安全方面的问题. 为了进一步增强qmail的安全性, qmail模块以不同的权限模式运行, 模块之间互不"信任", 他们并不以为其他模块总是按照他们假定的方式去运行.

    这些是qmail的核心模块:

    模块 功能
    qmail-smtpd 接收/拒收通过SMTP传递的邮件
    qmail-inject 本地邮件注入
    qmail-rspawn/qmail-remote 控制远程传输
    qmail-lspawn/qmail-local 控制本地传输
    qmail-send 处理队列
    qmail-clean 清除队列

    模块化也有一些不利因素, 整体式的MTA, 模块之间的相互作用定义良好, 而且模块之间只是交换最小的必要信息. 这是个大好事, 但模块化方式使处理某些事情变的困难起来. 举个例子, 为了debug目的, 运行sendmail 并使用"-v"选项, 使 Sendmail 打印它的活动跟踪消息到标准输出, 由于所有的包括邮件注入, 队列控制, 别名处理, .forward文件处理, 以及远程SMTP转发邮件等等都是由一个 sendmail 二进制程序控制, 那么可以很容易的跟踪整个邮件传送过程直到邮件被送抵目的地. 这样的等价物在qmail里面是不存在的, 如果在qmail上执行这样的"debug"过程, 需要实质性的改变源码以及在模块到模块之间的过程调试, 这增加了的很大复杂性.

    D.2. 文件结构

    /var/qmail 是qmail的文件结构的根. 在qmail 编译安装的时候可以选择改变这个目录的位置, 不过最好还是不作改动的安装到默认位置, 这样其他的管理员就知道到哪里能找到需要的东西. 如果你真的想重新定位部分或者全部的qmail 目录树, 最好的办法是使用符号连接方式. 详细信息请参看创建目录 小节中的细目.

    qmail 根目录下面的一级子目录:

    目录 内容
    alias 系统级别名定义的.qmail文件
    bin 二进制程序和可执行脚本
    boot 启动脚本
    control 配置文件
    doc 文档(不包括man 手册页)
    man man 手册页
    queue 未送出的邮件
    users qmail-users 的数据库文件

    D.3. 队列结构

    在qmail的安装目录下的 INTERNALS文件更充分的讨论了有关的细节信息. 下面是一些更宽泛的队列结构的概述.

    子目录 内容
    bounce 永久传送错误
    info* 信封发送者地址
    intd 由qmail-queue构建的信封
    local* 本地信封接收者地址
    lock 文件锁文件
    mess* 邮件文件
    pid 由qmail-queue使用用来获得 i 节点编号
    remote* 远程信封接收者地址
    todo 完整的信封


    注意: 由"*"标志的目录包含了一系列分开的由"0", "1",..., (最大数字直到conf-split 减去 1)这些数字命名的子目录. 这里conf-split 是由源代码目录下的conf-split 文件设定的一个参数, 在编译源码时确定, 默认是23. 分离出多个子目录是为了在繁忙的服务器上降低单个目录里面的文件数量. conf-split 必须是个质数.

    在mess组目录下的文件由它们的 i 节点编号命名. 这就意味着你不能使用标准的UNIX工具, 比如mv, dump/restore还有 tar来手动地移动这些文件. 这里有两个用户提供的实用工具, 可以使用它们来正确地重命名队列文件. 可以在这里http://www.qmail.org/ 找到这些工具.


    注意: 当qmail正在运行地时候, 修改队列文件是不安全的. 如果你想更改队列, 首先停止 qmail, 然后仔细的处理队列, 然后重启qmail.

    D.4. 图片

    在 /var/qmail/doc 下面有一系列的以 PIC 名字开头的文件. 这些是qmail处理不同情况的文本"图片". 它们显示了qmail 在各个模块之间处理的控制流, 在处理问题和建立复杂系统配置的时候这些图片将大有裨益.

    文件名 处理场景
    PIC.local2alias 传递给本地别名的本地注入邮件
    PIC.local2ext 传递给扩展地址的本地注入邮件
    PIC.local2local 传递给本地用户的本地注入邮件
    PIC.local2rem 传递给远程地址的本地注入邮件
    PIC.local2virt 传递给本地虚拟域上的一个地址的本地注入邮件
    PIC.nullclient 注入到空用户的邮件
    PIC.relaybad 使用本地主机转信失败的尝试
    PIC.relaygood 使用本地主机转信成功的尝试
    PIC.rem2local 通过SMTP为本地用户接收邮件

    这些图片也可以在线观看, 地址如下:

    如果你想看qmail的"真实"图片, 那么请查看Andre Opperman 的 "big qmail picture", 地址在http://www.nrg4u.com/ .


    附录 E. 一些不常见的问题 Infrequently Asked Questions

    一些没有资格称为常见问题的问题, 可是还是很重要也不容易回答的.

    E.1. qmail如何处理延期发送的邮件?

    每个邮件都有自己的重试时间表, 越长时间不能发送的邮件, 得到qmail重发的机会就越少. 重试时间表是不可更改的. 下面的表格显示了一个发往远程接收者的邮件, 如果这封邮件每次都无法发送, 直到这封邮件被反弹, 整个重试时间表如下. 本地传送邮件使用一个相似的不过频率更高的时间表.

    重试次数 天-小时-分钟-秒
    1 0 0-00:00:00
    2 400 0-00:06:40
    3 1600 0-00:26:40
    4 3600 0-01:00:00
    5 6400 0-01:46:40
    6 10000 0-02:46:40
    7 14400 0-04:00:00
    8 19600 0-05:26:40
    9 25600 0-07:06:40
    10 32400 0-09:00:00
    11 40000 0-11:06:40
    12 48400 0-13:26:40
    13 57600 0-16:00:00
    14 67600 0-18:46:40
    15 78400 0-21:46:40
    16 90000 1-01:00:00
    17 102400 1-04:26:40
    18 115600 1-08:06:40
    19 129600 1-12:00:00
    20 144400 1-16:06:40
    21 160000 1-20:26:40
    22 176400 2-01:00:00
    23 193600 2-05:46:40
    24 211600 2-10:46:40
    25 230400 2-16:00:00
    26 250000 2-21:26:40
    27 270400 3-03:06:40
    28 291600 3-09:00:00
    29 313600 3-15:06:40
    30 336400 3-21:26:40
    31 360000 4-04:00:00
    32 384400 4-10:46:40
    33 409600 4-17:46:40
    34 435600 5-01:00:00
    35 462400 5-08:26:40
    36 490000 5-16:06:40
    37 518400 6-00:00:00
    38 547600 6-08:06:40
    39 577600 6-16:26:40
    40 608400 7-01:00:00

    E.2. 为什么我无法给一个有很多MX记录的大站点发送邮件?

    如果你得到下面的错误提示:

    deferral: CNAME_lookup_failed_temporarily._(#4.4.3)/
    

    出问题的原因是qmail不能处理名字服务器返回的大尺寸查询返回. 安装 djbdns 来解决这个问题. 参考高级话题下面的 补丁 小节.

    不过也有一些人使用这样的系统但是却没有遇到这样的问题. 本质上说, 这取决于对你本地名字服务器查询的定时和排序, 名字服务器对于"aol.com"的ANY查询返回的可能是大于512 字节 的 UDP 数据包, 或者可能不是.

    "可能不是" 这种情况可能是碰巧查询的A记录和MX记录超时, 而NS记录没有超时. 由于 .COM的服务器设置的TTL记录生命期为2天, 而AOL的TTL只有1个小时, 这种超时现象会经常在较少的某些比较忙的名字服务器上发生. 比较忙碌的名字服务器更大的可能在所有开放时间把这些记录放在他们的高速缓存中. 查询超时而又没有打补丁的qmail将会试着去查询CNAME记录.

    一个更好的测试方式是发送邮件到nosuchuser@large-mx.ckdhr.com这里; 如果邮件被清除出了你的邮件队列, 并且从ckdhr.com反弹信息给你, 就表明你的MTA可以发送邮件给拥有超过512字节MX列表记录的主机. (如果使用单一查询项目, 在一个TTL生命期中, 尽管查询结果超过了512字节, 可是由于单一查询不依赖于定时和排序, 这个问题将不会被表现出来)

    E.3. QUEUE_EXTRA 是什么?

    QUEUE_EXTRA是一个编译时的配置参数, 用它来确定每个邮件传送的一个附加的接收者. 这个参数首先用于日志记录. 例如, FAQ里面描述的如何使用QUEUE_EXTRA来保存所有的进出邮件.

    要使用QUEUE_EXTRA, 编辑 extra.h 使用"Trecipient\0"这个格式确定附加的接收者, QUEUE_EXTRA的长度由QUEUE_EXTRALEN确定("\0"算成一个字符). 举一个例子:

        #define QUEUE_EXTRA "Tlog\0"
        #define QUEUE_EXTRALEN 5
    

    关掉正在运行的qmail. 如果你按照本文安装顺序, 运行下面的命令:

        qmailctl stop
    

    如果你没有qmailctl脚本, 你可以使用你的启动/关闭 脚本, 或者给qmail-send发送一个TERM信号.

    然后重编译qmail, 使用命令:

        make setup check
    

    设置 ~alias/.qmail-log 来定义你想要记录的内容. 比如, 需要记录邮件 ID(Message-ID), 那么就这样编写这个文件内容:

        | awk '/^$/ { exit } /^[mM][eE][sS][sS][aA][gG][eE]-/ { print }'
    

    最后, 重新启动qmail.


    附录 F. 错误讯息

    qmail的错误讯息以及他们的含义.

    参见 RFC 1893 标准文档内括号内每个错误信息的说明部分.

    这个附录是不完整的.


    附录 G. 新手常见问题(Gotchas)

    这个"gotchas" 是qmail 新手经常遇到的问题.

    G.1. qmail 不能给超级用户发邮件.

    为了防止qmail-local以特权用户运行命令的可能性, qmail忽略所有UID是0的用户. 这个文档请看 qmail-getpw 的 man 手册页.

    不过这并不意味着qmail不能给root用户传送邮件, 只是邮件传送必须由一个非特权用户来执行. 典型情况, 为root用户创建一个系统别名文件 ~alias/.qmail-root.

    G.2. qmail不能给没有主目录的用户发邮件.

    这是另外一个安全特色, 也是一个新手的很好的练习机会. 看看 qmail-getpw的man 手册页面找答案吧.

    G.3. qmail 不能给名字里面含有大写字符的用户投递邮件.

    qmail 将整个"本地部分" -- 邮件地址中"@" 符号左面的所有部分转换为小写. man 手册页面里面没有提到和表示, 不过代码里面有相关表示. 实际上在qmail-getpw 的 man 手册页面里面有关于qmail忽略使用大写字符名字用户的文档.

    G.4. qmail处理扩展地址的时候, 用冒号(:)替换掉了点(.).

    这是qmail另一个安全特色. 是为了防止扩展地址里面".."和文件树冲突, 点(.)置换为冒号(:)之后, qmail就可以确定使用的每个用户的所有 .qmail 文件都位于他们的主目录下面. 这个问题存档于 dot-qmail 的 man 手册页里面.

    G.5. qmail 处理扩展地址的时候把大写字符转换成了小写字符.

    qmail转换本地地址的整个部分为小写字符. 文档参见 dot-qmail 的 man 手册页.

    G.6. qmail 不使用 /etc/hosts 文件

    qmail 从不使用 /etc/hosts 来确定一个主机名关联的IP地址. 如果你在控制文件内使用主机名而不是IP地址, qmail必须能够访问名字服务器.

    即使在没有名字服务器的情况下, 也可以运行qmail, 在control 文件内的主机由 IP 地址确定, IP地址两边必须加上方括号([ ]). 例如:

        [10.1.2.219]
    

    实际上, 方括号不总是必要的--不过用上它们无论如何是恰当的.

    G.7. qmail 不在日志记录 SMTP 的活动.

    由于很多原因, qmail 对于 SMTP 的连接, 拒信, 非法命令或者有效命令都不记录, tcpserver可以用来记录连接, recordio 可以用来记录整个 SMTP 对话. recordio 是 ucspi-tcp 的一部分. 这个过程存档在FAQ里面. 可以在这个地址 http://cr.yp.to/qmail/faq/servers.html#recordio 访问到它.

    G.8. qmail 不生成邮件延迟通知.

    如果在几个小时内 Sendmail 无法传递邮件, 代表性的是4个小时, 它就会发送一个邮件延迟通知给邮件原始发送者. 这个通知有点像反弹邮件, 不过还不表示邮件传送永久失败了.

    qmail 并不发送这样的警告. 未发送邮件在队列内等待发送直到超过 queuelifetime 规定的时间后还未能发送, 才会被反弹给邮件原始发送者.

    G.9. qmail 由于/var/qmail/queue/lock/trigger 文件丢失、权限设置错误或者错误的文件属性设置等原因变的很慢

    qmail-queue 和 qmail-send 使用一个称作 /var/qmail/queue/lock/trigger 的命名管道进行通讯. 如果这个管道陷入混乱, qmail-send 将在大约半个小时内无法注意到新邮件.

    最好的方式是正确设置qmail, 在源代码目录下使用"make check"命令检查. 如果不能这样作, 那么像下面这样确定一下:

    # ls -l /var/qmail/queue/lock/trigger
    prw--w--w-   1 qmails   qmail           0 Jul  5 21:25 /var/qmail/queue/lock/trigger
    

    特别注意那一行开头的"p"(表明这是一个命名管道), 状态(特别是任意用户可写标志位), 以及用户和用户组的归属.

    G.10. DNS 或者 IDENT 查询使 SMTP 变慢

    如果 qmail-smtpd 对连接的反应变慢, 原因可能使由于DNS反相查询或者 IDENT 查询. 如果你 使用 tcpserver 运行 qmail-smtpd, 删除 "-h", "-p", 和 "-r" 选项, 并增加 "-H", "-P", "-R", 和 "-l hostname" 选项.

    参看 http://cr.yp.to/ucspi-tcp/tcpserver.html 这里的 tcpserver 的文档查看这些选项的说明.

    G.11. 回车(Carriage Return)和换行(CRLF)不同

    qmail-inject 和其他本地注入机制比如 sendmail 不能正确接受DOS风格的回车/换行符. 不像 Sendmail, qmail 要求本地注入邮件使用 Unix 换行(只有 LF). 这和PHP 脚本遇到的问题一样.

    G.12. 日志回滚造成qmail-send 和 tcpserver 停止

    如果你使用第二节描述的受到监控的日志服务, 日志服务将会因为以下任何原因停止: 磁盘满, run 脚本打字错误, 日志目录配置错误, 等等. 而管道将被填满, 导致服务被阻塞, 或者被挂起. 解决这个问题(参看 故障处理)之后, 所有部分都会恢复正常.

    G.13. qmail-smtpd 不能使地址的本地部分生效

    假如 example.com 被列入control/rcpthosts 文件, 发给 anything@example.com 的邮件在SMTP会话期间将会被接受. 如果 anything 不是一个合法用户或者别名, qmail 将发送一个反弹邮件给信封上的发送者地址.

    一些单纯的转信测试假设如果邮件被接受, 那么一定会被传送, 这是错的. 如果某人宣称你的系统使开放转信的, 你要查看通过转信的邮件的副本--包括完整的邮件头, 特别是 Received 部分--比较一下这些部分和你的日志记录.

    要在qmail 中增加接收者认证, 请参考这小节: 在SMTP对话过程中拒绝无效接收者.

    G.14. 设置防火墙导致远程无法连接 SMTP/POP3/IMAP 服务器

    如果安装了 SMTP, POP3 和 IMAP 服务器, 你可以在本机或者本地网络的主机连接到这些服务器, 但是无法从远程服务器连接, 很有可能是防火墙的问题.

    第一个查看的地方是服务器本身. 举例, Red Hat Linux, 使用 iptables 在默认配置下是阻塞 SMTP 服务的. 其他包过滤机制比如 ipchains 也会和这个问题有关系.

    也有可能是你的因特网服务提供商 (ISP) 阻塞了某些端口来防止垃圾邮件骚扰或者强制执行他们的服务条款(Terms of Service, TOS). 确认不是包过滤的原因以及你没有违反ISP的服务条款(TOS)之后, 可以联系你的ISP的技术支持解决问题.

    G.15. 如果USER 和 LOGNAME 没有设置的话, qmail-inject 将设置邮件发送方字段(From)为匿名(anonymous)

    如果通过 qmail-inject 发送邮件, 并且邮件不包括 From 字段, qmail-inject 将查找环境变量来得知是那个用户发送的邮件. 查找变量的顺序为: QMAILUSER, MAILUSER, USER, 然后 LOGNAME.

    普通用户登录期间通常要设置USER和LOGNAME变量, 不过某些批处理任务, 比如以 cron 执行的任务, 将不会设置这两个环境变量.

    为了使你的 cron 任务发送的邮件有一个合法的 From 字段, 请在发信之前设置一个环境变量就可以了.

    G.16. 停止qmail-send进程的时候, 它不总是立即退出.

    在还有邮件传送的情况下, 向qmail-send发送 KILL 信号是不能使qmail-send立刻退出的. qmail-send退出前将等待所有的qmail-local和qmail-remote进程完成任务, 这样qmail-send才能记录下传送结果. 由于这个原因, "qmailctl restart" 或者 "qmailctl stop" 这样的命令可能在qmail-send依然在运行的情况下, 报告qmail-send进程已经被停止了. 所以, 请使用"qmailctl stat"来检查"stop"和"restart"命令的实际执行结果.

    还要注意, qmail-send 退出前将遍历邮件队列, 所以当存在非常大的邮件队列情况下停止qmail-send 会有一个非常明显的时间延迟.

    G.17. 不能通过把邮件传送到/dev/null 将邮件丢弃.

    假设这样写一个传送指令:

    /dev/null

    因为qmail 认为/dev/null 是一个mbox 格式的邮箱, 而/dev/null 是个特殊文件, 所以这样作将导致qmail 无法传送邮件.

    最好的丢弃邮件的方式是建立一个.qmail 文件, 这个文件内可以包含无效的指令, 但一定要非空(.qmail 的空文件将被作为按照defaultdelivery 内缺省指令或者qmail-start 命令行指令进行传送) , 在这个文件里面只放上注释语句就可以作到了.

    举例如下, 一个仅包含注释的.qmail 文件:

    #

    或者:

    # throw messages away undelivered

    (注释语句可以随便些上点什么. 译者注)
    这样的.qmail 文件可以丢弃邮件, 而不予传送.

    G.18. qmail-send 正在运行过程中修改邮件队列是危险的

    在qmail-send 运行过程中, 如果你不是非常确切的知道你正在作什么, 修改/var/qmail/queue 下面的文件或目录是非常危险的, 可能会导致邮件队列崩溃, 举例来说, 邮件将处于未定义的状态, 日志文件中出现奇异错误信息, 重复传送邮件, 出现假的反弹邮件等等错误都可能发生. 一旦发生这些情况, 你必须找到并运行一个队列检查程序(有两个可以在 qmail.org 找到)或者创建一个新的空邮件队列.

    如果你要修改邮件队列, 首先停止qmail, 仔细处理队列, 然后重启qmail. 注意, qmail-send 停止也会造成这样的队列崩溃, 所以你应该知道如果你遇到这样的情况应该怎么作.



    附录 H. 关于本文 Life with qmail 的常见话题

    H.1. 这个 Life with qmail 的版本是多少?

    这是LWQ 2006年01月02日的英文版本(翻译).

    H.2. 谁拥有 Life with qmail?

    版权所有1999-2006, David E. Sill

    个人主页:http://Web.InfoAve.Net/~dsill/dave/

    H.3. Life with qmail 的版权信息? How is Life with qmail licensed?

    Life with qmail 使用OpenContent 1.0 版本许可证, 参见 http://www.opencontent.org/opl.shtml查看完整的版权许可证. 基本上, 你可以拷贝, 再发布, 或者对于修改版本可以对Life with qmail 进行修改, 如果重发布, 也需要在 OpenContent 的版权许可证规定范围内.

    H.4. 我怎么取得新版 LWQ 的发布通知?

    发送邮件到 lwq-announce-subscribe@sws1.ctd.ornl.gov 加入 lwq-announce 邮件列表.

    H.5. 在哪里可以为 LWQ 投稿, 捐助以及讨论它?

    发送邮件到 lwq-subscribe@sws1.ctd.ornl.gov 加入lwq邮件列表.

    H.6. Life with qmail 被翻译成其他语言了吗?

    大概LWQ已经被翻译成了几种语言. 参见 http://lifewithqmail.org/trans.html 查看更多关于LWQ的翻译消息.

    H.7. Life with qmail 有没有 PostScript, PDF, plain text, 或者其他任何除了HTML的格式?

    有的, 其他格式的可以在这里 http://lifewithqmail.org/ 取得.

    H.8. 我按照 Life with qmail 说的作了, 可是我的系统崩溃了, 或者弄坏了我的硬盘, 或者毁了我的爱情, 或者弄死了我的狗, 等等问题, 我该怎么办? (这属于老外的幽默啦. ^_^, 译者注)

    我很抱歉, 真的很抱歉. 可是使用 Life with qmail 是没有任何担保的. 请参考上面提到的 OpenContent 版权许可证. 我不是为了赚钱才写Life with qmail 的, 我只是想为 qmail 社区作出一些有益的贡献.

    其实, Life with qmail 并不是一个FAQ, 反而我希望这是个 NAQ (Never Asked Question).

    H.9. 我怎么为 LWQ捐赠和投稿?

    请把对 LWQ 的修正意见, 建议以及抱怨等等发送到 lwq@sill.org.

    如果你想要作更大的投稿, 比如, 比如文章的新的小部分或者附录, 那太棒了! 首先请和我协商以便确认哪些我想要在LWQ里面添加的内容还有就是核实是否已经有人在作同样的工作了.

    另外一个支持LWQ 的方式是去我的书店买东西, 这是Amazon.com 的联盟书店, 使用这个地址访问: http://www.amazon.com/exec/obidos/redirect-home/davesill.

    感谢你的衷心支持! Thanks for your support!

    H.10. 这个版本的LWQ有那些变化呢?

    Take One!