Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Tree: 30b6c89eb0
Fetching contributors…

Cannot retrieve contributors at this time

1989 lines (1867 sloc) 58.376 kB
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
<!ENTITY author "<ulink url='mailto:johnson.AT.worldhello.net'>Johnson</ulink>">
<!ENTITY orgname "<ulink url='http://www.worldhello.net'>worldhello.net</ulink>">
<!ENTITY % vers SYSTEM "version.xml">
%vers;
]>
<article id="index">
<articleinfo>
<title>知识管理</title>
<subtitle>Email Howto</subtitle>
<author><firstname>鑫</firstname><surname>蒋</surname></author>
<affiliation>
<orgname>&orgname;</orgname>
<address><email>johnson.AT.worldhello.net</email></address>
</affiliation>
<revhistory>
<!--revision>
<revnumber>$Revision$</revnumber>
<date>$Date$</date>
<authorinitials>$Author$</authorinitials>
<revremark>...</revremark>
</revision-->
<revision>
<revnumber>0.2.1</revnumber>
<date>2003/03/05</date>
<authorinitials>jiangxin</authorinitials>
<revremark>sendmail 8.12.7 发现安全漏洞</revremark>
</revision>
<revision>
<revnumber>0.2</revnumber>
<date>2003/2/22</date>
<authorinitials>jiangxin</authorinitials>
<revremark>补充 <link linkend="procmail">procmail</link></revremark>
</revision>
<revision>
<revnumber>0.1</revnumber>
<date>2003/2/11</date>
<authorinitials>jiangxin</authorinitials>
<revremark>东拼西凑出一个个人 Sendmail 配置心得</revremark>
</revision>
</revhistory>
<abstract>
<para>
工作需要,不得不配置一个自己的 Mail Server。发现 sendmail 并不想以前感觉那样难配置。从网上东拼西凑出一个个人心得,有机会就不断完善。对本文档有任何补充或建议,欢迎联系作者 &author;
</para>
<para>
(编译自版本: &doc.revision;,最后更新时间: &doc.lastchange;
</para>
</abstract>
</articleinfo>
<sect1 id="sendmail"><title>Sendmail</title>
<para>
可以通过命令 <command>telnet &lt;email_server&gt; 25</command> , 或者命令 <command>sendmail -dt -d0*</command> , 来查看sendmail版本号。如果需要配置 smtp over ssl,则最好使用 8.12版本以上的 sendmail。
</para>
<para>
由于 Sendmail 有着长期的安全漏洞历史,更需要着重注意 sendmail 的版本更新。
</para>
<warning>
<para>
Recent Sendmail Vulnerabilities:
</para>
<orderedlist>
<listitem>
<para>
2003.3.3, Sendmail 检查接收邮件标题字段的代码中,发现了缓冲区溢出的安全漏洞。
</para>
<para>
美国CERT/CC、美国Internet Security Systems(ISS)以及美国Sendmail.org等公司
于美国当地时间3月3日发出警告,在具有代表性的邮件服务器软件“Sendmail”中发现
了严重的安全漏洞。影响版本涉及 5.79 至 8.12.7。请立即升级至 8.12.8。
</para>
</listitem>
</orderedlist>
</warning>
<para>
Sendmail 作为 Linux, BSD 和其它 Unix 平台的“标配”,被广泛使用。再加上众多的相关软件支持,Sendmail 配置应该算得上是系统管理员的基本技能。Sendmail 主要的配置文件如下:
</para>
<orderedlist>
<listitem>
<para>
/etc/sendmail.cf
</para>
<para>
Sendmail 核心配置文件
</para>
</listitem>
<listitem>
<para>
/etc/aliases
</para>
<para>
邮件别名文件
</para>
</listitem>
<listitem>
<para>
/etc/mail/relay-domains
</para>
<para>
设定可RELAY的域名
</para>
</listitem>
<listitem>
<para>
/etc/mail/access
</para>
<para>
设定处理来信的方式:RELAY等
</para>
</listitem>
</orderedlist>
<sect2><title>M4 和 sendmail.cf</title>
<para>
Sendmail的配置文件 sendmail.cf 算得上“臭名昭著”,看看这个文件一定会让你头大,几乎没有人从头来写这个文件。关于 sendmail.cf 的详细内容,参见:<ulink url="http://www.sendmail.org/~ca/email/doc8.12/op-sh-5.html">Sendmail Installation and Operation Guide --- THE WHOLE SCOOP ON THE CONFIGURATION FILE</ulink>。
</para>
<para>
通过使用 m4 宏处理命令,由宏文件 sendmail.mc 来生成复杂的配置文件 sendmail.cf,一切变得简单多了。
</para>
<para>
/etc/mail/sendmail.mc 文件即是原始宏文件。生成配置文件 sendmail.cf 的命令为:
</para>
<screen>
<![CDATA[
$ m4 sendmail.mc > sendmail.cf
]]>
</screen>
<para>
默认的配置文件仅仅能在本机发送邮件,如果需要更强的功能,需要修改宏文件:<filename>sendmail.mc</filename>
</para>
<para>
缺省的<filename>sendmail.mc</filename>文件:
</para>
<screen>
divert(-1) <co id="co.divert"/>
dnl This is the sendmail macro config file. If you make changes to this file,
dnl you need the sendmail-cf rpm installed and then have to generate a
dnl new /etc/sendmail.cf by running the following command:
dnl
dnl m4 /etc/mail/sendmail.mc > /etc/sendmail.cf
dnl
include(`/usr/share/sendmail-cf/m4/cf.m4')
VERSIONID(`linux setup for Red Hat Linux')dnl <co id="co.versionid"/>
OSTYPE(`linux') <co id="co.ostype"/>
dnl Uncomment and edit the following line if your mail needs to be sent out
dnl through an external mail server:
dnl define(`SMART_HOST',`smtp.your.provider') <co id="co.dnl1"/>
define(`confDEF_USER_ID',``8:12'')dnl <co id="co.dnl2"/>
undefine(`UUCP_RELAY')dnl
undefine(`BITNET_RELAY')dnl
define(`confAUTO_REBUILD')dnl
define(`confTO_CONNECT', `1m')dnl
define(`confTRY_NULL_MX_LIST',true)dnl
define(`confDONT_PROBE_INTERFACES',true)dnl
define(`PROCMAIL_MAILER_PATH',`/usr/bin/procmail')dnl
define(`ALIAS_FILE', `/etc/aliases')dnl <co id="co.mc.aliases"/>
dnl define(`STATUS_FILE', `/etc/mail/statistics')dnl
define(`UUCP_MAILER_MAX', `2000000')dnl
define(`confUSERDB_SPEC', `/etc/mail/userdb.db')dnl
define(`confPRIVACY_FLAGS', `authwarnings,novrfy,noexpn,restrictqrun')dnl
define(`confAUTH_OPTIONS', `A')dnl
dnl TRUST_AUTH_MECH(`DIGEST-MD5 CRAM-MD5 LOGIN PLAIN')dnl
dnl define(`confAUTH_MECHANISMS', `DIGEST-MD5 CRAM-MD5 LOGIN PLAIN')dnl
dnl define(`confTO_QUEUEWARN', `4h')dnl
dnl define(`confTO_QUEUERETURN', `5d')dnl
dnl define(`confQUEUE_LA', `12')dnl
dnl define(`confREFUSE_LA', `18')dnl
dnl FEATURE(delay_checks)dnl
FEATURE(`no_default_msa',`dnl')dnl
FEATURE(`smrsh',`/usr/sbin/smrsh')dnl <co id="co.feature.smrsh"/>
FEATURE(`mailertable',`hash -o /etc/mail/mailertable.db')dnl
FEATURE(`virtusertable',`hash -o /etc/mail/virtusertable.db')dnl <co id="co.feature.virtuser"/>
FEATURE(redirect)dnl
FEATURE(always_add_domain)dnl <co id="co.feature.alwaysadddom"/>
FEATURE(use_cw_file)dnl <co id="co.feature.usecwfile"/>
FEATURE(use_ct_file)dnl <co id="co.feature.usectfile"/>
dnl The '-t' option will retry delivery if e.g. the user runs over his quota.
FEATURE(local_procmail,`',`procmail -t -Y -a $h -d $u')dnl
FEATURE(`access_db',`hash -o /etc/mail/access.db')dnl
FEATURE(`blacklist_recipients')dnl
EXPOSED_USER(`root')dnl
dnl This changes sendmail to only listen on the loopback device 127.0.0.1
dnl and not on any other network devices. Comment this out if you want
dnl to accept email over the network.
DAEMON_OPTIONS(`Port=smtp,Addr=127.0.0.1, Name=MTA')
dnl NOTE: binding both IPv4 and IPv6 daemon to the same port requires
dnl a kernel patch
dnl DAEMON_OPTIONS(`port=smtp,Addr=::1, Name=MTA-v6, Family=inet6')
dnl We strongly recommend to comment this one out if you want to protect
dnl yourself from spam. However, the laptop and users on computers that do
dnl not have 24x7 DNS do need this.
FEATURE(`accept_unresolvable_domains')dnl <co id="co.unresolv.domain"/>
dnl FEATURE(`relay_based_on_MX')dnl
MAILER(smtp)dnl
MAILER(procmail)dnl
Cwlocalhost.localdomain
</screen>
<calloutlist>
<callout arearefs="co.divert">
<para>
divert(-1),从这行以下到divert(0)之间会被忽略,不会加到产生出来的*.cf文件中,通常放一些版权信息之类。
</para>
</callout>
<callout arearefs="co.versionid">
<para>
放入一些版本信息
</para>
</callout>
<callout arearefs="co.ostype">
<para>
根据平台设置,产生相关环境设定
</para>
</callout>
<callout arearefs="co.dnl1">
<para>
行首的 dnl 相当于注释
</para>
</callout>
<callout arearefs="co.dnl2">
<para>
行尾的 dnl 用于去掉行尾的空格、回车换行,以避免生成的文件包含过多的空行。
</para>
</callout>
<callout arearefs="co.mc.aliases">
<para>
设置别名文件。亦可设置多个别名文件,如:define(`ALIAS_FILE', `/etc/aliases,/usr/local/majordomo/majordomo.aliases')dnl
</para>
</callout>
<callout arearefs="co.feature.smrsh">
<para>
smrsh 即 sendmail restricted shell。简而言之smrsh限制了攻击者可以执行的程序集。当它与sendmail程序一起使用的时候,smrsh有效的将sendmail可以执行的程序的范围限制在smrsh目录之下。
</para>
</callout>
<callout arearefs="co.feature.virtuser">
<para>
允许在同一个主机上使用多个虚拟域
</para>
</callout>
<callout arearefs="co.feature.alwaysadddom">
<para>
即使是本地传送的信件,也会加上domain-name。
</para>
</callout>
<callout arearefs="co.feature.usecwfile">
<para>
会参考 /etc/mail/local-host-names 来决定哪些domain-name是local-host。
</para>
</callout>
<callout arearefs="co.feature.usectfile">
<para>
会参考 /etc/mail/trust-users 文件,来决定哪些用户可以以其它身份发信而不产生警告。Majordomo 用户需要属于 trust-users。
</para>
</callout>
<callout arearefs="co.unresolv.domain">
<para>
发件人的地址如果不能解析,也能发送成功。避免由于域名解析受限制而拒收邮件。
</para>
</callout>
</calloutlist>
<para>
修改该配置如下:
</para>
<screen>
dnl Dmworldhello.net
dnl Dwmail
dnl define(`confDOMAIN_NAME', `$w.$m')dnl <co id="co.domainname"/>
... ...
FEATURE(`domaintable',`hash -o /etc/mail/domaintable') <co id="co.domaintable"/>
... ...
FEATURE(`genericstable',`hash -o /etc/mail/genericstable') <co id="co.genericstable"/>
... ...
GENERICS_DOMAIN_FILE(`/etc/mail/genericsdomain') <co id="co.genericsdomain"/>
... ...
<emphasis>dnl</emphasis> DAEMON_OPTIONS(`Port=smtp,Addr=127.0.0.1, Name=MTA') <co id="co.pubservice"/>
... ...
FEATURE(`accept_unqualified_senders')dnl <co id="co.unqual.sender"/>
... ...
define(confMAX_HOP,30) <co id="co.mc.maxhop"/>
... ...
Cwlocalhost.localdomain <emphasis>your_real_domain</emphasis> <co id="co.cw"/>
... ...
</screen>
<calloutlist>
<callout arearefs="co.domainname">
<para>
如果sendmail不能正确判断本机域名,使用由变量 $w 和 $m 确定的域名。
</para>
</callout>
<callout arearefs="co.domaintable">
<para>
添加配置,提供地址重写方式
</para>
</callout>
<callout arearefs="co.genericstable">
<para>
添加配置,提供地址重写方式
</para>
</callout>
<callout arearefs="co.genericsdomain">
<para>
添加配置,提供地址重写方式
</para>
</callout>
<callout arearefs="co.pubservice">
<para>
注释掉本语句的目的是侦听所有网卡,为整个网络提供服务
</para>
</callout>
<callout arearefs="co.unqual.sender">
<para>
允许未加域名的发件人发送邮件,默认禁止。
</para>
</callout>
<callout arearefs="co.mc.maxhop">
<para>
设置转发的地址不能超过30个。
</para>
</callout>
<callout arearefs="co.cw">
<para>
定义类$w,在此处或者外部文件中定义。用于设置服务器提供服务的域名,即本地主机名。
</para>
<para>
外部文件通常为 sendmail.cw,新版本为 local-host-names。但也有可能是其他名称,用如下命令查看:
</para>
<screen>
<![CDATA[
$ grep "^Fw" sendmail.cf
Fw/etc/mail/local-host-names
]]>
</screen>
</callout>
</calloutlist>
</sect2>
<sect2><title>mail relay 规则详解
<footnote id="fn.relay"><para>来源:<ulink url="http://www.fanqiang.com/a6/b3/20010725/0800001019.html">Sendmail relay规则及配置文件用法汇总</ulink></para></footnote>
</title>
<para>
在默认情况下,也就是安装完系统(Sendmail服务器)不做任何设置的情况下,则只能在本机上收发邮件,网络上(局域网或Internet)的任何其它主机不能向该SMTP服务器发送邮件。这往往并不能满足需要。
</para>
<sect3><title>配置允许本地用户RELAY</title>
<para>
对于内部的邮件服务器或者相对简单的网络环境,允许发送邮件的用户的IP地址相对固定或者完全是内部IP地址,则配置非常简单。
</para>
<itemizedlist>
<listitem>
<para>
允许其他机器使用邮件服务器发送邮件
</para>
<para>
若希望能实现发送,则需满足下面的任何一个条件即可(不需要同时满足):1. <emphasis>发送者身份属于“本地或者被允许的发送者”</emphasis>;2. <emphasis>接收者身份属于“本地或者被允许的接收者”</emphasis>。
</para>
</listitem>
<listitem>
<para>
/etc/mail/relay-domains
</para>
<para>
在配置文件<filename>/etc/sendmail.cf</filename>中,指定了该文件的路径:
</para>
<screen>
# Hosts for which relaying is permitted ($=R)
FR-o /etc/mail/relay-domains
</screen>
<para>
<filename>/etc/mail/relay-domains</filename>示例:
</para>
<screen>
localhost.localdomain
localhost
127.0.0.1
10.0.0
</screen>
<para>
即在列表中出现的主机,可以使用本邮件服务器发送邮件。
</para>
</listitem>
<listitem>
<para>
/etc/mail/access
</para>
<para>
除了使用文件<filename>relay-domains</filename>外,还可以使用<filename>access</filename>文件确定允许relay的主机,在配置文件<filename>/etc/sendmail.cf</filename>中,指定了该文件的路径:
</para>
<screen>
# Access list database (for spam stomping)
Kaccess hash -o /etc/mail/access.db
</screen>
<para>
<filename>/etc/mail/access</filename>示例:
</para>
<screen>
localhost.localdomain RELAY
localhost RELAY
127.0.0.1 RELAY
10.0.0 RELAY
</screen>
<para>
access文件和relay-domains格式的区别在于access文件中,允许relay的主机名添加<emphasis>RELAY</emphasis>关键字。
</para>
<para>
其它的关键字还有:
</para>
<itemizedlist>
<listitem>
<para>
OK
</para>
<para>
当有别的规则阻挡,仍旧允许
</para>
</listitem>
<listitem>
<para>
RELAY
</para>
<para>
允许转寄
</para>
</listitem>
<listitem>
<para>
REJECT
</para>
<para>
拒绝这个来源的信件
</para>
</listitem>
<listitem>
<para>
DISCARD
</para>
<para>
丢弃。这种情况下,邮件看上去是正常投递了,但是由于没有人接 受,邮件会自动地“消失”在网络中。
</para>
</listitem>
<listitem>
<para>
错误代码+任何其他字符串
</para>
<para>
将向发信者返回这个字符串作为出错信息。错误代码是R FC 822定义的标准出错代码。如: 550 We don like a spammer!
</para>
</listitem>
</itemizedlist>
</listitem>
<listitem>
<para>
属于本地/被允许的发送者,则RELAY
</para>
<para>
如果在<filename>relay-domains</filename>或者<filename>access</filename>文件中列出的是域名,则对发送者的IP地址先查找<filename>/etc/hosts</filename>文件(一般是如此,如果文件<filename>/etc/host.conf</filename>采用默认配置的话),如果没有,再查找DNS。查找DNS的过程是:先做IP地址的反向DNS查找,如果能够反向查找出来,且查找出来的主机的域部分属于上面两个文件中列出的域名,再对该主机名做正向DNS查找,若查找出的IP地址(主机的A记录)与发送者IP地址相同,则允许relay邮件,这表明发送者属于被允许的发送者。
</para>
<para>
如果正反向解析不一致,则会在/var/log/maillog中记录一行警告信息说"may be forged"(可能被伪造的)。如果收信人也不在access文件列表中,则拒发邮件。
</para>
</listitem>
<listitem>
<para>
本地或者被允许的接收者,则RELAY
</para>
<para>
相对于发送者,这个就非常简单了。只要接收者的email地址的域部分被列在/etc/mail/relay-domains或者/etc/mail/access 文件中,邮件被允许接收。
</para>
</listitem>
<listitem>
<para>
文件<anchor id="a.local-host-names"/><filename>/etc/mail/local-host-names</filename>,服务的域名亦可作为本地接收者的判断依据。
</para>
</listitem>
</itemizedlist>
</sect3>
<sect3><title>口令验证下的 open relay
<footnote id="fn.sasl"><para>来源:<ulink url="http://linux.softhouse.com.cn/linux/knowledge/tech/6236.html">Redhat 7.1下的Sendmail SASL认证的实现</ulink></para></footnote>
</title>
<para>
对于移动用户的情况,往往网络拓扑复杂,设置<filename>/etc/mail/relay-domains</filename>,或者<filename>/etc/mail/access</filename>就不够了。
</para>
<para>
当前的解决办法有:
</para>
<orderedlist>
<listitem>
<para>
公司设置自己的拨入服务器,仅仅公司员工可以用自己的用户名和密码拨入后发送邮件.
</para>
</listitem>
<listitem>
<para>
SMTP-After-POP3方法, 修改POP3程序,拨到ISP后先收一次自己的信,POP3检测到收信者IP地址后再动态地加这个IP地址到relay-domains或者access文件中,允许relay默认半个小时.
</para>
</listitem>
<listitem>
<para>
sendmail 8.10加入了SMTP用户认证功能,发送邮件时提示输入用户名和密码后允许relay.
</para>
</listitem>
</orderedlist>
<para>
显然第三种方法是最理想的。
</para>
<para>
首先检查是否支持 SASL 认证:
</para>
<screen>
#/usr/sbin/sendmail -d0.1 -bv root |grep SASL
NAMED_BIND NETINET NETINET6 NETUNIX NEWDB NIS QUEUE <emphasis>SASL</emphasis> SCANF
</screen>
<para>
如果出现了 SASL,则sendmail编译时编译了SASL模块,否则需要重新编译 SASL,
</para>
<para>
设置口令验证,需要修改宏文件 sendmail.mc,如下:
</para>
<screen>
define(QUEUE_DIR,`/var/spool/mqueue/q*') <co id="co.auth.queue"/>
TRUST_AUTH_MECH(`DIGEST-MD5 CRAM-MD5 LOGIN PLAIN')dnl <co id="co.auth.trust"/>
define(`confAUTH_MECHANISMS', `DIGEST-MD5 CRAM-MD5 LOGIN PLAIN')dnl <co id="co.auth.mech"/>
dnl define(`confDEF_AUTH_INFO', `/etc/mail/auth/auth-info') <co id="co.auth.info"/>
dnl FEATURE(`no_default_msa')
dnl DAEMON_OPTIONS(`Port=smtp,Name=MTA')dnl <co id="co.auth.smtp"/>
DAEMON_OPTIONS(`Port=25,Name=MSA,M=Ea')dnl <co id="co.auth.msa"/>
</screen>
<calloutlist>
<callout arearefs="co.auth.queue">
<para>
和认证无关,但是启动了多个邮件队列,希望得到更好的队列处理和性能改进。
</para>
</callout>
<callout arearefs="co.auth.trust">
<para>
"TRUST_AUTH_MECH"的作用是使sendmail不管access文件中如何设置,都能 relay 那些通过LOGIN,PLAIN或DIGEST-MD5方式验证的邮件。
</para>
</callout>
<callout arearefs="co.auth.mech">
<para>
"confAUTH_MECHANISMS"的作用是确定系统的认证方式。
</para>
</callout>
<callout arearefs="co.auth.info">
<para>
"confDEF_AUTH_INFO"的作用是当你的计算机作为客户机时,向另外一台有smtp认证功能的主机进行认证,用户和密码存放在auth-info文件中,在这个例子中并不需要这个功能,所以注释掉了。
</para>
</callout>
<callout arearefs="co.auth.smtp">
<para>
设置非口令验证的SMTP端口
</para>
</callout>
<callout arearefs="co.auth.msa">
<para>
注释本行,则25端口可以同时进行口令验证和非口令验证,否则只能有完成口令验证,方可发送邮件。
</para>
</callout>
</calloutlist>
<para>
测试:输入如下命令
</para>
<screen>
$ <command>telnet localhost 25</command>
Connected to localhost.
Escape character is '^]'.
220 localhost.localdomain ESMTP Sendmail 8.11.6/8.11.6; Wed, 12 Feb 2003 16:38:34 +0800
<command>ehlo localhost</command>
250-xxxxxxxxxxxxxxxxxxxxxxxxx, pleased to meet you
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-SIZE
250-DSN
250-ONEX
250-ETRN
250-XUSR
250-AUTH LOGIN PLAIN <co id="co.auth.output"/>
250 HELP
<command>auth login</command>
</screen>
<calloutlist>
<callout arearefs="co.auth.output">
<para>
看到本行,则支持口令验证。
</para>
<para>
Outlook Express使用LOGIN认证,Netscape Mail使用PLAIN认证,Foxmail 3.11 一般使用LOGIN认证
</para>
</callout>
</calloutlist>
<para>
文件:<filename>/usr/lib/sasl/Sendmail.conf</filename>
</para>
<screen>
pwcheck_method:pam
</screen>
<para>
既然Redhat Linux普遍使用PAM,我们就用PAM 认证。为了支持加密验证,则需要使用SASLDB方式的认证。
</para>
<para>
文件:<filename>/etc/pam.d/smtp</filename>
</para>
</sect3>
<sect3><title>提高安全性:SMTP over SSL</title>
<para>
参见<link linkend="smtpoverssl">从头安装 sendmail</link>
</para>
</sect3>
</sect2>
<sect2><title>别名 aliases 和 .forward 文件</title>
<sect3><title>/etc/mail/aliases</title>
<para>
一个重要的邮件重写规则。root 用户可以通过对该文件的配置,建立邮件组、重定向本地用户等等。别名文件会循环检查,直到影射到的邮件地址不在本机接收之列(参见配置文件<link linkend="a.local-host-names"><filename>/etc/mail/local-host-names</filename></link>)。
</para>
<para>
示例:
</para>
<screen>
user1: me@otherdomain.com,user2,user3 <co id="co.alias.mult"/>
user2: user2@otherdomain.com
alises: :include:/etc/mail/filealiases <co id="co.alias.file"/>
list-request: |/usr/local/bin/auto_reply <co id="co.alias.pipe"/>
nobody: /dev/null <co id="co.alias.dev"/>
</screen>
<calloutlist>
<callout arearefs="co.alias.mult">
<para>
逗号分隔多个地址。
</para>
</callout>
<callout arearefs="co.alias.file">
<para>
对于经常变化的邮件列表,可以采用外部文件方式。一个邮件一行。
</para>
</callout>
<callout arearefs="co.alias.pipe">
<para>
管道
</para>
</callout>
<callout arearefs="co.alias.dev">
<para>
设备文件
</para>
</callout>
</calloutlist>
<para>
更改别名文件后使用newaliases或sendmail -bi建立邮件别名文件的二进制数据文件。
</para>
<para>
特殊的别名
</para>
<orderedlist>
<listitem>
<para>
owner-aliasname : address
</para>
<para>
设置该别名后,退信将退回到owner-xxx 别名下。
</para>
</listitem>
</orderedlist>
</sect3>
<sect3><title>~/.forward</title>
<para>
别名文件一般由root用户管理,而普通用户则可以通过用户主目录下的 .forward 文件,实现邮件别名、转发等一系列处理功能。
</para>
<para>
当一个别名解析成一个本地用户地址后,sendmail 察看该用户主目录是否存在 .forward 文件,如果存在,读取该文件中的内容,决定进一步的处理方式。
</para>
<para>
.forward 文件可以通过三种不同的处理方式,对接受的邮件进行处理:定义存储邮件的邮箱文件名(以字符“/”开始的文件名)、进行转发的目的地址、管道(以字符“|”开始,对电子邮件进行处理的外部应用程序)。可以使用第三种方法“管道”,来启动 <link linkend="procmail">Procmail</link>。 该文件格式类似 aliases 文件,但是省略了冒号之前的部分,毕竟.forward只针对一个特定的本地用户么。
</para>
<para>
例如:用户 johnson,需要将其邮件拷贝一份给 jiangxin,再回复给发信人说本人正在度假(通过 vocation 程序实现),但仍然保留给自己一份。如果 .forward 内容如下,则会造成死循环:
</para>
<screen>
jiangxin
"|/usr/ucb/vacation johnson"
johnson
</screen>
<para>
解决办法是在 johnson 前面加上斜线 \,则再次发送给 johnson 时,则不会再次处理 .forward 文件。修改后如下:
</para>
<screen>
jiangxin,"|/usr/ucb/vacation johnson",\johnson
</screen>
</sect3>
</sect2>
<sect2><title>用 virtusertable 管理虚拟域</title>
<para>
如同Apache一样,sendmail也允许使用虚拟主机功能,这是通过FEATURE(virtusertable)功能实现的,而虚拟主机的文件缺省是/etc/mail/virtusertable。这个文件的形式类似于aliases文件,即:左地址 右地址 ,中间用Tab键分开。<emphasis>还需要注意的是,虚拟域(左地址的域名),应该属于本机接收之列</emphasis>。
</para>
<screen>
joe@yourdomain.com jschmoe <co id="co.virt.local"/>
bogus@yourdomain.com error:nouser No such user here <co id="co.virt.error"/>
@testdomain.com test@mydomain.com <co id="co.virt.domain"/>
@yourdomain.com %1@othercompany.com <co id="co.virt.param"/>
</screen>
<calloutlist>
<callout arearefs="co.virt.local">
<para>
这样一行意味着本来应该发送给 joe@yourdomain.com 的邮件现在要发送给本机的 用户 jschmoe。
</para>
</callout>
<callout arearefs="co.virt.error">
<para>
发向 bogus@yourdomain.com 的邮件,返回错误信息。
</para>
</callout>
<callout arearefs="co.virt.domain">
<para>
意味着所有发往 xxx@testdomain 的邮件都会被发送到 test@mydomain.com。
</para>
</callout>
<callout arearefs="co.virt.param">
<para>
代表参数转义,例如 user1@yourdomain.com 的邮件被发送到user1@othercompany.com。
</para>
</callout>
</calloutlist>
<para>
aliases 文件同样可以将本地用户,映射到其它地址,那么和 virtusertable 的优先级如何?<footnoteref linkend='fn.relay'/>
</para>
<orderedlist>
<listitem>
<para>
当接收者邮件地址的域部分在 /etc/mail/local-host-names 中又在/etc/mail/virtusertable中时,优先检查virtusertable文件,应用该文件中的定义规则.
</para>
</listitem>
<listitem>
<para>
要应用virtusertable规则,则接收者邮件地址的域部分必须在 /etc/mail/local-host-names 文件中存在
</para>
</listitem>
<listitem>
<para>
若接收者邮件地址的域部分在 /etc/mail/local-host-names 文件中但不在 virtusertable 文件中有相应的定义则先只应用 aliases 中的定义去扩展别名,一旦扩展出的别名接收者邮件的域部分在 virtusertable 中有定义行时则决不再别名下去,马上运行virtusertable中的定义规则。
</para>
</listitem>
</orderedlist>
</sect2>
<sect2><title>其它配置文件</title>
<para>
优先级:domaintable &gt; virtusertable &gt; local-host-names &gt; mailertable &gt; DNS MX记录
</para>
<para>
</para>
<sect3><title>/etc/mail/domaintable</title>
<orderedlist>
<listitem>
<para>
无论什么时候,domaintable都是优先检查,且没有任何附加条件,无条件检查,与/etc/mail/local-host-names中是否有某域名无关。
</para>
<para>
而 virtusertable 要求域名属于本机接收之列。
</para>
</listitem>
<listitem>
<para>
一般地用来做域名更换,假如你的公司@abc.com可能被员工误打为abd.com,则放入下面的行到 /etc/mail/domaintable
</para>
<screen>
abd.com abc.com
</screen>
</listitem>
<listitem>
<para>
使用 domaintable ,发件人和收件人的地址全部被替换。
</para>
<para>
而使用 virtusertable 仅仅将邮件的信封地址替换、信头地址不变,而且也仅仅替换收件人地址。
</para>
</listitem>
</orderedlist>
</sect3>
<sect3><title>genericstable和genericsdomain</title>
<para>
若文件/etc/mail/genericstable 的内容为:
</para>
<screen>
jwu jwu@sources.com
</screen>
<para>
若文件/etc/mail/genericsdomain的内容为:
</para>
<screen>
test.com
</screen>
<para>
如果该SMTP服务器从互联网上收到一封发送者邮件地址为jwu@test.com的信,则发送者邮件地址被重写为jwu@sources.com,且message envelope中的return address也是jwu@sources.com
</para>
</sect3>
<sect3><title>/etc/mail/mailertable</title>
<para>
跨越DNS的MX的记录,优先于MX记录,可以与MX记录指定的主机设定不同. mailertable的运用不需要接收者邮件地址的域部分在/etc/mail/local-host-names中存在.
</para>
<screen>
sh.abc.com relay:[192.168.11.1]
bj.abc.com smtp:mail.bj.abc.com
</screen>
<para>
则发送给jwu@sh.abc.com,发送给192.168.11.1, 并且邮件头显示:“received by shmail[192.168.11.] for jwu@sh.abc.com”
</para>
<para>
发送给 user@bj.abc.com,通过服务器 mail.bj.abc.com 转发。
</para>
</sect3>
</sect2>
<sect2><title>地址伪装</title>
<para>
我遇到的一个需要地址伪装的例子是,一个应用软件需要频繁在用户之间发送邮件,公司的邮件服务器要求身份认证,而该软件不支持,于是配置了一个内部邮件服务器作为该软件要求的SMTP服务器。但是问题又来了,如果发件人地址属于公司的邮件地址,则邮件回被退回,仍旧报告发件人需要身份验证。于是想到了将发件人地址伪装。
</para>
<para>
那么何为邮件的地址伪装呢?地址伪装只伪装邮件的发送者部分。凡是转发邮件的发送者地址属于"本地域"(不包含"@域名"只有用户名的地址,或者由 class{w})或者包含在 MASQUERADE_DOMAIN 的定义当中,则将发送者地址伪装为 MASQUERADE_AS 定义的地址。例如:采用如下配置后,user1@domain1.com 发送给 user2@domain1.com 的邮件,被重写为由 user1@domain2.com 发送给 user2@domain1.com;同样根据定义,本地域发出的邮件,也要将发送者的邮件地址写为MASQUERADE_AS 定义的地址,即 @domain2.com。配置如下:
</para>
<screen>
<![CDATA[
FEATURE(masquerade_envelope)
MASQUERADE_DOMAIN(domain1.com)
MASQUERADE_AS(domain2.com)
]]>
</screen>
<para>
FEATURE(masquerade_envelope) 很重要。如果没有定义该 Feature,则只修改邮件 header 部分的 From 地址,而不修改信封地址,邮件回复仍然回复到伪装前的地址。
</para>
<para>
常用的几个伪装规则:
</para>
<screen>
MASQUERADE_AS(domain2.com) <co id="co.mas.as"/>
MASQUERADE_DOMAIN(domain1.com) <co id="co.mas.domain"/>
MASQUERADE_DOMAIN_FILE(`filename') <co id="co.mas.domainfile"/>
FEATURE(allmasquerade) <co id="co.mas.all"/>
FEATURE(masquerade_entire_domain) <co id="co.mas.ent"/>
MASQUERADE_EXCEPTION(`host.domain1.com') <co id="co.mas.except"/>
EXPOSED_USER(`root majordomo') <co id="co.mas.expose"/>
EXPOSED_USER_FILE(`filename') <co id="co.mas.exposefile"/>
FEATURE(masquerade_envelope) <co id="co.mas.env"/>
</screen>
<calloutlist>
<callout arearefs="co.mas.as">
<para>
指出将要伪装成的域名
</para>
</callout>
<callout arearefs="co.mas.domain">
<para>
除了本地域以外,其它需要被替换的地址
</para>
</callout>
<callout arearefs="co.mas.domainfile">
<para>
除了本地域以外,其它需要被替换的地址,列在文件 <filename>filename</filename> 中
</para>
</callout>
<callout arearefs="co.mas.all">
<para>
还伪装message header中的To:地址
</para>
</callout>
<callout arearefs="co.mas.ent">
<para>
若选择,则 *.domain1.com 都被转化为 domain2.com,否则只有 domain1.com 被转化为 domain2.com
</para>
</callout>
<callout arearefs="co.mas.except">
<para>
当设置了伪装整个域时,需要排除的个别不要伪装的主机地址
</para>
</callout>
<callout arearefs="co.mas.expose">
<para>
个别用户不需要伪装,允许暴露出真实的邮件主机名,则在此设置。如 root, majordomo 用户。
</para>
</callout>
<callout arearefs="co.mas.exposefile">
<para>
同上,但用户名保存在文件中。
</para>
</callout>
<callout arearefs="co.mas.env">
<para>
伪装message envelope部分的return address,当不能交付邮件并退回给发送者时会用到该地址
</para>
</callout>
</calloutlist>
<para>
关于地址伪装的几个重要参考:
</para>
<itemizedlist>
<listitem>
<para>
<ulink url="http://www.connact.com/~esj/sendmail/masquerade.html">Sendmail Masquerade Capabilities</ulink>
</para>
</listitem>
<listitem>
<para>
<ulink url="http://www.sendmail.org/m4/masquerading.html">MASQUERADING AND RELAYING</ulink>
</para>
</listitem>
</itemizedlist>
</sect2>
<sect2><title>DNS 和 Email</title>
<para>
sendmail 使用类$w列出主机名。对于DNS中的A记录,必须在$w类中列出,但对于CNAME别名记录,DNS会自动检索出来。
</para>
<para>
如果DNS中有MX记录,则只需要在sendmail主机名中列出域名即可。
</para>
<para>
DNS的设置参见:<ulink url="http://www.worldhello.net/doc/dns_howto/">《DNS 配置示例》</ulink>。
</para>
</sect2>
<sect2 id="configpop3"><title>配置pop3
<footnote id="fn.pop3"><para>来源:<ulink url="http://www.chinaunix.net/bbsjh/1/5245.html">关于linux配置sendmail的问题</ulink></para></footnote>
</title>
<para>
需要安装imap。打开系统的pop3端口。
</para>
<para>
请查看/usr/sbin/下是否含有ipop2d、ipop3d文件,如没有,请安装imap-4.7c2-12.i386.rpm软件包。支持pop3,pop3 over ssl,imap,imap over ssl等。
</para>
</sect2>
<sect2><title>从头安装 Sendmail</title>
<para>
如果系统中没有安装 sendmail,或者功能达不到需要而需要升级,就需要重新安装。
</para>
<sect3><title>下载软件包</title>
<itemizedlist>
<listitem>
<para>
sendmail
</para>
<para>
<ulink url="ftp://ftp.sendmail.org/pub/sendmail/sendmail.8.12.8.tar.gz">下载 sendmail...</ulink>
</para>
</listitem>
<listitem>
<para>
imap
</para>
<para>
<ulink url="ftp://ftp.redhat.com/pub/redhat/linux/7.2/en/os/i386/RedHat/RPMS/imap-2000c-15.i386.rpm">下载 imap-2000c-15.i386.rpm ...</ulink>
</para>
</listitem>
<listitem>
<para>
sasl
</para>
<para>
<ulink url="ftp://ftp.andrew.cmu.edu/pub/cyrus-mail/">下载 cyrus-sasl-1.5.28.tar.gz ...</ulink>
</para>
</listitem>
</itemizedlist>
</sect3>
<sect3><title>安装 SASL,以支持SMTP认证
<footnoteref linkend='fn.sasl'/>
</title>
<para>
首先要<ulink url="ftp://ftp.andrew.cmu.edu/pub/cyrus-mail/">下载sasl库</ulink>,该函数库提供了安全认证所需函数,当前版本是1.5.28。注意2.X 版本无法与sendmail结合,因为API还未做修改。安装过程如下:
</para>
<screen>
$ gzip cyrus-sasl-1.5.27.tar.gz
$ tar -xvf cyrus-sasl-1.5.27.tar
$ cd cyrus-sasl-1.5.27
$ ./configure -prefix=/usr --disable-krb4 --disable-gssapi --enable-login
$ make
$ make install
</screen>
<para>
接下来,在编译sendmail之前,需要修改(或添加)配置文件: &lt;sendmail代码树&gt;/devtools/Site/site.config.m4,如下:
</para>
<screen>
dnl APPENDDEF(`confLIBDIRS',`-L/usr/local/lib')
dnl PPENDDEF(`confINCDIRS',`-I/usr/local/include')
APPENDDEF(`confENVDEF',`-DSASL')
APPENDDEF(`conf_sendmail_LIBS',`-lsasl')
</screen>
</sect3>
<sect3 id="smtpoverssl"><title>支持SMTP over SSL
<footnote id="fn.starttls"><para>来源:<ulink url="http://www.ofb.net/~jheiss/sendmail/tlsandrelay.shtml">Configuring Sendmail's STARTTLS (SSL) and Relaying</ulink></para></footnote>
</title>
<para>
修改配置文件: &lt;sendmail代码树&gt;/devtools/Site/site.config.m4,如下:
</para>
<screen>
dnl Stuff for TLS
APPENDDEF(`confINCDIRS', `-I/usr/local/include')
APPENDDEF(`confLIBDIRS', `-L/usr/local/lib')
APPENDDEF(`conf_sendmail_ENVDEF', `-DSTARTTLS')
dnl add to previous direction APPENDDEF(`conf_sendmail_LIBS', `-lssl -lcrypto')
APPENDDEF(`conf_sendmail_LIBS', `-lsasl -lssl -lcrypto')
</screen>
</sect3>
<sect3><title>安装 sendmail</title>
<screen>
$ sh Build
$ sh Build install
</screen>
</sect3>
<sect3><title>配置 sendmail — 支持 SMTP 认证
<footnoteref linkend='fn.sasl'/>
</title>
<para>
修改 sendmail.mc 如下:
</para>
<screen>
TRUST_AUTH_MECH(`LOGIN PLAIN DIGEST-MD5')dnl
define(`confAUTH_MECHANISMS', `LOGIN PLAIN DIGEST-MD5')dnl
dnl define(`confDEF_AUTH_INFO', `/etc/mail/auth/auth-info')
FEATURE(`no_default_msa')dnl
DAEMON_OPTIONS(`Port=25, Name=MSA, M=Ea')dnl
</screen>
</sect3>
<sect3><title>配置 sendmail — 支持 SMTP over SSL
<footnoteref linkend='fn.starttls'/>
</title>
<para>
修改 sendmail.mc 如下:
</para>
<screen>
dnl define(`CERT_DIR', `MAIL_SETTINGS_DIR`'certs')dnl
define(`CERT_DIR', `/etc/mail/certs')dnl
define(`confCACERT_PATH', `CERT_DIR')dnl
define(`confCACERT', `CERT_DIR/cacert.pem')dnl <co id="co.ssl.cacert"/>
define(`confSERVER_CERT', `CERT_DIR/cert.pem')dnl <co id="co.ssl.cert"/>
define(`confSERVER_KEY', `CERT_DIR/key.pem')dnl <co id="co.ssl.key"/>
define(`confCLIENT_CERT', `CERT_DIR/cert.pem')dnl
define(`confCLIENT_KEY', `CERT_DIR/key.pem')dnl
</screen>
<calloutlist>
<callout arearefs="co.ssl.cacert">
<para>
cacert.pem : Certificate Authority (CA) certificate
</para>
</callout>
<callout arearefs="co.ssl.cert">
<para>
cert.pem : x.509 certificate, signed by CA
</para>
</callout>
<callout arearefs="co.ssl.key">
<para>
key.pem : x.509 private key
</para>
</callout>
</calloutlist>
</sect3>
<sect3><title>配置 sendmail — 证书管理
<footnote id="fn.cert"><para>来源:<ulink url="http://www.sendmail.org/~ca/email/other/cagreg.html">Very brief introduction to create a CA and a CERT </ulink></para></footnote>
</title>
<orderedlist>
<listitem>
<para>
To make certificate authority:
</para>
<screen>
$ mkdir CA
$ cd CA
$ mkdir certs crl newcerts private
$ echo "01" > serial
$ cp /dev/null index.txt
$ cp /usr/local/openssl/openssl.cnf.sample openssl.cnf
$ vi openssl.cnf (set values)
$ openssl req -new -x509 -keyout private/cakey.pem -out cacert.pem -days 365 -config openssl.cnf
</screen>
</listitem>
<listitem>
<para>
To make a new certificate:
</para>
<screen>
$ cd CA #(same directory created above) <co id="co.cert.newreq"/>
$ openssl req -nodes -new -x509 -keyout newreq.pem -out newreq.pem -days 365 -config openssl.cnf
$
$ #cd CA #(same directory created above)
$ openssl x509 -x509toreq -in newreq.pem -signkey newreq.pem -out tmp.pem
$ openssl ca -config openssl.cnf -policy policy_anything -out newcert.pem -infiles tmp.pem <co id="co.cert.newcert"/>
$ rm -f tmp.pem
</screen>
<calloutlist>
<callout arearefs="co.cert.newreq">
<para>
(certificate and private key in file newreq.pem) To sign new certificate with certificate authority:
</para>
</callout>
<callout arearefs="co.cert.newreq">
<para>
(newcert.pem contains signed certificate, newreq.pem still contains unsigned certificate and private key)
</para>
</callout>
</calloutlist>
</listitem>
<listitem>
<para>
Edit newreq.pem
</para>
<para>
Remove the unsigned certificate (leaving the private key)
</para>
</listitem>
<listitem>
<para>
Copy files
</para>
<screen>
$ cp cacert.pem /etc/mail/certs/cacert.pem
$ cp newreq.pem /etc/mail/certs/key.pem
$ cp newcert.pem /etc/mail/certs/cert.pem
</screen>
</listitem>
<listitem>
<para>
Set permissions
</para>
<screen>
$ chmod 400 key.pem
</screen>
</listitem>
<listitem>
<para>
Check key properties
</para>
<screen>
$ openssl x509 -noout -in cacert.pem -text
</screen>
<para>
Make sure that the CN of the CA certificate and CN of the server certificate are different, because newer versions of Mozilla and Netscape won't accept the server certificate if it is self-signed.
</para>
</listitem>
</orderedlist>
</sect3>
<sect3><title>配置pop3</title>
<para>
参见: <link linkend="configpop3">前面章节的描述。</link>
</para>
</sect3>
<sect3><title>关于权限</title>
<screen>
-r-xr-sr-x root smmsp ... /PATH/TO/sendmail
drwxrwx--- smmsp smmsp ... /var/spool/clientmqueue
drwx------ root wheel ... /var/spool/mqueue
-r--r--r-- root wheel ... /etc/mail/sendmail.cf
-r--r--r-- root wheel ... /etc/mail/submit.cf
</screen>
</sect3>
<sect3><title>启动 sendmail</title>
<screen>
$ sendmail -bd -q1h
</screen>
<para>
-bd 参数,表示将sendmail作为一个守护进程来运行;
</para>
<para>
-q1h 参数,表示每隔一个小时发送一次邮件,类似地,-q15m是15分钟,等等。
</para>
</sect3>
</sect2>
<sect2><title>邮件分拣</title>
<para>
.forward 配置文件,可以调用外部程序处理邮件,包括邮件杀毒、自动回复、邮件转发、备份、丢弃等等。
</para>
<para>
sendmail 如果配置了 smrsh,则对调用外部程序有所限制,需要针对 smrsh 作特殊处理,参见:<link linkend="faq.smrsh">FAQ</link>
</para>
<sect3><title>vacation 自动回信<footnote id="fn.vacation"><para>来源:<ulink url="http://www.jimmy-lam.com/studyarea/tips/vacation.htm">Vacation 自动回信程序</ulink></para></footnote>
</title>
<para>
在 .forward 文件中设置使用 vacation 处理邮件:
</para>
<screen>
\ric, "|/usr/bin/vacation -a allman eric"
</screen>
<para>
which would send messages to you (assuming your login name was eric) and reply to any messages for ``eric'' or ``allman''.
</para>
<para>
Vacation returns a message, ~/.vacation.msg by default, to the sender informing them that you are currently not reading your mail. The message is only sent to each sender once per reply interval (see -r below). The intended use is in a .forward file. For example, your .forward file might have:
</para>
<para>
~/.vacation.msg 范例
</para>
<screen>
Subject: Re:$SUBJECT
From: Song ( 由 vacation 程式自动回信 )
$FROM 您好:
我目前无法看到这封信。
当我回来上班并看过这封信後,我会尽快给您回信。
谢谢。
</screen>
<para>
如果想在回信中使用 Reply-To:,需要用参数 -r 调用 vacation。
</para>
<para>
vacation 会把回过信的邮件地址存入 .vacation.db 中,同时在 7 天之中不会再自动回覆相同的邮件地址。7 天是系统预设值,如要修改可在启动时使用 -tN 的参数,N 是天数,如:vacation -I -r -t1 song ,这样隔 1 天就会再自动回覆相同的邮件地址了。
</para>
<para>
vacation 执行时要用到使用者的 shell,如果使用者的 shell 被设成 /dev/null或是 /bin/false 的话,会有错误出现。
</para>
<para>
</para>
</sect3>
<sect3 id="procmail"><title>procmail</title>
<para>
procmail就是一个用于过滤用户接收到的电子邮件,并能对其自动分类、处理的一个应用软件。
</para>
<para>
在 .forward 文件中设置使用 procmail 处理邮件:
</para>
<screen>
"|/usr/bin/procmail"
</screen>
<para>
procmail 的配置文件为:/etc/procmailrc,或者用户主目录下的文件 ~/.procmailrc 由环境变量和过滤规则组成。邮件的投递动作由第一个匹配的过滤规则确定。如果没有匹配任何规则,则执行确省的投递动作。
</para>
<para>
投递规则的格式如下(man procmailrc):
</para>
<screen>
<![CDATA[
:0 [flags] [ : [locallockfile] ]
<zero or more conditions (one per line)>
<exactly one action line>
]]>
</screen>
<para>
冒号——`:',开始一条规则。后面的 0,代表下面列出的条件表达式的个数不限制。
</para>
<para>
可能用到的标志有:
</para>
<itemizedlist>
<listitem>
<para>
H (确省)
</para>
<para>
只对信头进行常规表达式匹配。
</para>
</listitem>
<listitem>
<para>
B
</para>
<para>
对信体亦作常规表达式匹配。
</para>
</listitem>
<listitem>
<para>
D
</para>
<para>
大小写敏感匹配。确省是大小写不敏感。
</para>
</listitem>
<listitem>
<para>
A, a
</para>
<para>
只有当前一个不带A或者a的条件表达式匹配,才进行条件判断。
</para>
</listitem>
<listitem>
<para>
E,e
</para>
<para>
相当于 Else If。
</para>
</listitem>
<listitem>
<para>
h(确省)
</para>
<para>
将信头送入管道、文件、目的地
</para>
</listitem>
<listitem>
<para>
b(确省)
</para>
<para>
将信体送入管道、文件、目的地
</para>
</listitem>
<listitem>
<para>
f
</para>
<para>
将管道视为过滤器
</para>
</listitem>
<listitem>
<para>
c
</para>
<para>
信件拷贝,即使匹配本条规则,仍去匹配其它规则
</para>
</listitem>
</itemizedlist>
<para>
接下来是条件部分。条件判断以星号开始——`*',后面跟一个常规表达式。可以有零个或多个条件表达式。如果是多个条件表达式,则需要各个条件均匹配,即 and 的关系。如果没有条件表达式,则结果确省为真。
</para>
<para>
范例(man procmailex):
</para>
<itemizedlist>
<listitem>
<para>
处理由crontab出发的邮件。对于不关心的邮件予以删除,对于关心的邮件,发送到邮件列表 list-cron。
</para>
<screen>
<![CDATA[
:0:
* ^Subject: Cron .* /bin/sh /www/up.sh
/dev/null
:0:
* ^Subject: Cron .*
list-cron
]]>
</screen>
</listitem>
<listitem>
<para>
Forward all mail from peter about compilers to william (and keep a copy of it here in petcompil).
</para>
<screen>
<![CDATA[
:0
* ^From.*peter
* ^Subject:.*compilers
{
:0 c
! william@somewhere.edu
:0
petcompil
}
]]>
</screen>
</listitem>
<listitem>
<para>
等价的表达式
</para>
<screen>
<![CDATA[
:0 c
* ^From.*peter
* ^Subject:.*compilers
! william@somewhere.edu
:0 A
petcompil
]]>
</screen>
</listitem>
<listitem>
<para>
等价的,但是速度稍慢的表达式
</para>
<screen>
<![CDATA[
:0 c
* ^From.*peter
* ^Subject:.*compilers
! william@somewhere.edu
:0
* ^From.*peter
* ^Subject:.*compilers
petcompil
]]>
</screen>
</listitem>
<listitem>
<para>
Forward all mails shorter than 1000 bytes to my home address (no lockfile needed on this recipe).
</para>
<screen>
<![CDATA[
:0
* < 1000
! myname@home
]]>
</screen>
</listitem>
</itemizedlist>
<para>
Procmail 的FAQ,参见:<ulink url="http://www.uwasa.fi/~ts/info/proctips.html">Timo's procmail tips and recipes</ulink>
</para>
</sect3>
</sect2>
<sect2><title>FAQ</title>
<qandaset defaultlabel='number'>
<qandaentry>
<question id="faq.smrsh">
<para>
安装 majordomo,aliases 文件中有:<command>majordomo: "|/usr/local/majordomo/wrapper majordomo"</command>。majordomo运行时报错:smrsh: "wrapper" not available for sendmail programs (stat failed)。为什么?
</para>
</question>
<answer>
<para>
因为Sendmail使用 smrsh (SendMail Restricted SHell)。smrsh程序的目的是作为在mailer中为sendmail定义的"/bin/sh"的替代shell。smrsh是一种受限shell工具,它通过"/etc/smrsh"目录来明确指定可执行文件的列表。简而言之smrsh限制了攻击者可以执行的程序集。当它与sendmail程序一起使用的时候,smrsh有效的将sendmail可以执行的程序的范围限制在smrsh目录之下。
</para>
<para>
在 sendmail.mc 文件中的配置:
</para>
<screen>
FEATURE(`smrsh',`/usr/sbin/smrsh')dnl
</screen>
<para>
smrsh 允许执行的程序,需要在 "/usr/adm/sm.bin" 目录中创建符号连接。如果定义了环境变量 SMRSH_CMDDIR,则smrsh允许运行的程序放在该环境变量定义的目录中,否则该目录为:"/usr/adm/sm.bin"。测试 smrsh:
</para>
<screen>
$ ln -s /usr/bin/vim /usr/adm/sm.bin/
$ /usr/sbin/smrsh -c /usr/bin/vim
</screen>
</answer>
</qandaentry>
<qandaentry>
<question id="faq.dontblamesendmail">
<para>
尤其是在和其它软件配合使用时,Sendmail经常会因为文件或者目录的权限问题——组写权限,而报错。怎么办?
</para>
</question>
<answer>
<para>
如果不想对文件、目录的设置过于苛刻的话,可以考虑使用 <ulink url="http://www.sendmail.org/tips/DontBlameSendmail.html">DontBlameSendmail</ulink> 选项。例如:
</para>
<informalexample>
<screen>
<![CDATA[
define(`confDONT_BLAME_SENDMAIL', `AssumeSafeChown')
define(`confDONT_BLAME_SENDMAIL', `GroupWritableAliasFile')
define(`confDONT_BLAME_SENDMAIL', `GroupWritableDirPathSafe')
define(`confDONT_BLAME_SENDMAIL', `GroupWritableIncludeFileSafe')
define(`confDONT_BLAME_SENDMAIL', `IncludeFileInGroupWritableDirPath')
define(`confDONT_BLAME_SENDMAIL', `IncludeFileInUnsafeDirPath')
]]>
</screen>
</informalexample>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
如何让sendmail具有泛email支持?即无需设置本机账号的邮件账户?
</para>
</question>
<answer>
<para>
通过设置 LUSER_RELAY,还和 procmail 配合使用。
</para>
<informalexample>
<screen>
<![CDATA[
define(`LUSER_RELAY', `local:root')
]]>
</screen>
</informalexample>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
一个用户离开了公司,但仍然收到许多关于他/她的邮件,我怎么让别人知道此人已经使用新的邮件地址?
</para>
</question>
<answer>
<para>
加下面的行到M4宏配置文件中
</para>
<screen>
FEATURE(`redirect')dnl
</screen>
<para>
然后加下面的行到aliases文件中:
</para>
<screen>
olduser: him@new.address.REDIRECT
</screen>
<para>
所有发到旧的邮件地址的人将收到一个新邮件地址的通知消息.
</para>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
为什么我更改了上面各种配置文件后仍然不起作用?
</para>
</question>
<answer>
<para>
更改配置后,需要进入到/etc/mail 目录下,执行:
</para>
<screen>
<![CDATA[
cd /etc/mail
make
newaliases
/etc/init.d/sendmail restart
]]>
</screen>
<para>
或者:在任意配置文件更改后都要运行makemap,例如:
</para>
<screen>
<![CDATA[
# makemap hash virtusertable.db < virtusertable
]]>
</screen>
<para>
但是对于local-host-names和relay-domains文件的更改要用下面的命令重启Sendmail
</para>
<screen>
<![CDATA[
#killall -HUP sendmail
]]>
</screen>
<para>
对aliases文件的更改要运行
</para>
<screen>
#newaliases
</screen>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
怎么检查一封邮件的发封过程?
</para>
</question>
<answer>
<para>
在Sendmail邮件服务器上执行下面的命令.
</para>
<screen>
<![CDATA[
# echo testing | /usr/sbin/sendmail -f sender@somedomain.com -v someone@somedomain.com
]]>
</screen>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
如果用 POP3 命令,直接在服务器上操作邮件?
</para>
</question>
<answer>
<para>
telnet 登陆服务器的 110 端口,执行 POP3 命令:
</para>
<itemizedlist>
<listitem>
<para>
USER &lt;username&gt;
</para>
</listitem>
<listitem>
<para>
PASS &lt;password&gt;
</para>
</listitem>
<listitem>
<para>
LIST [msg]
</para>
</listitem>
<listitem>
<para>
TOP [msg] [count_n]
</para>
</listitem>
<listitem>
<para>
UIDL [msg]
</para>
</listitem>
<listitem>
<para>
APOP name digest
</para>
</listitem>
<listitem>
<para>
DELE [msg]
</para>
</listitem>
<listitem>
<para>
NOOP
</para>
</listitem>
<listitem>
<para>
QUIT
</para>
</listitem>
</itemizedlist>
</answer>
</qandaentry>
<qandaentry>
<question>
<para>
如何用 SMTP 命令,远程登录到服务器上发送邮件?
</para>
</question>
<answer>
<para>
telnet 登陆服务器的 25 端口,执行 SMTP 命令:
</para>
<itemizedlist>
<listitem>
<para>
HELO &lt;your.site.name&gt;
</para>
<para>
或者:EHLO &lt;your.site.name&gt;
</para>
</listitem>
<listitem>
<para>
MAIL FROM:&lt;user@somewherer.net&gt;
</para>
</listitem>
<listitem>
<para>
RCPT TO: &lt;username@dest.domain&gt;
</para>
</listitem>
<listitem>
<para>
DATA
</para>
</listitem>
<listitem>
<para>
QUIT
</para>
</listitem>
</itemizedlist>
</answer>
</qandaentry>
</qandaset>
</sect2>
</sect1>
<sect1 id="qmail"><title>qmail</title>
<para>
两年前配过。记得有网上有一个不错的文档<ulink url="http://www.lifewithqmail.org">《Life with qmail》</ulink>,去 Google 上查一查吧。
</para>
</sect1>
<sect1 id="mailarchive"><title>Mail Archive</title>
<para>
邮件如何归档?<ulink url="http://www.mhonarc.org/">MHonarc</ulink>,一个强大的邮件归档工具,将邮件转换为 html,是一个不错的选择。
</para>
<para>
但是如何将 Outlook 的邮件转换为 MHonarc 能够识别的格式呢?在 SourceForge.net 上有几个开放源码项目:
</para>
<itemizedlist>
<listitem>
<para>
<ulink url="http://sourceforge.net/projects/ol2mbox">ol2mbox</ulink>
</para>
<para>
Outlook to unix mail converter. 可以将 Outlook 的 PST 格式转换为 mailbox 格式。
</para>
</listitem>
<listitem>
<para>
<ulink url="http://sourceforge.net/projects/mbx2mbox">mbx2mbox</ulink>
</para>
<para>
Converts Outlook .mbx and .dbx files into standard RFC822 mail files.
</para>
</listitem>
</itemizedlist>
<para>
MHonarc 的配置参见:<ulink url="/doc/mailinglist/">Maillist Howto</ulink>。
</para>
</sect1>
<appendix id="background"><title>基础知识</title>
<sect1 id="appendix-1"><title>基本概念</title>
<itemizedlist>
<listitem>
<para>
MUA
</para>
<para>
邮件阅读或发送程序,如 outlook, 在邮件系统中用户只与 MUA 打交道,MUA将邮件系统的复杂性与用户隔离开。
</para>
</listitem>
<listitem>
<para>
Mail Router
</para>
<para>
程序,从用户处接收邮件并决定其目的地址以及如何到达目的地。比如根据接收者的地址不同,电子邮件可能通过TCP/IP网络发送,或者通过UUCP或FAX发送。邮件路由使用接收者地址及其内部的配置信息来选择一个最好的MTA,然后将邮信件转给此MTA。
</para>
</listitem>
<listitem>
<para>
MTA(Mail Transport agent)
</para>
<para>
一个专用程序,其作用类似于邮局,用于在两个机器之间发送邮件。通常,一个机器上只有一个MTA。sendmail程序就是一个MTA,此外还有其他MTA,如MMDF,Smail 3.x, qmail以及zmailer等。
</para>
<para>
MTA能够理解特定网络的EMAIL协议并通过网络传输信件,如UUCP可通过UUCP连接发送信件,但无法处理SMTP信件。
</para>
</listitem>
<listitem>
<para>
MDA(Mail Delivery Agent:投递代理)
</para>
<para>
sendmail自己并不完成最终的邮件发送,它要调作其他的程序来完成最后的投递服务。在SVR4系统中一般是/bin/mail.
</para>
</listitem>
<listitem>
<para>
信封(envelope)和内容(content)
</para>
<para>
一个email消息由两部分组成:信封(envelope)和内容(content)。
</para>
<para>
信封告诉SMTP代理(sendmail或者postfix)如何投递消息。
</para>
<para>
内容又包括信头(Header)和 消息内容。Header 和消息内容之间用一个空行分隔。内容包括能被人们阅读的消息本身和一些标题(header)(比如消息subject),而一些内容中的header可能和envelope中的重复(比如"To"地址),这些重复的header用来显示时候使用,而envelope中的则是用来投递使用。(这也是为什么你会收到"To"地址不是你的垃圾邮件)
</para>
</listitem>
<listitem>
<para>
Envelope sender (ES), Envelope recipient (ER), Header sender (HS), Header recipient (HR)
</para>
<para>
Envelope sender (ES) -- The address provided by the MAIL FROM: SMTP command. Mail transport agents send delivery errors to this address, and often check for the existence of the hostname portion of this email address in DNS. For this reason, if you are rewriting/masquerading the HS, it may be a good idea to masquerade the ES.
</para>
<para>
Envelope recipient (ER) -- The address provided by the RCPT TO: SMTP command. It is the final destination address of the email. This may differ from the HR if the address is rewritten using the user database, aliases database, or virtusertable.
</para>
<para>
Header sender (HS) -- The From: address in the message header. This address is frequently masqueraded/rewritten from user@host.domain.com to user@domain.com, especially when host.domain.com is not configured to handle mail directly.
</para>
<para>
Header recipient (HR) -- The To: address in the message header. This is the recipient address specified by the author of the message. It is left intact unless you use the allmasquerade feature or domaintable.
</para>
<para>
</para>
<screen>
$ telnet smtp.mydomain.com 25 <co id="smtpsess.telnet"/>
Trying smtp.mydomain.com...
Connected to smtp.mydomain.com.
Escape character is '^]'.
220 smtp.mydomain.com ESMTP
mail from: mailfrom@mydomain.com <co id="smtpsess.es"/>
250 ok
rcpt to: jiangxin <co id="smtpsess.er"/>
250 ok
data <co id="smtpsess.data"/>
354 go ahead
Date: Tue, 1 Mar 2008 16:10:44 +0800 <co id="smtpsess.header"/>
From: Header-From &lt;header-from@mydomain.com&gt; <co id="smtpsess.hs"/>
To: Header-to@mydomain.com <co id="smtpsess.hr"/>
Subject: smtp test <co id="smtpsess.headersubject"/>
<co id="smtpsess.blankline"/>
Hi, <co id="smtpsess.msgcontent"/>
This mail contains only a test message. Ignore it.
Sincerely yours, Johnson
. <co id="smtpsess.msgend"/>
</screen>
<calloutlist>
<callout arearefs="smtpsess.telnet">
<para>
telnet 邮件服务器的 smtp 端口,开始 SMTP 会话;
</para>
</callout>
<callout arearefs="smtpsess.es">
<para>
用户输入,作为 Envelope sender (ES)。此处输入的地址必须是要送达的真实的邮件地址;
</para>
</callout>
<callout arearefs="smtpsess.er">
<para>
用户输入,作为 Envelope recipient (ER)。应该输入发送者的地址,出现在邮件头的路由信息中;
</para>
</callout>
<callout arearefs="smtpsess.data">
<para>
输入 data 命令,开始输入信件内容;
</para>
</callout>
<callout arearefs="smtpsess.header">
<para>
信件的开始输入信头。信头可以包含 发送邮件的时间、Header Sender、Header Recipient、信件标题;
</para>
</callout>
<callout arearefs="smtpsess.hs">
<para>
用户输入,作为 Header sender (HS);
</para>
</callout>
<callout arearefs="smtpsess.hr">
<para>
用户输入,作为 Header recipient (HR);
</para>
</callout>
<callout arearefs="smtpsess.headersubject">
<para>
用户输入,作为信件标题
</para>
</callout>
<callout arearefs="smtpsess.blankline">
<para>
输入一个空行,作为信头和信件内容的分隔;
</para>
</callout>
<callout arearefs="smtpsess.msgcontent">
<para>
开始输入信件内容;
</para>
</callout>
<callout arearefs="smtpsess.msgend">
<para>
输入一个点`.' 作为信件结束的标志;
</para>
</callout>
</calloutlist>
</listitem>
</itemizedlist>
</sect1>
<sect1 id="appendix-2"><title>相关资源</title>
<itemizedlist>
<listitem>
<para>
RFC 821 STMP
</para>
</listitem>
<listitem>
<para>
RFC 822 EMAIL格式规范
</para>
</listitem>
<listitem>
<para>
RFC 1425 ESMTP
</para>
</listitem>
<listitem>
<para>
RFC 1123 对主机的要求及对前面的RFC的一些修改
</para>
</listitem>
<listitem>
<para>
SIOG: Sendmail Installation and Operation Guide
</para>
</listitem>
</itemizedlist>
</sect1>
</appendix>
</article>
Jump to Line
Something went wrong with that request. Please try again.