当前位置: 代码迷 >> 综合 >> 2020-12-02 Centos8.2邮件服务器搭建攻略!一文吃透Postfix+Dovecot+MySQL!
  详细解决方案

2020-12-02 Centos8.2邮件服务器搭建攻略!一文吃透Postfix+Dovecot+MySQL!

热度:62   发布时间:2023-12-15 15:12:47.0
1.jpg

今天来聊聊Linux邮件服务器的搭建,本以为这不是一件很困难的事情,毕竟电子邮件这种高度成熟的技术应该有很容易部属吧,上手后才发现原来坑还真不少。本方案以主流的postfix + dovacot为基础,其中postfix用作smtp,dovecot用作pop3(或imap),关于smtp和pop3这些基础原理就不多讨论了,大家应该对此是耳熟能详的。

  1. 工作模式
    postfix构建的smtp系统至少有两种工作模式,第一种是利用本地真实账号进行邮件收发,比如本地Linux系统有用户root或someone,那么就有root@example.com和someone@example.com两个email地址。 第二种相对复杂一些,为了管理的方便和系统安全,postfix的用户管理采用了虚拟用户方式,即postfix单独设立了许多用户,他们各自在系统中映射有独立的硬盘空间。但同时这些用户又跟本地Linux系统内固有的真实账号没有关联。本文所有讨论就是建立在这种模式下的,值得注意的是,这两种工作模式的部署方法差异极大,在参考网上教程的时候,首先要确认它是建立在哪个模式下的,否则容易张冠李戴,出现很多令人头疼的问题。

  2. 运行流程
    对于电子邮件,我们有一个可能存在的误区是,会将smtp和pop3按照字面的意思去理解,即smtp代表发件服务器,pop3是收件服务器。其实并不完全是这样。下面是一封电子邮件在网上的简单交互流程:

发件人:me@qq.com 收件人:you@gmail.comme@qq.com 用邮件客户端(比如outlook)写了一封邮件给you@gmail.com,点下发送按钮后,邮件首先会发送到smtp.qq.com
smtp.qq.com 检索到这封邮件的收件人域名是gmail.com,于是通过互联网(WAN)将邮件发送到smtp.gmail.com
smtp.gmail.com确认收下邮件后,将它转存到邮件服务器的硬盘中待收。
请注意,通过观察以上流程,你会发现smtp服务器其实身兼了 “收、发” 两个功能,在整个流程中, 对于smtp.qq.com而言,是发送。 而从smtp.gmail.com的角度来看,则是接收。那么,咱们平时经常说起的 “收件服务器pop3” 又是怎么回事呢,整个流程似乎看不到它的身影?

pop3(或imap服务器,与之性质相同)更多的是起一个中转作用,它将存储在邮件服务器硬盘中的邮件转移回邮件客户端(user agent),换句话说它只负责从邮件服务器到邮件客户端这段路径,而邮件在广域网上的收发则是smtp要做的事,与pop3并没有关系。pop3与imap的区别是,pop3将邮件拉回本地后,即与服务器无关了。imap更先进一些,它能做到实时将你在邮件客户端的操作反馈回邮件服务器,比如:删除邮件,标记已读等,服务器上的邮件也会做相应的动作。所以无论从浏览器登录邮箱或者客户端软件登录邮箱,看到的邮件以及状态都是一致的。

pop3-smtp-imap-difference-00.jpg

基础原理就这么点,下面开始进入实战环节。

一、 准备工作
前面说过,本文以虚拟邮件用户为基础,创建虚拟用户有很多方法,其中最容易也最易于扩展的方式莫过于采用数据库来管理邮件客户,比如说以后如果需要扩展Web Mail功能,也容易与之无缝衔接。

本文选用Centos下最常见的MariaDB作为数据库,它与MySQL是完全兼容的,关于MariaDB的部署不在本文讨论之内,网上有很多教程,也非常简单。
既然进入实战了,必须要先把我的运行环境做一个说明:
OS : Centos 8.2
DB : MariaDB 10.3.17
Postfix 3.3.1
Dovecot 2.3.8
编辑器:nano
最后,文中所有出现example.com的地方,需要换成你自己的域名。文中所有出现nano的地方表达的意思都是修改这个文件。

准备工作部分我们要做三件事:

  1. 建立数据库
  2. 修改DNS设置
  3. 获取域名证书

一步一步来,我们首先来创建数据库(默认你已经装好了MySQL或MariaDB):

  1. 建库mysql -u root -p 密码
    进入mysql,然后执行:
create database servermail;
GRANT SELECT ON servermail.* TO 'usermail'@'127.0.0.1' IDENTIFIED BY 'mailpassword';
FLUSH PRIVILEGES;
USE servermail;
  1. 建表
CREATE TABLE `virtual_domains` (
`id`  INT NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `virtual_users` (
`id` INT NOT NULL AUTO_INCREMENT,
`domain_id` INT NOT NULL,
`password` VARCHAR(106) NOT NULL,
`email` VARCHAR(120) NOT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `email` (`email`),
FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `virtual_aliases` (
`id` INT NOT NULL AUTO_INCREMENT,
`domain_id` INT NOT NULL,
`source` varchar(100) NOT NULL,
`destination` varchar(100) NOT NULL,
PRIMARY KEY (`id`),
FOREIGN KEY (domain_id) REFERENCES virtual_domains(id) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  1. 生成一些初始数据
    创建域名:
INSERT INTO `servermail`.`virtual_domains`
(`id` ,`name`)
VALUES
('1', 'example.com'),
('2', 'mail.example.com');

生成两个初始email账号:
其中,dmarck-reports@example.com是将来设置DKIM需要用到的,这是后话先别管它,创建了再说:

INSERT INTO `servermail`.`virtual_users`
(`id`, `domain_id`, `password` , `email`)
VALUES
('1', '1', ENCRYPT('密码', CONCAT('$6$', SUBSTRING(SHA(RAND()), -16))), 'webmaster@example.com'),
('2', '1', ENCRYPT('密码', CONCAT('$6$', SUBSTRING(SHA(RAND()), -16))), 'dmarck-reports@example.com');

生成一个别名:

INSERT INTO `servermail`.`virtual_aliases`
(`id`, `domain_id`, `source`, `destination`)
VALUES
('1', '1', 'boss@example.com', 'webmaster@example.com');

至此,数据库的基本操作完毕。

二、修改DNS服务器
这需要登录你的域名管理界面,做几个简单的操作:

  1. 添加一个A记录,如图:

    image.png
  2. 添加一个MX记录,如图:

    image.png

每个域名提供商的操作界面有可能不太一样,但都是大同小异的。

接下来我们需要为邮件服务器获取域名证书,抛开安全性不谈,纯粹从装X的角度而言,这玩意就如同https一样,这年头你的网站还穿着http出来见人真的就有点丢人了,所以证书几乎是必备的。
域名证书有很多获取方式,有收费的也有免费的,国内有一家通过网页申请的,可参见我写的另一篇博文:https://www.jianshu.com/p/b4b5ca1d88d6

今天我们采用另一个方法,利用Letsencrypt在线生成,这个方案的好处是不用等待,证书立等可取,而且流程相对也比较简单。
因为证书必须要对应一个真实存在的网站,所以我们还必须先装装样子,安装一个nginx,还好Letsencrypt对网站的实际内容没什么要求,nginx默认的初始页面也是可以的。

  1. 首先安装nginxdnf -y install nginx
    装好之后到浏览器输入你的域名,如果出现nginx欢迎页面,说明安装成功。

  2. 然后安装certbotdnf -y install certbot python3-certbot-nginx

  3. 生成证书certbot certonly -a nginx --agree-tos --staple-ocsp --email webmaster@example.com -d mail.example.com
    注意,联系人电子邮件不一定非要本域名下的,随便填一个也行。

如果没有问题,系统将回显如下:

  • Congratulations! Your certificate and chain have been saved at:
    /etc/letsencrypt/live/mail.example.com/fullchain.pem
    Your key file has been saved at:
    /etc/letsencrypt/live/mail.example.com/privkey.pem
    Your cert will expire on 2021-02-27.

这里面包括了公私钥的存放地址以及有效期之类的信息。

至此,准备工作全部完成了,下面进入我们的核心部署环节!

三、Postfix篇

  1. nano main.cf
    main.cf是一个超级复杂的配置文件,不过大多数都是注释。限于篇幅我就不把整个文件贴出来了,你可以将源文件完全清空,然后将以下内容原封不动地复制进去,保存即可。注意所有出现example.com的地方,需要换成你自己的域名(后面的所有配置文件都是如此,接下来我就不再强调了)
mydomain = example.com
myorigin = mail.example.com
myhostname = mail.example.com
mydestination = \$mydomain
inet_interfaces = all
message_size_limit=52428800
mailbox_size_limit=0
smtpd_tls_cert_file=/etc/letsencrypt/live/mail.example.com/fullchain.pem
smtpd_tls_key_file=/etc/letsencrypt/live/mail.example.com/privkey.pem
smtpd_use_tls=yes
smtpd_tls_auth_only = yes
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
smtpd_recipient_restrictions = permit_sasl_authenticated, permit_mynetworks, reject_unauth_destination
smtpd_banner = $myhostname ESMTP \$mail_name (Ubuntu)
biff = no
append_dot_mydomain = no
readme_directory = no
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
relayhost =
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mailbox_size_limit = 0
recipient_delimiter = +
virtual_transport = lmtp:unix:private/dovecot-lmtp
virtual_mailbox_domains = mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
virtual_mailbox_maps = mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
virtual_alias_maps = mysql:/etc/postfix/mysql-virtual-alias-maps.cf

话说整个main.cf有相当多的设置项目,真正钻进去研究透彻需要花费大量时间,对于上述设置我只谈几个我已经看明白的:mydomain = example.com
我的域名是example.commyorigin = example.com
myorigin参数指定默认域名,该默认域名将附加到没有@domain部分的发件人和收件人地址。 需要将其值更改为example.com,因此邮件服务器上的发件人将具有@example.com地址。myhostname = mail.example.com
与其他SMTP服务器通信时,Postfix使用此主机名来标识自己。 但是,操作系统主机名可能会更改,因此,最好直接在配置文件中设好。mydestination = \$mydomain
mydestination参数指定服务器将其视为自身最终目的地的域列表。这个听起来有点拗口,说白了就是别人给您发信,哪些信你是接受的。
比如12345@qq.com给您发一封信,收件人是webmaster@example.com,接受,对应的就是$mydomain
注意:此处如果设错了,你可以给别人发信,但是别人给你发的信你会收不到。
smtpd_tls_cert_file=/etc/letsencrypt/live/mail.example.com/fullchain.pem
smtpd_tls_key_file=/etc/letsencrypt/live/mail.example.com/privkey.pem
这两个是刚才我们生成的证书。message_size_limit=52428800mailbox_size_limit=0
这两个设置比较实用,是指附件最大允许容量和邮箱的总容量,这里我们把最大附件设为50MB,邮箱总容量则不设限制(0)

virtual_transport = lmtp:unix:private/dovecot-lmtp
这是一条核心设置,表示通过lmtp (Local Mail Transfer Protocol)协议,将本地邮件传递到dovecot中,相当于告诉Postfix,将从广域网收到的邮件,最终传递到dovecot能控制的地方,以便我们用pop3或imap下载到邮件客户端。

virtual_mailbox_domains = mysql:/etc/postfix/mysql-virtual-mailbox-domains.cfvirtual_mailbox_maps = mysql:/etc/postfix/mysql-virtual-mailbox-maps.cfvirtual_alias_maps = mysql:/etc/postfix/mysql-virtual-alias-maps.cf
这三行与数据库有关,表示邮箱的虚拟域,用户映射关系和别名映射关系,分别由哪三个SQL脚本做查询动作。

  1. 接下来我们就要创建这3个SQL脚本了,尽管这不是标准的SQL脚本,但稍懂一点SQL语句的朋友一定也可以看出其中的关联,这里也不再展开讨论了:

nano /etc/postfix/mysql-virtual-mailbox-domains.cf

user = usermail
password = mailpassword
hosts = 127.0.0.1
dbname = servermail
query = SELECT 1 FROM virtual_domains WHERE name='%s'

nano /etc/postfix/mysql-virtual-mailbox-maps.cf

user = usermail
password = mailpassword
hosts = 127.0.0.1
dbname = servermail
query = SELECT 1 FROM virtual_users WHERE email='%s'

nano /etc/postfix/mysql-virtual-alias-maps.cf

user = usermail
password = mailpassword
hosts = 127.0.0.1
dbname = servermail
query = SELECT destination FROM virtual_aliases WHERE source='%s'

创建好之后,用systemctl restart postfix 重启一次postfix,然后测试一下刚才建立的三个脚本。postmap -q example.com mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
正确的话,应该返回:1

postmap -q rockage@example.com mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
正确的话,应该返回:1

postmap -q boss@example.com mysql:/etc/postfix/mysql-virtual-alias-maps.cf
正确的话,应该返回:webmaster@example.com

  1. nano /etc/postfix/master.cf
    这也是一个巨复杂的配置文件,老规矩,先彻底清空,然后原封不动把以下内容粘贴进去:
smtp      inet  n       -       n       -       -       smtpd
submission inet n       -       -       -       -       smtpd-o syslog_name=postfix/submission-o smtpd_tls_security_level=encrypt-o smtpd_sasl_auth_enable=yes-o smtpd_client_restrictions=permit_sasl_authenticated,reject
smtps     inet  n       -       y       -       -       smtpd-o syslog_name=postfix/smtps-o smtpd_tls_wrappermode=yes-o smtpd_sasl_auth_enable=yes-o smtpd_relay_restrictions=permit_sasl_authenticated,reject-o smtpd_recipient_restrictions=permit_mynetworks,permit_sasl_authenticated,reject-o smtpd_sasl_type=dovecot-o smtpd_sasl_path=private/auth
pickup    unix  n       -       n       60      1       pickup
cleanup   unix  n       -       n       -       0       cleanup
qmgr      unix  n       -       n       300     1       qmgr
tlsmgr    unix  -       -       n       1000?   1       tlsmgr
rewrite   unix  -       -       n       -       -       trivial-rewrite
bounce    unix  -       -       n       -       0       bounce
defer     unix  -       -       n       -       0       bounce
trace     unix  -       -       n       -       0       bounce
verify    unix  -       -       n       -       1       verify
flush     unix  n       -       n       1000?   0       flush
proxymap  unix  -       -       n       -       -       proxymap
proxywrite unix -       -       n       -       1       proxymap
smtp      unix  -       -       n       -       -       smtp
relay     unix  -       -       n       -       -       smtp-o syslog_name=postfix/$service_name
showq     unix  n       -       n       -       -       showq
error     unix  -       -       n       -       -       error
retry     unix  -       -       n       -       -       error
discard   unix  -       -       n       -       -       discard
local     unix  -       n       n       -       -       local
virtual   unix  -       n       n       -       -       virtual
lmtp      unix  -       -       n       -       -       lmtp
anvil     unix  -       -       n       -       1       anvil
scache    unix  -       -       n       -       1       scache

master.cf这个文件主要掌管着postfix的各种服务,
这个文件的奇特之处是,缩进敏感!你会看到很多顶格的比如:submission inet n - - - - smtpdsmtps inet n - y - - smtpd
这样的行。
同时他们下面又有一些-o syslog_name=postfix/submission-o smtpd_tls_security_level=encrypt
这样的行,所不同的是-o前面多了两空格,这是何意?
这两个空格不能删除,否则会报错,这就是所谓的缩进敏感(和Python有点像),
顶格的那些行,表示服务,带空格的那些行,表示该服务下的具体设置。
可以看到我们开启了smtp,smtps和submission这三个服务,分别对应端口25,465和587,功能分别是:传统smtp服务,加密的smtp服务,submission也是一个加密服务,smtps 和 submission从功能上而言极其类似,其端口分别是465和587,关于这两个端口在历史上还有一些故事,感兴趣的可以自行搜索,这似乎是一个历史遗留问题,而不是技术问题。题外话我们暂且不管,反正两个都开通就是了。

至此,Postfix的设置工作就完成了,你可以通过以下命令用它发一封最简单的邮件,看看能否收到?echo "Hello world!" | sendmail 你的qq@qq.com

第三篇:Dovecot

  1. 安装dovecotdnf -y install dovecot dovecot-mysql

  2. nano dovecot.conf

protocols = imap lmtp
listen = *, ::
mail_max_userip_connections = 50
!include conf.d/*.conf
!include_try local.conf

这其实也是一个很复杂的配置文件,但是注释去掉之后也没什么内容。protocols = imap lmtp
表示支持的协议,这里我们只开通了imap和lmtp,如果你需要pop3的话,加上去即可。
注意:此处的lmtp必须打开,这是dovecot和postfix交流的通道。

listen = *, ::
表示监听所有地址,*表示ipv4,::表示ipv6,如果你没有启用ipv6,直接listen = *也行

mail_max_userip_connections = 50
设置一个合理的数值,否则会报mail_max_userip_connections 错误。

!include conf.d/*.conf!include_try local.conf
没有太大的作用,表示此处将包含conf.d文件夹下的所有配置文件。

  1. nano /etc/dovecot/conf.d/10-mail.conf
mail_location = maildir:/var/mail/vhosts/%d/%n
mail_privileged_group = mail

这个文件的原始体积也很大,但删掉注释之后只有2行,它设置的是邮箱对应硬盘的具体位置,%d表示域名,%n表示用户名,比如在本文中,webmaster@example.com的物理位置在:
/var/mail/vhost/example.com/webmaster

  1. 创建用户组和用户:groupadd -g 5000 vmailuseradd -g vmail -u 5000 vmail -d /var/mail
    创建一个用户组vmail并添加一个用户vmail,id为5000,
    用户vmail属于用户组vmail。起始目录为 /var/mail

  2. 创建域名目录:mkdir -p /var/mail/vhosts/example.com

  3. 修改/var/mail和/etc/dovecot的拥有者:chown -R vmail:vmail /var/mailchown -R vmail:dovecot /etc/dovecotchmod -R o-rwx /etc/dovecot

  4. 查看权限ls -ld /var/mail
    如果显示:

lrwxrwxrwx. 1 vmail vmail 10 May 11 2019 /var/mail -> spool/mail

说明权限设置成功,请注意:这一步非常重要,如果该目录持有者不是vmail的话,dovecot在收到邮件后无法保存,将会报错。

  1. nano /etc/dovecot/conf.d/10-auth.conf
disable_plaintext_auth = yes
auth_mechanisms = plain login
!include auth-sql.conf.ext

disable_plaintext_auth = yes
表示登录密码必须加密,否则不通过,我们这个方案是全盘TLS加密的,因此此处把他打开,不允许明文密码。

auth_mechanisms = plain login
授权机制,表示允许明文密码授权和login密码授权,为啥此处我们选择明文密码呢?此明文非彼明文,此处的明文是指在SSL/TLS加密通道中的明文,因为本身就已经加密过了,所以我们不需要担心密码泄露问题,而此处的login方式,是专门为outlook准备的。此处可以选择cram-md5,专门用于加密密码,但本身我们已经是加密通道了,因此没有必要画蛇添足。

!include auth-sql.conf.ext
启用MySQL授权

  1. nano /etc/dovecot/conf.d/auth-sql.conf.ext
passdb {driver = sqlargs = /etc/dovecot/dovecot-sql.conf.ext
}
userdb {driver = staticargs = uid=vmail gid=vmail home=/var/mail/vhosts/%d/%n
}

当我们通过邮件客户端登录咱们的pop3(或imap)服务器准备取回邮件时,需要进行密码核对和用户名核对,那么dovecot是如何实现这个授权的呢?
这个文件指定dovecot是如何获取用户密码和用户资料的,密码部分采用sql脚本方式。用户数据采用static (静态) 方式,通常,SQL数据库也可以做这件事,也可以通过它得到用户的UID,GID和主目录。但此处如果我们仅使用静态UID和GID,并且可以使用模板指定主目录,则可以改用静态方式,它会比SQL方式略快一些。

  1. nano /etc/dovecot/dovecot-sql.conf.ext
driver = mysql
connect = host=127.0.0.1 dbname=servermail user=usermail password=mailpassword
default_pass_scheme = SHA512-CRYPT
password_query = SELECT email as user, password FROM virtual_users WHERE email='%u';

这个文件就是刚才我们说的SQL方式获取用户密码的脚本,很简单只有一句,相信大家都能看得懂。
说句题外话,dovecot只能识别user和password字段,如果你的初始数据库用的并不是这两个字段的话,必须是用as修饰符强制将它们转换成user和password。

  1. nano /etc/dovecot/conf.d/10-master.conf
service lmtp {unix_listener /var/spool/postfix/private/dovecot-lmtp {mode = 0600user = postfixgroup = postfix}
}service auth {unix_listener /var/spool/postfix/private/auth {mode = 0666user = postfixgroup = postfix}unix_listener auth-userdb {mode = 0600user = vmail}user = dovecot
}service auth-worker {user = vmail
}

这个文件主要作用是为了打通dovecot和postfix的关联,授权postfix通过lmtp协议访问属于dovecot的地盘,访问权限是0600,表示有读写权限,但无执行权限,差不多就这意思,就不赘述了。这个文件的源文件也比较庞杂,里面对多个协议都有设定,但是如果你全部把它们删了也没关系,等于采用默认设置,比如imap的端口默认是993等,但如果你有一些特殊要求比如说需要使用别的非常规端口之类的,建议你还是是用源文件,不要采用我这个精简版。

  1. nano /etc/dovecot/conf.d/10-ssl.conf
ssl = required
ssl_cert = </etc/letsencrypt/live/mail.example.com/fullchain.pem
ssl_key = </etc/letsencrypt/live/mail.example.com/privkey.pem
ssl_cipher_list = PROFILE=SYSTEM

这个配置文件主要是设置SSL,ssl = required
表示强制使用SSL加密通道,从密码到邮件内容全部加密,这就是前面咱们在“授权机制”那个步骤允许使用的plain(明文密码)的原因了,因为整个通道都已经被加密了,明文密码走在加密通道里面也可以认为是安全的,后面两行指定了我们在准备步骤生成的证书存放位置。请注意,这两个文件与Postfix里的设置是完全一致的,也就是说Postfix和Dovecot采用的是同一个证书,不仅如此,实际上这本证书还可以用于nginx用于加密你的Web网站,开通https等。

  1. /etc/dovecot/conf.d/15-mailboxes.conf
namespace inbox {inbox = yesmailbox Drafts {auto = createspecial_use = \Drafts}mailbox Junk {auto = createspecial_use = \Junk}mailbox Trash {auto = createspecial_use = \Trash}mailbox Sent {auto = createspecial_use = \Sent}mailbox "Sent Messages" {auto = createspecial_use = \Sent}
}

这个文件是用来指定收件箱的命名空间的,auto = create表示当这些邮箱都没有的时候,就自动创建它,这里指定的都是常规的,比如收件箱,已发送,垃圾箱,已删除等等,如果需要别的种类,请自行研究。

四. 验证
终于快大功告成了!
现在我们需要验证一下服务器到底设置成功没有,首先重启一下postfix和dovecot:stystemctl restart postfix dovecot
查看日志的方法是:tail -f /var/log/maillog
请注意:postfix和dovecot的日志是合并在一起的,两者的变化都会记录在这个文件里。

  1. 初级判断:
    本文中,我们开通了smtp, smtps, imaps, lmtp, submission 这四个服务,分别对应端口:

25/tcp smtp :负责广域网邮件传递,非加密
465/tcp smtps :同上,加密
143/tcp imap :负责将服务器的邮件传回邮件服务端,非加密
993/tcp imaps :同上,加密
587/tcp submission :同上,加密
lmtp :为内部传输服务,不对外,无端口号

最简单的,我们可以用:netstat -tunlp
看看这些端口起来了没有,
如果显示这样:

Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State PID/Program name
tcp 0 0 0.0.0.0:25 0.0.0.0:* LISTEN 6717/master
tcp 0 0 0.0.0.0:465 0.0.0.0:* LISTEN 6717/master
tcp 0 0 0.0.0.0:143 0.0.0.0:* LISTEN 6729/dovecot
tcp 0 0 0.0.0.0:993 0.0.0.0:* LISTEN 6729/dovecot
tcp 0 0 0.0.0.0:587 0.0.0.0:* LISTEN 6717/master

说明OK,如果指定的端口号不存在,那么说明服务有问题,需要排查。
另外一个更高端的端口扫描器叫做nmap,也可以实现同样的功能,首先安装它:dng -y install nmap
使用很简单:nmap mail.example.com

  1. 测试连通性:
    如果端口都存在,说明大毛病没有了,我们可以用telnet测一下,
    命令很简单,比如我们想测一下993端口:telnet mail.example.com 993
    如果返回:

Trying 123.123.123.123...
Connected to mail.example.com.
Escape character is '^]'.

说明没有大问题,输入quit或ctrl+c,退出。
如果返回:

Trying 123.123.123.123...
telnet: connect to address 204.44.70.25: Connection refused

则说明这个端口有毛病,需要排查。

  1. 高端测试
    利用openssl命令,我们可以对这些服务进行更深层次的检测。
    例如我们想查一下服务器的993端口(imap)加密通道到底正不正常:openssl s_client -connect mail.example.com:993
    如果返回一大堆类似密文的东西,说明基本OK,往上翻,如果出现类似这样的信息:

depth=1 C = US, O = Let's Encrypt, CN = Let's Encrypt Authority X3
verify return:1
depth=0 CN = mail.example.com

说明证书是OK的,由Let's Encrypt公司颁发,域名也跟你的实际域名对得上,说明SSL这一块大问题没有。

如果输入了这条命令毫无反应,或报错,或者域名不是你的域名,你就要仔细排查你的域名证书是不是有问题了,因为dovecot装好之后本身有一本默认证书,但那不是你的域名的,尽管看上去好像没毛病,但实际那本证书是无法使用的。

  1. 常见错误
    问题: Error: namespace configuration error: inbox=yes namespace missingnano /etc/dovecot/conf.d/15-mailboxes.conf
namespace inbox {inbox = yes #添加这一行,注意位置一定别搞错,只能加在这里mailbox Drafts {auto = createspecial_use = \Drafts}

问题:Recipient address rejected: User unknown in local recipient tablenano /etc/postfix/main.cf :

mydestination = \$mydomain

问题: Error: Diffie-Hellman key exchange requested, but no DH parameters provided. Set ssh_dh=</path/to/dh.pemnano /etc/dovecot/dovecot.conf
去掉pop3:

protocols = imap lmtp

pop3需要强制使用迪菲-赫爾曼密鑰(简称DH),因此你需要自己去建一个,相当耗时且麻烦,所以本文中干脆就不用pop3了,imap现在已经是主流协议了,而且功能更强大。

其他认证类问题:
基本上问题出在SSL,各种乱七八糟的报错都有,这里就不赘述了,实在不行就从源头开始查,从生成证书那一步就开始认真核对,比如输入域名的时候有没有敲错之类。

更诡异的问题:
大家不一定都能碰到,在此我只做一个记录:
所有服务都运行正常,openssl测试也通过了,但是当我用客户端进行设置的时候就是报ssl错误,百思不得其解,更诡异的是,日志丝毫没有反应,无论我在邮件客户端怎么操作,服务器这边就是毫无反应,关键是连报错都没有,排查工作根本无从谈起。折腾了一晚上,第二天自己好了!这更让人窝火,通过回忆,我找出了问题所在:我在进行客户端测试的时候忘记关FQ开关... 因为采用的是tun2socks方式全局FQ,我猜测某些数据经过多层跳板是不是无法最终发送到服务器导致?

目前的问题:
Mozilla Thunderbird客户端无法使用,Foxmail却很完美,目前我也没有招,搜遍整个google,貌似不止我一个,初步判断是Thunderbird对加密证书有别的要求,反正平时我也是用Foxmail,这个问题先搁一边,以后有时间再慢慢研究。

关于防火墙:
firewalld和iptables本人不会用,只贴一个nft的简单版,放行了本文中所有涉及到的端口,关于端口放行的问题,不麻烦,请自行百度谷歌。
我的简单防火墙脚本:

flush ruleset
table inet filter {chain input {type filter hook input priority 0; policy drop;ct state established,related acceptct state invalid dropiif lo acceptip protocol icmp icmp type { destination-unreachable, router-solicitation, router-advertisement, time-exceeded, parameter-problem } acceptip protocol igmp accepttcp dport { ssh, http, https,smtp, smtps, imap, imaps, 993 } accept}chain forward {type filter hook forward priority 0; policy drop;}chain output {type filter hook output priority 0; policy accept;}
}

使用方法,先把上面的粘贴复制成一个文件,然后nft -f 文件名,即可。

关于客户端设置:
以Foxmail为例,如图:

image.png
image.png

结束了吗?
其实才刚开始,后面的事情还多着呢,还需要给我们的邮件服务器设置WEB Mail,设置SPF、DKIM、DMARC等等等等,SPF和DKIM可以参考我的前一篇博文:https://www.jianshu.com/p/736867371d28
如何提高邮件服务器的“受尊重度”是一门大学问,而且还不怎么和技术直接挂钩,非常不省心,我的邮件服务器至今也没进得了gmail的法眼,尽管可以通过Postmark等第三方smtp代发机构解决这个难题,但如果大家有什么好方法让我们理直气壮被gmail认可的话,欢迎留言告知,交流,感谢!!

  相关解决方案