×

从零开始邮件服务器搭建

96
YusenMeng
2017.03.03 14:33* 字数 3542

概念解释

SPF:Sender Policy Framework,直译过来就是发件人保证框架.出现的主要原因是SMTP协议的缺陷.XMTP中,发件人的邮箱地址是可以伪造的,因而SPF的出现就是防止伪造发件人.SPF的记录实际上就是DNS服务器上面的一个记录.如果邮件服务器收到了一封邮件,来自主机的IP是45.76.210.63并且生成发件人为yusengy@info.邮件服务器会去查询yusengy@info的SPF记录.如果SPF记录的IP为45.76.210.63,那么就认为是合法的,否则通常都会被退信.SPF记录一般如下.

SPF记录
SPF记录

DKIM:DomainKeys Identified Mail.功能目的与SPF相似,主要是让收件人可以通过加密解密的方式来得知发件人是否是真实的.原理就是在电子邮件的开头插入一段签名,然后接收方通过从DNS查询得到公钥以后,以进行验证,与SSH的公钥和密钥类似.
记录一般如下:

DKIM公钥
DKIM公钥

PTR:反向域名解析,可以通过发件人的IP地址反向得知域名,也是一种用以判断发件人是否正常的方式.

MUA:Mail User Agent.用户邮件代理,用户通过MUA接收发送邮件.例如Outlook, formail等.

MTA: Mail Transfer Protocol.邮件传输代理,是SMTP的一种实现.常用的MTA有sendmail,Postfix.本例中使用Postfix.MTA仅仅负责邮件的传输,MDA负责把接收到的邮件保存在硬盘中.

MDA: Mail Deliver Agent,邮件分发代理.负责将接收到的邮件保存在邮件服务器上.sendmail以及Postfix默认使用的MDA是procmail.

MRA: Mail Receive Agent,邮件接收代理,用来实现IMAP,POP3协议,负责与MUA交互,将服务器上的邮件通过IMAP以及POP3传输给客户端.本例中使用的MRA是Dovecot.

LMTP:Local Mail Transfer Protocol.本地邮件传输协议,是SMTP协议的扩展.本例中用与同一主机内邮件传输.

Postfix:一个开源的MTA服务器,负责通过SMTP协议管理发送到本机的邮件以及由本机向外发送的邮件.与sendMail相似.现今流行的服务器套件例如Zimbra,IRedMail内部都采用Postfix作为MTA.

Dovecot:一个开源的IMAP以及POP3服务器.通常工作是验证用户身份以及邮件的处理.

MySQL:存取用户信息,监听的域名信息,用户邮箱地址以及登录密码等.

邮件协议简述

SMTP

SMTP全称是Simple Mail Transfer Protocol,直译过来就是简单邮件传输协议, 由RFC5321定义.主要的工作就是把邮件信息从发件人的邮件服务器中传送到接收人的邮件服务器中,偶尔我们使用MUA来发送邮件的话,也承载传输用户邮件到发件服务器的功能, 因而也称作协议,顺带提一下,SMTP协议的出现是比HTTP还早的,最早在1982年中发布第一版的RFC.
因而因为提出的年代久远,所以在当时有许多问题都考虑不全面并且也有这许多的限制,例如SMTP要求信息内容需要是7位的ASCII来承载,因而我们在发送以及接受的时候,都需要将其编码解码.
另外,SMTP还存在一个问题就是没有对发送方进行一个身份验证,虽然在早期的互联网环境没有很大问题,但是在垃圾邮件满天飞的今天,这却是一个明显的短板.因而衍生出了SPF, DKIM, DMARC等一系列用来验证发件人身份的方法.

POP3

POP3,Post Office Protocol Version 3,直译就是邮局协议第三版,由RFC1939进行定义.这个协议的主要服务于用户管理邮件服务器上面的电子邮件.具体过程是:当外来邮件发送到收件人的邮件服务器上时,收件人可以使用邮件客户端连接邮件服务器,把未阅读的邮件服务器以及部分信息拉取回本地进行处理.在拉取的过程中,我们可以选择拉取完删除以及拉取完不删除两种方式,不过现在默认一般都是拉取完不删除,方便我们在其他的地方也能对邮件进行阅读以及管理.

IMAP

IMAP, Internet Message Access Protocol, 直译过来就是网络信息访问协议,可能和现在主流的翻译不太一致,不过能理解其意思就好.相对于pop3协议所有邮件的管理都需要下载下来进而管理,IMAP提供了用户远程访问邮件服务器的途径,因而通过IMAP,用户可以直接管理邮件服务器上的邮件.

工作原理

电子邮件架构

邮件原理
邮件原理

这里我们使用的MTA是Postfix, MRA是Dovecot.我们可以绘制出邮件服务器接受邮件,用户查收邮件以及用户发送邮件的过程.

邮件服务器接受收件

假设yusen@Foxmail.com发送一封邮件到yusen@yusengy.info中.

邮件服务器接受邮件
邮件服务器接受邮件

  1. foxmail.com服务器会通过DNS查询到yusengy.info的MX记录,然后找到Postfix所在的服务器所在.
  2. 邮件通过SMTP协议发送给Postfix.
  3. Postfix通过MySQL查询,yusengy.info是否是本机需要处理的域名.
  4. MySQL通过查询返回确认信息给Postfix.
  5. Postfix得到确认信息,把邮件传送给Dovecot,由Dovecot的LMTP服务来说投递工作.
  6. Dovecot把邮件的内容保存在对应的路径中.

用户查收邮件过程

用户查收邮件过程
用户查收邮件过程
  1. MUA向Dovecot请求IMAP连接.
  2. Dovecot发送自己的SSL证书.
  3. MUA发送用户的账号密码.
  4. Dovecot得到账号密码向MySQL查询.
  5. MySQL返回查询结果.
  6. 如果账号密码正确,Dovecot读取在改用户路径下的信息.
  7. 得到最新的邮件以及其他的一些统计信息.
  8. 通过IMAP协议发送给MUA.

用户发送邮件的过程

用户发送邮件过程.png-19.1kB
用户发送邮件过程.png-19.1kB
  1. MUA请求Postfix建立SMTP连接
  2. Postfix发送SSL证书给MUA
  3. MUA发送账号密码给Postfix,请求验证
  4. Postfix请求Dovecot验证账号密码.
  5. Dovecot请求MySQL查询结果
  6. MySQL返回查询结果.
  7. Dovecot返回Postfix账号密码验证结果.
  8. Postfix返回MUA账号密码验证结果.
  9. MUA使用SMTP协议发送邮件到Postfix.
  10. Postfix把邮件进行发送.接下来的步骤参考前面服务器查收邮件的过程.

邮件服务器搭建

根据上面的几个示意图,我们已经基本了解了邮件发送,接收的一般流程以及每个组件在其中的职责.了解清楚以后,邮件服务器的搭建则会变得简单了许多,明白其中每一步的作用以及缘由.

前期准备

设置hostname

CentOS7,可以通过hostnamectl set-hostname hostname命令设置hostname,并且修改hosts文件.这里域名是yusengy.info.

hostnamectl set-hostname mail.yusengy.info

为什么要设置hostname呢?因为一般情况下,Postfix在与其他的SMTP服务器进行通信的时候,会使用hostname来表名自己的身份.主机名有两种形式,单名字FQDN(Fully Qualified Domain Name).如果SMTP服务器不是用FQDN来表明身份,则有可能会被拒收.

修改防火墙开放端口

修改防火墙开发相应的端口,分别是25, 465, 587, 110, 995, 143, 993.

域名解析配置

域名解析配置
域名解析配置

安装Postfix, Dovecot以及数据库

由于Centos中默认的源没有MySQL,因而使用MariaDB代替,实际使用与MySQL一致.
首先更新系统yum update -y.把系统的一些组件更新到最新,然后需要修改一些CentOS的源设置,因为CentOS默认源里面的Postfix默认是不能和MariaDB协同工作的,因而我们需要安装扩展源里面的Postfix.
修改: /etc/yum.repos.d/CentOS-Base.repo

[base]
name=CentOS-$releasever - Base
exclude=postfix

#released updates
[updates]
name=CentOS-$releasever - Updates
exclude=postfix

修改完毕以后,我们让扩展源生效,并且安装我们所需要的应用以及服务.

yum --enablerepo=centosplus install postfix
yum install dovecot mariadb-server dovecot-mysql

接下来,我们配置MariaDB数据库来处理虚拟域名以及用户信息.

数据库配置

MariaDB的安装配置与MySQL有些许不同,MySQL是在安装的时候设置root的密码,而MariaDB则是在安装完毕后设置密码.
首先我们启动MariaDB.

systemctl enable mariadb.service
systemctl start mariadb.service

然后,我们进行一些初始化的配置.

mysql_secure_installation

输入mysql_secure_installation后,我们可以修改root用户的密码,禁止外部使用root登录,删除匿名账户以及删除test表等等.

数据库概览

创建mail数据库用以处理邮件相关的业务.并且创建邮件管理员.

GRANT SELECT, INSERT, UPDATE, DELETE ON mail.* TO 'mail_admin'@'localhost' IDENTIFIED BY 'mys123123';
GRANT SELECT, INSERT, UPDATE, DELETE ON mail.* TO 'mail_admin'@'localhost.localdomain' IDENTIFIED BY 'mys123123';
FLUSH PRIVILEGES;

这里的mys123123替换成自己的密码.我这里只是做示范使用,实际中应该使用强度更大的字符串作为密码.

数据库
数据库

mail数据库中一共有4个表,分别是虚拟域名, 邮件转发, 用户信息以及传输路径四个表..
表格
表格

虚拟域名表

该表存储的是本地服务器用来接收邮件的域名.


虚拟域名表表结构
虚拟域名表表结构

创建语句

CREATE TABLE domains (domain varchar(50) NOT NULL, PRIMARY KEY (domain) );

邮件转发

可以用来转发邮件.


邮件发送表表结构
邮件发送表表结构
CREATE TABLE forwardings (source varchar(80) NOT NULL, destination TEXT NOT NULL, PRIMARY KEY (source) );

用户表

用来存储用户的账号密码.这里密码使用加密的方式进行存储.


用户信息表结构
用户信息表结构
CREATE TABLE users (email varchar(80) NOT NULL, password varchar(20) NOT NULL, PRIMARY KEY (email) );

传输路径表

传输表可以用来指定邮件的传输路径.


传输表结构
传输表结构
CREATE TABLE transport ( domain varchar(128) NOT NULL default '', transport varchar(128) NOT NULL default '', UNIQUE KEY domain (domain) );

在配置完数据库以后,我们最好修改数据库的配置文件,只允许本地访问数据库,提高安全性.
修改: /etc/my.cnf

bind-address=127.0.0.1

如果数据库存储在其他的服务器上面,我们这里的bind-address地址在后面配置Postfix的时候需要相应的修改.不过为了安全起见,最好还是不要让数据库能够直接在外部可以访问.

配置完成了以后,我们则可以重启数据,使配置生效.

systemctl restart  mariadb.service

配置Postfix

配置完成了数据库以后,我们就需要配置Postfix,让其可以与MariaDB协同工作.因为Postfix寻找域名,用户账号等需要通过数据库来完成,但是其本身是不知道如何查询的,因而需要我们定制化.
下面的配置中,把mys123123替换成前面数据库管理员设置的密码

创建虚拟域名配置

创建:/etc/postfix/mysql-virtual_domains.cf

user = mail_admin
password = mys123123
dbname = mail
query = SELECT domain AS virtual FROM domains WHERE domain='%s'
hosts = 127.0.0.1

创建邮件转发配置

创建:/etc/postfix/mysql-virtual_forwardings.cf

user = mail_admin
password = mys123123
dbname = mail
query = SELECT destination FROM forwardings WHERE source='%s'
hosts = 127.0.0.1

创建虚拟邮箱配置

创建: /etc/postfix/mysql-virtual_mailboxes.cf

user = mail_admin
password = mys123123
dbname = mail
query = SELECT CONCAT(SUBSTRING_INDEX(email,'@',-1),'/',SUBSTRING_INDEX(email,'@',1),'/') FROM users WHERE email='%s'
hosts = 127.0.0.1

创建电子邮件与文件映射

创建:/etc/postfix/mysql-virtual_email2email.cf

user = mail_admin
password = mys123123
dbname = mail
query = SELECT email FROM users WHERE email='%s'
hosts = 127.0.0.1

创建完毕以后修改权限以及分配用户组.

chmod o= /etc/postfix/mysql-virtual_*.cf
chgrp postfix /etc/postfix/mysql-virtual_*.cf

同时,我们创建一个新的用户组以及用户,用来处理邮件.所有的虚拟邮箱,都会存在这个用户的home目录下.

groupadd -g 5000 vmail
useradd -g vmail -u 5000 vmail -d /home/vmail -m

接下来,我们对Postfix总体进行配置.把下面的mail.yusengy.info替换成你的hostname.如果你希望使用自己的SSL证书,则把/etc/pki/dovecot/private/dovecot.pem替换成你的证书路径.

postconf -e 'myhostname = mail.yusengy.info'
postconf -e 'mydestination = localhost, localhost.localdomain'
postconf -e 'mynetworks = 127.0.0.0/8'
postconf -e 'inet_interfaces = all'
postconf -e 'message_size_limit = 30720000'
postconf -e 'virtual_alias_domains ='
postconf -e 'virtual_alias_maps = proxy:mysql:/etc/postfix/mysql-virtual_forwardings.cf, mysql:/etc/postfix/mysql-virtual_email2email.cf'
postconf -e 'virtual_mailbox_domains = proxy:mysql:/etc/postfix/mysql-virtual_domains.cf'
postconf -e 'virtual_mailbox_maps = proxy:mysql:/etc/postfix/mysql-virtual_mailboxes.cf'
postconf -e 'virtual_mailbox_base = /home/vmail'
postconf -e 'virtual_uid_maps = static:5000'
postconf -e 'virtual_gid_maps = static:5000'
postconf -e 'smtpd_sasl_type = dovecot'
postconf -e 'smtpd_sasl_path = private/auth'
postconf -e 'smtpd_sasl_auth_enable = yes'
postconf -e 'broken_sasl_auth_clients = yes'
postconf -e 'smtpd_sasl_authenticated_header = yes'
postconf -e 'smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination'
postconf -e 'smtpd_use_tls = yes'
postconf -e 'smtpd_tls_cert_file = /etc/pki/dovecot/certs/dovecot.pem'
postconf -e 'smtpd_tls_key_file = /etc/pki/dovecot/private/dovecot.pem'
postconf -e 'virtual_create_maildirsize = yes'
postconf -e 'virtual_maildir_extended = yes'
postconf -e 'proxy_read_maps = $local_recipient_maps $mydestination $virtual_alias_maps $virtual_alias_domains $virtual_mailbox_maps $virtual_mailbox_domains $relay_recipient_maps $relay_domains $canonical_maps $sender_canonical_maps $recipient_canonical_maps $relocated_maps $transport_maps $mynetworks $virtual_mailbox_limit_maps'
postconf -e 'virtual_transport = dovecot'
postconf -e 'dovecot_destination_recipient_limit = 1'

修改Postfix配置,添加Dovecot服务.
修改:/etc/postfix/master.cf

dovecot   unix  -       n       n       -       -       pipe
    flags=DRhu user=vmail:vmail argv=/usr/libexec/dovecot/deliver -f ${sender} -d ${recipient}

submission以及smtps部分给反注释了,让这部分代码生效.

配置截图
配置截图

重启Postfix,至此,Postfix就基本配置好了.

systemctl enable postfix.service
systemctl start  postfix.service

Dovecot配置

修改:/etc/dovecot/dovecot.conf
这里把域名yusengy.info替换成自己配置的域名.

protocols = imap pop3
log_timestamp = "%Y-%m-%d %H:%M:%S "
mail_location = maildir:/home/vmail/%d/%n/Maildir

ssl_cert = </etc/pki/dovecot/certs/dovecot.pem
ssl_key = </etc/pki/dovecot/private/dovecot.pem

namespace {
    type = private
    separator = .
    prefix = INBOX.
    inbox = yes
}

service auth {
    unix_listener auth-master {
        mode = 0600
        user = vmail
    }

    unix_listener /var/spool/postfix/private/auth {
        mode = 0666
        user = postfix
        group = postfix
    }

user = root
}

service auth-worker {
    user = root
}

protocol lda {
    log_path = /home/vmail/dovecot-deliver.log
    auth_socket_path = /var/run/dovecot/auth-master
    postmaster_address = postmaster@yusengy.info
}

因为数据库存储有用户的账号密码信息,Dovecot的职责之一就是验证用户的账号密码,因而我们还需要创建一个配置文件以让Dovecot与数据库进行交互.
老惯例,这里也是把密码进行替换一下.
创建:/etc/dovecot/dovecot-sql.conf.ext

driver = mysql
connect = host=127.0.0.1 dbname=mail user=mail_admin password=mys123123
default_pass_scheme = CRYPT
password_query = SELECT email as user, password FROM users WHERE email='%u';

修改文件所属的用户组以及访问权限

chgrp dovecot /etc/dovecot/dovecot-sql.conf.ext
chmod o= /etc/dovecot/dovecot-sql.conf.ext

设置Dovecot在开启启动并且启动其服务

systemctl enable dovecot.service
systemctl start  dovecot.service

然后我们观察一下var/log/maillog,确定现在Dovecot没有错误

Dovecot日志
Dovecot日志

然后我们使用Telnet检测一下pop3服务是否正常.

yum install telnet
telnet localhost pop3

如果你看到的和我看到的差不多,那么说明是pop3服务是正常的.


pop3服务
pop3服务

检测Postfix

接下来则是检测Postfix是否运行正常.

telnet localhost 25
ehlo localhost

如果连接成功,同时输入EHLO命令有如下返回值,则Postfix是正常的.

Postfix测试
Postfix测试

创建用户

接下来,我们在MariaDB中的邮箱中加入新的用户,用作日常邮件的发送.
这里的用户密码不要使用明文存储.

USE mail;
INSERT INTO domains (domain) VALUES ('yusengy.info');
INSERT INTO users (email, password) VALUES ('yusen@yusengy.info', ENCRYPT('123123'));
quit

到这个时候,我们的邮件服务器基本就已经搭建完成了,接下来只要使用MUA进行连接,就能像正常的邮件服务器一样使用了.

MUA配置
MUA配置

尝试给自己的QQ邮箱发件看看.是不是收到了?


邮件截图
邮件截图

如果被拒收或者在垃圾箱中,说明我们的邮件发送服务器信誉不够,这个时候我们需要给我们的邮件服务器做一些条件,例如添加SPF, DKIM以及DMARC等,以提高邮件发送的成功率,当这些完成以后,基本能够直接发送到收件箱了.具体可以参考这一篇文章
邮件服务器添加SPF,DKIM,DMARC,PTR

至此,一个邮件服务器的搭建就完成了,通过这一系列的操作,是否对于电子邮件协议又有了进一步的理解呢?
如果没有在收件箱收到发送的邮件,可以在垃圾箱看看,或者看看是否退件了.这篇文章中我们没有谈到SPF, DKIM以及DMARC验证的配置,因而有可能会被QQ邮箱退件的,毕竟现实中的邮件服务器还需要一系列的配置,以提高送达率.这些我在后面会开一篇文章专门讲解.
如果MUA提示发件失败,那么我们可以查看一下日志,分别在/var/log/maillog以及/home/vmail/dovecot-deliver.log,找到对应的错误,然后回到文章相应的地方看看是否配置错了.如果还无法解决,可留言私信,我看到了会进行相应的解答.

Algorithm 4th
Web note ad 1