Linux邮件服务器搭建攻略(一文吃透Postfix+Dovecot+MySQL)

1.jpg

今天来聊聊Linux邮件服务器的搭建,本以为电子邮件这种高度成熟的技术应该很容易部署,上手后才发现原来坑还真不少。本方案以主流的postfix + dovacot为基础,其中postfix用作smtp,dovecot用作pop3(或imap)。

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

  2. 运行流程
    对于电子邮件,我们有可能存在的一个误区是,将smtp和pop3按照字面的意思去理解,即smtp只管发件,pop3则只负责收件。其实并不完全是这样。下面是一封电子邮件在互联网上的投递流程:

  • 发件人:[email protected] 收件人:[email protected]
    [email protected] 用邮件客户端(比如outlook)写了一封邮件给[email protected],点下发送按钮后,邮件首先会发送到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:创建数据库

  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账号:
其中,[email protected]是将来设置DKIM需要用到的,这是后话先别管它,创建了再说:

INSERT INTO `servermail`.`virtual_users`
(`id`, `domain_id`, `password` , `email`)
VALUES
('1', '1', ENCRYPT('密码', CONCAT('$6$', SUBSTRING(SHA(RAND()), -16))), '[email protected]'),
('2', '1', ENCRYPT('密码', CONCAT('$6$', SUBSTRING(SHA(RAND()), -16))), '[email protected]');

生成一个别名:

INSERT INTO `servermail`.`virtual_aliases`
(`id`, `domain_id`, `source`, `destination`)
VALUES
('1', '1', '[email protected]', '[email protected]');

据库的基本操作完毕。


准备步骤2:修改DNS服务器

这需要登录你的域名管理界面,做几个简单的操作:

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


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


    image.png

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


准备步骤3:申请证书

接下来我们需要为邮件服务器获取域名证书,抛开安全性不谈,纯粹从装X的角度而言,这玩意就如同https一样,这年头你的网站还穿着http出来见人就真的有点丢人了,因此证书几乎是必备的。

域名证书有很多获取方式,有收费的也有免费的,国内有一家通过网页申请的,可参见我写的另一篇博文:https://www.jianshu.com/p/b4b5ca1d88d6

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

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

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

  3. 生成证书
    certbot certonly -a nginx --agree-tos --staple-ocsp --email [email protected] -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篇

首先我们需要安装postfix,在centos下这很简单,只需要一条命令:
dnf -y install postfix postfix-mysql
设置自启动:
systemctl start postfix
systemctl enable postfix
安装完毕后,开始对postfix进行设置,其中关键的配置文件有两个:main.cf和master.cf。

1. nano /etc/postfix/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.com

myorigin = example.com
myorigin参数指定默认域名,该默认域名将附加到没有@domain部分的发件人和收件人地址。 需要将其值更改为example.com,因此邮件服务器上的发件人将具有@example.com地址。

myhostname = mail.example.com
与其他SMTP服务器通信时,Postfix使用此主机名来标识自己。 但是,操作系统主机名可能会更改,因此,最好直接在配置文件中设置。

mydestination = \$mydomain
mydestination参数指定服务器将其视为自身最终目的地的域列表。这个听起来有点拗口,说白了就是别人给您发信,哪些信你是接受的。比如[email protected]给您发一封信,收件人是[email protected],当你的smtp服务器接收到这封信的时候表示接受,对应的规则就是$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=52428800
mailbox_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.cf
virtual_mailbox_maps = mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
virtual_alias_maps = mysql:/etc/postfix/mysql-virtual-alias-maps.cf
这三行与数据库有关,表示邮箱的虚拟域,用户映射关系和别名映射关系,分别由哪三个SQL脚本做查询动作。

  1. 接下来我们就要创建这3个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 [email protected] mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
正确的话,应该返回:1

postmap -q [email protected] mysql:/etc/postfix/mysql-virtual-alias-maps.cf
正确的话,应该返回:[email protected]

2. 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 - - - - smtpd
smtps inet n - y - - smtpd
同时他们下面又有一些
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=encrypt
以-o开头的行,前面多了两空格,表示该服务下的具体设置。这两个空格不能删除,否则会报错,这就是所谓的缩进敏感。

可以看到我们开启了smtp,smtps和submission这三个服务,分别对应端口25,465和587,功能分别是:传统smtp服务,加密的smtps服务,还有一个submission。这是一个与smtps类似的加密协议。smtps 和 submission从功能上而言极其雷同,关于这两个端口,历史上还有一些彼此争夺话语权的野史,感兴趣的可以自行搜索。题外话我们暂且不表,反正两个都开通就是了。

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


三、核心内容:Dovecot篇

1. 安装dovecot
dnf -y install dovecot dovecot-mysql
设置自启动:
systemctl start dovecot
systemctl enable dovecot


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文件夹下的所有配置文件。

3. nano /etc/dovecot/conf.d/10-mail.conf

mail_location = maildir:/var/mail/vhosts/%d/%n
mail_privileged_group = mail

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

/var/mail/vhost/example.com/webmaster

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

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

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

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

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

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

8. 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授权

9. nano /etc/dovecot/conf.d/auth-sql.conf.ext

passdb {
  driver = sql
  args = /etc/dovecot/dovecot-sql.conf.ext
}
userdb {
  driver = static
  args = uid=vmail gid=vmail home=/var/mail/vhosts/%d/%n
}

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

10. 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。

11. nano /etc/dovecot/conf.d/10-master.conf

service lmtp {
  unix_listener /var/spool/postfix/private/dovecot-lmtp {
   mode = 0600
   user = postfix
   group = postfix
  }
}

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

  unix_listener auth-userdb {
   mode = 0600
   user = vmail
  }
  user = dovecot
}

service auth-worker {
  user = vmail
}

这个文件主要作用是为了打通dovecot和postfix的关联,授权postfix通过lmtp协议访问属于dovecot的地盘,访问权限是0600,表示有读写权限,但无执行权限。这个文件的源文件也比较庞杂,里面对多个协议都有设定,但是如果你全部把它们删了也没关系,等于采用默认设置,比如你把imap这一段删了,那么dovacot会将imap设为默认端口993。

11. nano /etc/dovecot/conf.d/10-ssl.conf

ssl = required
ssl_cert = 

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

12. nano /etc/dovecot/conf.d/15-mailboxes.conf

namespace inbox {
  inbox = yes
  mailbox Drafts {
    auto = create
    special_use = \Drafts
  }
  mailbox Junk {
    auto = create
    special_use = \Junk
  }
  mailbox Trash {
    auto = create
    special_use = \Trash
  }

  mailbox Sent {
    auto = create
    special_use = \Sent
  }
  mailbox "Sent Messages" {
    auto = create
    special_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


2. 测试连通性:
如果端口都存在,说明大毛病没有了,我们可以用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 123.123.123.123: Connection refused
则说明这个端口有毛病,需要排查。


3. 高端测试
利用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装好之后本身有一本默认证书,但那不是你的域名的,尽管看上去好像没毛病,但实际那本证书是无法使用的。


4. 常见错误

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

  • 问题:Recipient address rejected: User unknown in local recipient table
    nano /etc/postfix/main.cf :
mydestination = \$mydomain

  • 问题: Error: Diffie-Hellman key exchange requested, but no DH parameters provided. Set ssh_dh= nano /etc/dovecot/dovecot.conf
    去掉pop3:
protocols = imap lmtp

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


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

  • 更诡异的问题:
    大家不一定都能碰到,在此我只做一个记录:
    所有服务都运行正常,openssl测试也通过了,但是当我用客户端进行设置的时候foxmail就是报ssl错误,百思不得其解,更诡异的是,日志丝毫没有反应,连报错都没有,排查工作根本无从谈起。折腾了一晚上,第二天故障居然自行消失了!找不到问题这更让人窝火,后来通过慢慢回忆,我找出了问题所在:我在用foxmail客户端测试的时候忘记关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 accept
                ct state invalid drop
                iif lo accept
                ip protocol icmp icmp type { destination-unreachable, router-solicitation, router-advertisement, time-exceeded, parameter-problem } accept
                ip protocol igmp accept
                tcp dport { ssh, http, https,smtp, smtps, imap, imaps} 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认可的话,欢迎留言告知,交流,感谢!!

你可能感兴趣的:(Linux邮件服务器搭建攻略(一文吃透Postfix+Dovecot+MySQL))