美文网首页
从零开始学习邮件系统搭建(一)——正经发出一封邮件

从零开始学习邮件系统搭建(一)——正经发出一封邮件

作者: Jinglever | 来源:发表于2017-04-12 19:27 被阅读0次

    前言
      出于工作原因,需要学习搭建邮件系统,为避免日后生疏最后忘了,这里会记录我整个学习的过程,包括中途遇到的不解之处,当然也会有一个完整的搭建成品的步骤。
      网上可以搜到不少关于搭建邮件系统的文章,质量参差不齐,我本人更希望自己能了解到更多,而非照着步骤啪啪啪搭起来就算了,以后遇到问题能比较有效率地寻找解决方案。
      我一边学一边写,会有理解错的,后面发现之后会回头修正。欢迎留言指教。

    涉及到概念(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,表示该主机在域名树的位置。

    安装一些软件

    说明:下面安装的软件并非全是必要的,为了后面的学习,先装好了。

    1. 安装postfix:yum install postfix。我执行后发现是升级原有的版本。设置开机启动chkconfig postfix on
    2. 删除原有的sendmail:rpm -e sendmail or yum remove sendmail。本ECS没安装sendmail。
    3. 安装Cyrus SASL相关的软件:yum install cyrus-sasl cyrus-sasl-plain cyrus-sasl-md5 cyrus-sase-sql
    4. 安装dovecot:yum install dovecot。我安装的版本是1:2.0.9-22.el6。
    5. 安装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.简直迫不及待啊):
    1. 启动postfix:/etc/init.d/postfix start;
    2. netstat -tlnp |grep 25;可以看到
    3. yum install telnet; 我发现ECS还没安装telnet。
    4. 用telnet跟postfix交互(不妨tail -f /var/log/maillog看输出什么log,有时候很有用)
    5. 检查一下收件箱,收到啦!虽然是在垃圾箱里。是的,只需要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
    • 可以使用多行来表示同一个设定值,只要前一行末尾有逗号,下一行开头有空白字符就行。所以前面说第一行的开头处不要有空白字符。
    • 如果对同一个设定项重复做了配置,以后面写的配置为准。
    1. 好习惯:cd /etc/postfix; cp main.cf main.cf.bk;
    2. vim main.cfps.如果没能搜到,就在文件末尾添加即可。下面所有的设定项可以通过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
    
    1. 由于mynetworks设置了hash:/etc/postfix/access,所以需要执行postmap hash:/etc/postfix/access来生成对应的哈希库/etc/postfix/access.db
    2. /etc/init.d/postfix restart #使配置文件生效 因为改动了inet_protocols和inet_interfaces,所以需要restart,否则reload即可
    3. 设置DNS解析,增加两条A记录,之所以其中一个主机记录写mail,因为前面$myhostname写了mail.howard.org啊。
    4. 设置DNS解析,增加一条MX记录,记录值跟$myhostname一致。因为只有一条MX记录,所以MX优先级是多少不重要啦。
    5. 设置DNS解析,增加一条SPF记录,其实是按照SPF格式增加一条TXT记录,有助于提高服务器IP信誉度。


    6. 发工单跟阿里云请求对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_restrictionssmtpd_client_restrictionssmtpd_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_xxxreject_xxx的区别哈。这个设定项被用得比较多,对于版本号小于2.10的postfix,还有需要注意设置不当导致relay open的问题,参考《Postfix SMTP relay and access control》

    搭配上面这三个设定项的,一般是mynetworksmydestination。所以这两项的设定极其重要。

    正经地发送一封成熟的邮件

    行文至此,对于一个内部使用的SMTP服务器已经完成,可以通过mynetworks设置只允许内部使用。那么下面来正经地发一封邮件,还是用telnet,顺便看一下有哪些常见的格式。

    正经发一封邮件

    最后

    上面那个截图,用的都是英文,如果要用中文的话,需要指定编码格式之类,挺烦的,不妨打开一封从公共邮件商寄过来的邮件,看看邮件源代码。不过后面我们会借助第三方的软件来帮忙发送邮件,所以我们这里点到即止吧。
      现在已经可以正常发邮件了,还缺点啥呢?两点:1、如果我想用如foxmail之类的邮件客户端来远程连接到本邮件服务器发邮件,要怎么做呢?毕竟前面的配置,限制了mynetworks,但我们邮件客户端这头的IP可是不定的啊。2、通过TCP来连接这个SMTP服务器发邮件,这中间的数据传输都是明文的,如果邮件内容很私密很重要,就会担心被窃听,怎么办呢?我打算在下一篇文章里了解怎么解决这两个问题。

    <br />
    <br />
    <br />

    参考的文章:
    1. 鸟哥的Linux私房菜(第二十二章)
    2. 从零开始邮件服务器搭建

    相关文章

      网友评论

          本文标题:从零开始学习邮件系统搭建(一)——正经发出一封邮件

          本文链接:https://www.haomeiwen.com/subject/ufjxattx.html