前言:
出于工作原因,需要学习搭建邮件系统,为避免日后生疏最后忘了,这里会记录我整个学习的过程,包括中途遇到的不解之处,当然也会有一个完整的搭建成品的步骤。
网上可以搜到不少关于搭建邮件系统的文章,质量参差不齐,我本人更希望自己能了解到更多,而非照着步骤啪啪啪搭起来就算了,以后遇到问题能比较有效率地寻找解决方案。
我一边学一边写,会有理解错的,后面发现之后会回头修正。欢迎留言指教。
涉及到概念(ps.直接看没意思,先往后看,发现不明白的英文名词再回来这里查一下吧
)
名词 | 解释 |
---|---|
MUA | (Mail User Agent)用户邮件代理,用于接收邮件。如foxmail。 |
MTA | (Mail Transfer Agent)邮件传输代理,用于接受发邮件请求并完成转发动作。如postfix。 |
MDA | (Mail Delivery Agent)邮件分发代理,用于将收到的邮件放进收件人信箱中,具有过滤邮件、自动回复等功能。主要的MTA程序都有自己的MDA功能,也有比较强大的第三方MDA,如procmail等。 |
MRA | (Mail Retrieval Agent)邮件取回代理,提供POP3/IMAP协议,供MUA将邮件取出。 |
POP3 | (Post Office Protocol version 3)邮局协议第三版。对于MUA拉取邮件到本地的动作,可以设置拉取完后删除 和拉取后不删除 两种方式,对邮件得下载到本地后才能进行管理。 |
IMAP | (Internet Message Access Protocol)网络信息访问协议。相比POP3,可以远程访问邮件服务器管理邮件,不一定非得先下载到本地。 |
SMTP | (Simple Mail Transfer Protocol)简单邮件传输协议。MTA就是SMTP的一个实现,端口号通常是25。SMTP协议很早就出现,比HTTP还早,本身没有对发送方的身份验证,所以后来出现了SPF、DKIM、DMARC等东西来弥补。 |
Postfix | 一个开源的MTA程序,负责通过SMTP协议发送邮件。是作者为改善sendmail开发的,如今很流行。 |
Cyrus SASL | Cyrus Simple Authentication and Security Layer的缩写,是一个辅助的程序,针对SMTP的认证,它提供了saslauthd来进行账号密码的比对。同时,它还支持两个auxprop插件:sasldb,sql。反正就是提供不同方式的身份验证。后面会学到。 |
Dovecot | 一个开源的MRA程序,按照POP3/IMAP协议提供邮件取回服务,同时,它支持对用户的身份进行验证,貌似也用来协助SMTP服务器做身份验证,而且可以做到比cyrus sasl更好? |
MX | 邮件交换记录。发邮件时,会根据收件人的地址后缀去DNS服务器查到MX记录,从而定位收件地址所在的服务器。 |
SPF | (Sender Policy Framework)是为了防范垃圾邮件而提出来的一种DNS记录类型。用于登记某个域名拥有的用来外发邮件的所有IP地址。收方邮件服务器可能会根据发方的域名向DNS服务器索取发方域名的SPF记录,跟发方的IP做匹配,如果不能匹配上,那么说明这封邮件并非由真正的发方域名的服务器发出,可能会判为垃圾邮件。 |
PTR | 反向域名解析。使得可以通过发方的IP地址反查到域名,也是判断发件人是否正常的手段。 |
名词的解释暂时到这可好。。另外还有那些DKIM之类,后面要用到的时候再说。
邮件系统工作原理图(ps.看这些图觉得烦,不妨先往后看吧,想要知道收发邮件的背后机制时再来这看
)
在简书里的这篇文章从零开始邮件服务器搭建给出了几个流程图,特别好地描述了邮件系统的工作原理,推荐过去阅读,有对流程图的详细讲解。我在下面仅把图贴过来(如果原作者不愿我把图贴过来,可以留言,我删掉便是),方便查看。
邮件系统架构
邮件服务器接收邮件
用户查收邮件过程
用户发送邮件过程
我的工作环境
服务器是阿里云上的ECS,操作系统是Centos 6.8 (64位)。下面一步步地,是从一个全新的由公共镜像创建的ECS开始,慢慢部署,琢磨。
首先,为了好看些,vim /etc/bashrc
,末尾添加如下代码:
#color
use_color=true
if ${use_color}; then
if [[ ${EUID} == 0 ]]; then
PS1='\[\033[01;31m\]\h\[\033[01;34m\] \W \$\[\033[00m\] '
else
PS1='\[\033[01;32m\]\u@\h\[\033[01;34m\] \w \$\[\033[00m\] '
fi
else
if [[ ${EUID} == 0 ]]; then
PS1='\u@\h \W \$ '
else
PS1='\u@\h \w \$ '
fi
fi
alias ll='ls -la'
alias vi='vim'
alias grep='grep --color=auto'
然后,修改hostname,比原先那样好看些吧。虽说Postfix会用到hostname,但因为可以在main.cf(如果你不知道这个,可以先不管,后面会说)里设置,所以,在这里修改hostname,我能想到的好处,就是好看。
vim /etc/sysconfig/network;
HOSTNAME=mail.howard.org #修改HOSTNAME
vim /etc/hosts;
127.0.0.1 mail.howard.org #hosts对hostname本身关系不大,增加一个mapping,便于有些程序对hostsname的dns解析
hostname mail.howard.org; #上面的修改需要重启主机才会生效,这里不想重启,就直接改内存里的吧。需要退出当前会话重新进来才可以看到生效
hostname要符合FQDN,可以自行百度。比如我这台主机是邮件服务器,hostname写成mail.howard.org,属于全称域名,domain就是howard.org,主机名是mail,表示该主机在域名树的位置。
安装一些软件
说明:下面安装的软件并非全是必要的,为了后面的学习,先装好了。
- 安装postfix:
yum install postfix
。我执行后发现是升级原有的版本。设置开机启动chkconfig postfix on
。 - 删除原有的sendmail:
rpm -e sendmail
oryum remove sendmail
。本ECS没安装sendmail。 - 安装Cyrus SASL相关的软件:
yum install cyrus-sasl cyrus-sasl-plain cyrus-sasl-md5 cyrus-sase-sql
。 - 安装dovecot:
yum install dovecot
。我安装的版本是1:2.0.9-22.el6。 - 安装MySQL:
由于ECS默认的源里的MySQL版本是5.1,所以下面先改一下源:
wget http://dl.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm;
wget http://rpms.famillecollet.com/enterprise/remi-release-6.rpm;
rpm -ivh *.rpm;
vim /etc/yum.repos.d/remi.repo;
[remi] enabled=1 #设置remi下面的enabled为1
yum install mysql-server; #现在安装的就是MySQL 5.5版本了
/etc/init.d/mysqld start; #启动MySQL
chkconfig mysqld on; #开机自启动
mysql -u root -p; #看到等待输入密码时,直接按回车,因为是全新安装的,所以无密码。进入后是mysql的控制台
mysql>drop database test; #删除test库
mysql>use mysql; #切换至mysql库
mysql>delete from user where user=''; #删除匿名账户
mysql>update user set password=PASSWORD('123456') where user='root';#设置root密码
mysql>grant all privileges on *.* to root@'%' identified by '123456';#设置允许远程访问(为方便才这样设的,你懂的)
mysql>flush privileges;
mysql>exit
配置防火墙
对于阿里云主机,用安全组也是不错的选择。下面是配置iptables
的方法:
ll /etc/sysconfig/iptables; #本ECS默认没有配置iptables,所以这里会报找不到文件
iptables-save > /etc/sysconfig/iptables; #生成一个空的iptables配置文件
#在 :OUTPUT ACCEPT [107:11768] 跟 COMMIT 两行之间插入下面这些内容
-A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
-A INPUT -p icmp -j ACCEPT
-A INPUT -i lo -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 22 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 3306 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 25 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 993 -j ACCEPT
-A INPUT -m state --state NEW -m tcp -p tcp --dport 995 -j ACCEPT
-A INPUT -j REJECT --reject-with icmp-host-prohibited
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
#上面的意思大概就是,只对tcp连接开放22、3306、25、993、995端口,其他都封禁。
/etc/init.d/iptables restart
下面先让服务器可以正常发出一封邮件
先试试现在能不能发送了(ps.简直迫不及待啊
):
- 启动postfix:
/etc/init.d/postfix start;
-
netstat -tlnp |grep 25;
可以看到
-
yum install telnet;
我发现ECS还没安装telnet。 - 用telnet跟postfix交互(不妨
tail -f /var/log/maillog
看输出什么log,有时候很有用)
- 检查一下收件箱,收到啦!虽然是在垃圾箱里。是的,只需要postfix就可以完成发邮件的事情了!不过我们也发现了两个问题,一个是这个过程没有要求验证身份;第二是在
/var/log/maillog
里输出不少warning。下面就来做一些配置,让发邮件这个任务完成得更好些。
修改默认邮件传输代理(MTA)
输入alternatives --display mta;
看第一行,发现提示的第一行是mta - 状态是自动
。现在我们把它改成手动的强制指向postfix:alternatives --config mta
,根据提示,选择sendmail.postfix。这个时候再输入alternatives --display mta;
,现在可以看到第一行是mta - 状态是手工
。
配置postfix(/etc/postfix/main.cf
)
关于postfix的历史以及
/etc/postfix
目录下各个文件的意义,请移步看鸟哥的文章鸟哥的Linux私房菜(第二十二章)。这里备注一下修改main.cf需要注意的地方:
- #符号是注释符
- 给变量赋值的写法,要注意=号的两边得留空格。而这一行的开头不能有空白字符。
如:myhostname = xxx.xxx.com
- 可以使用$符号来延伸变量的使用,如:
myorigin = $myhostname
- 如果要给一个变量赋值多个值,值的写法建议用逗号+空格来隔开。
如:mydestination = $myhostname, $mydomain, xxx.xxx.com
- 可以使用多行来表示同一个设定值,只要前一行末尾有逗号,下一行开头有空白字符就行。所以前面说第一行的开头处不要有空白字符。
- 如果对同一个设定项重复做了配置,以后面写的配置为准。
- 好习惯:
cd /etc/postfix; cp main.cf main.cf.bk;
-
vim main.cf
(ps.如果没能搜到,就在文件末尾添加即可。下面所有的设定项可以通过man 5 postconf查看其意思。
)
#主机名;会被后面很多设定项引用,务必使用FQDN,即完整主机名
myhostname = mail.howard.org
#域名;一般是主机名去掉第一个.前面那截剩下的,后面也被很多设定项引用
mydomain = howard.org
#发信源主机;对应邮件标头上的“mail from”;默认是$myhostname,如果多台主机使用同一个domain,那么就设成$mydomain
myorigin = $mydomain
#postfix的监听接口(极重要);默认只开放给本机localhost,如果要监听整个internet的话,设为all
inet_interfaces = all
#postfix的监听IP协议;默认是all,即同时监听IPv4和IPv6,但如果服务器的网络只支持IPv4,那就设为ipv4
inet_protocols = ipv4
#能收信的主机名(极重要);DNS里的MX指向的主机名也要写到这里来
#如果是邮件域网关,要加上$mydomain,其他smtp节点就不用加$mydomain
mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
#约定信任的用户端(极重要);规定了本MTA可以为哪些用户端进行Relay,就是转发了
#千万不要open relay,会让本MTA的IP进入各种黑名单
#鸟哥建议下面这种写法,使用hash:/etc/postfix/access,就是个外部的哈希库,可以参考鸟哥的文章👆了解详情
mynetworks = 127.0.0.0/8, hash:/etc/postfix/access
#默认收件箱在/var/spool/mail/user,所有的邮件存放在同一个文件中
#改成Maildir/,收件会存储在/home/user/Maildir/下,每封邮件是一个文件
#如果改成Mailbox,则收件会存储在/home/user/Mailbox中,都存在同一个文件里
home_mailbox = Maildir/
#在SMTP服务器的欢迎标语上显示软件版本。Postfix本身对这个不关心
smtpd_banner = $myhostname ESMTP
#邮件最大尺寸,单位:字节
message_size_limit = 52428800
#规定收件箱最大容量,单位:字节
mailbox_size_limit = 1073741824
- 由于
mynetworks
设置了hash:/etc/postfix/access
,所以需要执行postmap hash:/etc/postfix/access
来生成对应的哈希库/etc/postfix/access.db
/etc/init.d/postfix restart #使配置文件生效 因为改动了inet_protocols和inet_interfaces,所以需要restart,否则reload即可
- 设置DNS解析,增加两条A记录,之所以其中一个主机记录写mail,因为前面
$myhostname
写了mail.howard.org啊。
- 设置DNS解析,增加一条MX记录,记录值跟
$myhostname
一致。因为只有一条MX记录,所以MX优先级是多少不重要啦。
-
设置DNS解析,增加一条SPF记录,其实是按照SPF格式增加一条TXT记录,有助于提高服务器IP信誉度。
- 发工单跟阿里云请求对ECS的IP跟主机域名mail.howard.org做反向域名解析,有助于提高服务器IP的信誉度。
关于MX、SPF、PRT
这几项基本都是为了增加服务器IP的信誉度的。参考这个文章的说法:如何避免你外发的电子邮件被误判为垃圾邮件。或者自己网上搜搜,很容易能理解。
关于Open Relay
在上面配置/etc/postfix/main.cf
时提到Open Relay这个名词。
如果开启了Open Relay,那么就是说,任何人都可以连接到你的SMTP服务器进行转发将邮件寄出去,不管客户端是哪里、发件人是谁、收件人是谁。这种情况是非常糟糕的,意味着你的服务器会成为发送垃圾邮件的人的工具。所以绝大部分收件服务器对Open Relay的SMTP服务器是零容忍,同时也有不少第三方机构会扫描记录这种SMTP服务器,并将其扔进黑名单。所以,不要开启Open Relay。
那么怎么禁止Open Relay呢?换句话说就是,要怎么配置才可以限制不能被随意利用来转发邮件。无非就是,限制客户端、限制发件人、限制收件人等等。其实,现在安装的postfix,默认就是禁止Open Relay的。下面我们来理解一下是怎么禁止Open Relay的。
在我的理解里,主要通过配置下面三个设定项来达到目的:smtpd_recipient_restrictions
,smtpd_client_restrictions
,smtpd_sender_restrictions
。通过man 5 postconf
可以查到这三个设定项的含义和用法。通过postconf -h xxxx
可以查看当前配置里设定项xxxx
的值。
-
smtpd_client_restrictions
,用于限制发信客户端,默认值是空,即不限制。如果是给内部固定的主机使用,可以设置这项,比如:smtpd_client_restrictions = permit_mynetworks, reject_unknown_client_hostname
。 -
smtpd_sender_restrictions
,用于限制发信人,对应MAIL FROM
指令的内容,默认值是空,即不限制。 由于MAIL FROM
可以很简单地伪造,所以,这个参数没啥作用其实,一般不用。 -
smtpd_recipient_restrictions
,用于限制收件人,对应RCPT TO
指令的内容,默认值为permit_mynetworks, reject_unauth_destination
,即允许客户端属于mynetworks
的发信请求,拒绝不在mydestination
范围内的发信请求,这两条约定不是且的关系,而是先到先得的关系,即如果发现符合mynetworks
,那么不管是否符合mydestination
,都通过;相反,就算不符合mynetworks
,但因为第一项并没有明说拒绝,那么继续用第二项做判断,可见permit_xxx
跟reject_xxx
的区别哈。这个设定项被用得比较多,对于版本号小于2.10的postfix,还有需要注意设置不当导致relay open的问题,参考《Postfix SMTP relay and access control》。
搭配上面这三个设定项的,一般是mynetworks
和mydestination
。所以这两项的设定极其重要。
正经地发送一封成熟的邮件
行文至此,对于一个内部使用的SMTP服务器已经完成,可以通过mynetworks设置只允许内部使用。那么下面来正经地发一封邮件,还是用telnet,顺便看一下有哪些常见的格式。
最后
上面那个截图,用的都是英文,如果要用中文的话,需要指定编码格式之类,挺烦的,不妨打开一封从公共邮件商寄过来的邮件,看看邮件源代码。不过后面我们会借助第三方的软件来帮忙发送邮件,所以我们这里点到即止吧。
现在已经可以正常发邮件了,还缺点啥呢?两点:1、如果我想用如foxmail之类的邮件客户端来远程连接到本邮件服务器发邮件,要怎么做呢?毕竟前面的配置,限制了mynetworks,但我们邮件客户端这头的IP可是不定的啊。2、通过TCP来连接这个SMTP服务器发邮件,这中间的数据传输都是明文的,如果邮件内容很私密很重要,就会担心被窃听,怎么办呢?我打算在下一篇文章里了解怎么解决这两个问题。
<br />
<br />
<br />