开始之前
- Postfix: 是一个标准的MTA「Mail Transfer Agent」服务器,它负责通过SMTP协议管理发送到本机的邮件以及由本机发向外界的邮件。
- Dovecot: 是一个非常优秀的IMAP/POP服务器用以接收外界发送到本机的邮件。通常,Dovecot的工作内容包括:验证用户身份以确保邮件不会被泄露。
- MySQL: 它将存储所有的用户信息,其中包括:需要监听的域名信息、用户邮箱地址、登录密码、邮箱别名「alias」等
工作原理
服务器接收邮件的过程
在开始讲述本例的内容之前,我们先来看看Postfix+Dovecot+MySQL是如何相互协作以实现邮件服务器的各项功能。我们假设 张三通过php3.cn的邮箱zhangsan@php3.cn发送一份邮件给 李四lisi@mydomain.com,则服务器接收邮件的过程大致如下图所示:
- zhangsan@php3.cn发送邮件到lisi@mydomain.com
- php3.cn服务器会通过DNS查询mydomain.com的MX记录并找到Postfix所在的服务器
- 邮件被发送给Postfix
- Postfix转向MySQL求助,以查询mydomain.com是不是需要处理的域名
- MySQL返回确认信息给Postfix
- Postfix将接受到的邮件投递给Dovecot的LMTP服务以便做处理
- Dovecot将邮件内容保存到lisi@mydomain.com用户对应的磁盘路径
用户查收邮件的过程
上述例子中我们看到了服务器接收邮件的过程,接下来我们看看,当大家通过用户名密码登录邮箱查看邮件时,会发生什么事情:
- 邮件客户端 to Dovecot:尊敬的Dovecot大人,您好!我阔以建立一个IMAP加密连接吗?
- Dovecot to 邮件客户端:当然阔以。这是我的SSL证书,请您告诉我帐号和密码!
- 邮件客户端 to Dovecot:好滴!这是我的用户名和密码,千万不要告诉别人哦!
- Dovecot to MySQL:Hi 美女!请问下,这个用户名和密码是正确的嘛?
- MySQL to Dovecot:好的,请稍后!呃……这个用户名和密码是正确的哦!
- Dovecot打开存放在本地磁盘/var/mail/mydomain.com/llisi的mailbox
- Dovecot获取到最新的邮件及其他相关信息
- Dovecot将邮件及其相关的其他信息通过IMAP协议发送给客户端
用户发送邮件的过程
查收了最新的邮件之后,李四lisi@mydomain.com发现张三给他发来了邮件。现在,李四回复一封邮件给张三,会发生什么事情:
- 邮件客户端 to Postfix:尊敬的Postfix大人,您好!我阔以建立一个安全的SMTP连接嘛?
- Postfix to 邮件客户端:说人话!可以就是可以,干嘛要说「阔以」啊!你丫贱啊,找抽啊!想建立SMTP连接可以,不过要加密。这是我的SSL证书,告诉我你的帐号和密码,你个贱人!
- 邮件客户端 to Postfix:对不起,大人,我错鸟!这是我的帐号和密码,不要告诉别人哦!
- Postfix to Dovecot:Hi 帅哥,帮我查一下这个帐号和密码!
- Dovecot to MySQL:Hi 美女,这个帐号和密码是正确的呢?!还是正确的呢?!还是……
- MySQL to Dovecot:好啦,你乖啦!我查过啦,这个帐号密码是正确的啦!表卖萌哦,Dovecot君!
- Dovecot to Postfix:大锅,则个帐号密码斯正缺滴!
- Postfix to 邮件客户端:贱人,过来!你给的帐号密码是正确的,允许你发送邮件!
- 邮件客户端将编写好的邮件通过SMTP协议发送给Postfix
- Postfix将收到的邮件转发给对方
以上,大家已经看到邮件收、发的整个过程。接下来看看如何才能成功配置邮件服务器。
DNS配置
首先,你需要有一个域名。本例中假定我们的域名为mydomain.com,以此为基础去做后续的所有工作。请注意:在DNS相关配置没有成功之前,请勿尝试后续的操作。即使你配置好了Postifx,只要DNS相关配置没有成功,邮件服务器一样不能正常工作。
设置完以后,DNS的MX记录及TTL时间大致如下:
mydomain.com MX 10 12.34.56.78 mail.mydomain.com MX 10 12.34.56.78
MySQL安装及配置
安装详见网上资料
本例中我们使用MySQL数据库保存Postfix需要服务的虚拟域名、用户帐号及密码、邮件别名三个重要的信息。
请注意:
其实Postfix和Dovecot是完全可以不使用数据库的,二者都可以通过各种配置文件完成「零数据库」的邮件服务器。但是,既然可以使用数据库这么方便,为什么不用呢?
新建数据库及用户
接下来,我们需要新建一个MySQL用户及一个数据库:
-
使用root口令登录MySQL
mysql -u root -p
-
输入root口令
-
新建一个数据库,名称叫做mailserver:
create database mailserver character set utf8;
-
输入如下命令以新建一个用户mailserver,并指定密码为mailserver123:
create user mailserver@localhost identified by mailserver123;
-
将数据库mailserver的所有权限赋给用户mailserver:
grant all on mailserver.* to mailserver@localhost identified by mailserver123;
-
退出root用户:
exit;
-
使用mailserver用户登录:
mysql -u mailserver -p
-
输入mailserver帐号的口令
-
将默认数据库切换为mailserver数据库:
use mailserver;
新建表格
-
输入如下SQL语句以新建virtual_domains表,该表是本地服务器用以接收邮件的域名:
CREATE TABLE `virtual_domains` ( `id` int(11) NOT NULL auto_increment, `name` varchar(50) NOT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;
-
输入如下SQL语句以新建virtual_users表,该表邮件服务器的终端用户表,记录用户的邮件地址及密码「千万不要保存明文密码」:
CREATE TABLE `virtual_users` ( `id` int(11) NOT NULL auto_increment, `domain_id` int(11) NOT NULL, `password` varchar(106) NOT NULL, `email` varchar(100) 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;
-
输入如下SQL语句以新建virtual_aliases表,该表是邮件服务器别名表「邮件服务器种的别名alias的概念大家可以Google一番」:
CREATE TABLE `virtual_aliases` ( `id` int(11) NOT NULL auto_increment, `domain_id` int(11) 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
插入数据
为了便于查看结果,接下来给上述三张表种插入一些测试数据:
-
给virtual_domains表插入测试数据,大致如下:
insert into virtual_domains(id,name) values(1,mail.mydomain.com); insert into virtual_domains(id,name) values(2,mydomain.com);
请注意:
上述表种id字段是自增列,可以不赋值。但无论如何,接下来的两张表种我们将需要上述表种的逐渐列id的值。比如:我将要添加mydomain.com域名下的邮箱帐号,而mydomain.com在virtual_domains表种的id值为2。 -
给virtual_users表添加用户数据:
insert into virtual_users(id,domain_id,password,email) values (1,2,ENCRYPT(zhangsan123456, CONCAT($7$, SUBSTRING(SHA(RAND()), -16))),zhangsan@mydomain.com); insert into virtual_users(id,domain_id,password,email) values (2,2,ENCRYPT(123456lisi, CONCAT($7$, SUBSTRING(SHA(RAND()), -16))),lisi@mydomain.com);
-
给virtual_aliases表添加别名数据:
insert into virtual_aliases(id,domain_id,source,destination) values (1,2,all@mydomain.com,zhangsan@mydomain.com); insert into virtual_aliases(id,domain_id,source,destination) values (1,2,all@mydomain.com,lisi@mydomain.com);
请注意:
通过上述别名表的数据,当有人给all@mydomain.com发送邮件时,系统将自动将邮件转发给zhangsan@mydomain.com和lisi@mydomain.com
这种场景,在公司内部「发送通知」等情况下适用
测试数据
写几个SQL查询语句查看下结果吧
select * from virtual_domains; select * from virtual_users; select * from virtual_aliases;
Postfix安装及配置
安装详见 https://www.php3.cn/a/196.html
Postfix是邮件发送的核心服务器,所有向内、向外投递的邮件都需要经过Postfix通过SMTP协议完成。接下来的内容,大家需要修改Postfix相关的一些参数,它们是:
- 告诉Postfix如何连接MySQL数据库,并让Postfix通过数据库种的表确定收发邮件的域名、用户帐号及密码、邮件别名等
- 告诉Postfix将收到的邮件转发给Dovecot的LMTP服务以完成本地投递
- 开放本地端口25、110
Postfix的配置
-
使用vi编辑器打开/etc/postfix/main.cf文件
vi /etc/postfix/main.cf
-
复制如下内容,并将其插入到上述注释代码之后:
smtpd_tls_auth_only = yes #Enabling SMTP for authenticated users, and handing off authentication to Dovecot 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
-
按照如下方式修改mydestination一行的值:
mydestination = localhost
请注意:
将mydestination的值修改为localhost,以便Postfix能够通过MySQL表中相关数据决定需要接受/发送邮件的域名,这样更具有通用性 -
在文档种加入以下内容,以便告诉Postfix不要使用LDA「Local Delivery Agent」转而使用Dovecot的LMTP完成本地邮件投递:
#Handing off local delivery to Dovecots LMTP, and telling it where to store mail virtual_transport = lmtp:unix:private/dovecot-lmtp
-
在文档中加入以下内容,以便告诉Postfix去MySQL数据库种寻找域名、用户帐号密码及邮件别名等信息:
#Virtual domains, users, and aliases 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
-
新建/etc/postfix/mysql-virtual-mailbox-domains.cf文件并输入如下内容:
user = mailserver password = mailserver123 hosts = 127.0.0.1 dbname = mailserver query = SELECT 1 FROM virtual_domains WHERE name=%s
-
重启Postfix服务
service postfix restart
-
测试上述内容是否正确,如果上述内容配置正确,则如下命令执行后返回结果应该为1:
postmap -q mydomain.com mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
-
新建/etc/postfix/mysql-virtual-mailbox-maps.cf文件并输入如下内容:
user = mailserver password = mailserver123 hosts = 127.0.0.1 dbname = mailserver query = SELECT 1 FROM virtual_users WHERE email=%s
-
重启Postfix服务
service postfix restart
-
测试上述配置是否正确,如果上述内容配置正确,则如下命令执行后返回结果应该为1:
postmap -q lisi@mydomain.com mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
-
新建/etc/postfix/mysql-virtual-alias-maps.cf文件并输入如下内容:
user = mailserver password = mailserver123 hosts = 127.0.0.1 dbname = mailserver query = SELECT destination FROM virtual_aliases WHERE source=%s
-
重启Postfix服务
service postfix restart
-
测试上述配置是否正确,如果上述配置正确,则如下命令执行后返回结果应该是之前添加的别名帐号:
postmap -q all@mydomain.com mysql:/etc/postfix/mysql-virtual-alias-maps.cf
-
重启Postfix服务
service postfix restart
搞定,Postfix服务器应该配置完成了。
Dovecot安装及配置
Dovecot在本例中充当IMAP、POP服务器的角色,同时它也将负责用户登录时用户身份的验证「Dovecot会将真正的验证工作交给MySQL处理」。
这部分的内容配置起来相对简单,但是需要配置的文件繁多。大体上,我们需要配置如下的信息:
- 开启Dovecot的IMAP、POP3、LMTP协议
- 告知Dovecot本地邮件的投档路径
- 连接Dovecot和MySQL数据库以验证用户身份
Dovecot的安装
通过如下命令安装Dovecot最新版:
yum install dovecot dovecot-mysql
Dovecot的配置
需要修改的配置文件有:
- /etc/dovecot/dovecot.conf Dovecot的主配置文件
- /etc/dovecot/conf.d/10-mail.conf Dovecot将要操作的磁盘路径相关配置信息
- /etc/dovecot/conf.d/10-auth.conf 用户验证相关配置信息
- /etc/dovecot/conf.d/auth-sql.conf.ext SQL-Type验证相关配置信息
- /etc/dovecot/dovecot-sql.conf.ext Dovecot与数据库连接相关配置信息
- /etc/dovecot/conf.d/10-master.conf Dovecot本地socket相关配置信息
- /etc/dovecot/conf.d/10-ssl.conf 关于SSL的相关配置信息
请注意:
在修改上述文件之前,请一定先做好备份以方便恢复
修改/etc/dovecot/dovecot.conf文件
使用vi编辑器打开/etc/dovecot/dovecot.conf文件并在文件种加入如下内容:
!include conf.d/*.conf # Enable installed protocols = imap pop3 lmtp
如果以上内容已经存在,只需要把该行的#号去掉即可
上述内容大致的意思是:告诉Dovecot启用所有.conf文件;并开启Dovecot的imap、pop3、lmtp等相关协议使之正常工作
修改/etc/dovecot/conf.d/10-mail.conf文件
打开文件并找到mail_location相关信息,将其指定到本地磁盘的某个路径,这个路径将来会存放收到的邮件,如下所示:
mail_location = maildir:/var/mail/vhosts/%d/%n
保存文件并退出
创建/var/mail/vhosts/文件夹给每个需要启用的域名:
mkdir -p /var/mail/vhosts/mydomain.com
输入如下命令以新建vmail用户组及用户并赋权限
groupadd -g 5000 vmail useradd -g vmail -u 5000 vmail -d /var/mail
接下来修改一下/var/mail/目录的权限,使vmail能够访问:
chown -R vmail:vmail /var/mail
修改/etc/dovecot/conf.d/10-auth.conf文件
找到文件中disable_plaintext_auth并取消注释
disable_plaintext_auth = no
找到文件中auth_mechanisms并将其修改为如下值:
auth_mechanisms = plain login
默认情况下,Dovecot是允许系统用户登录使用的,我们需要将其禁用。找到文件种如下内容并将其注释:
#!include auth-system.conf.ext
开启Dovecot的MySQL支持,取消!include auth-sql.conf.ext的注释符号:
#!include auth-system.conf.ext !include auth-sql.conf.ext #!include auth-ldap.conf.ext #!include auth-passwdfile.conf.ext #!include auth-checkpassword.conf.ext #!include auth-vpopmail.conf.ext #!include auth-static.conf.ext
修改/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 }
修改/etc/dovecot/dovecot-sql.conf.ext文件
取消文件中driver行的注释,并将其修改为如下:
driver = mysql
取消文件中connect行的注释,并将其修改为如下:
connect = host=127.0.0.1 dbname=mailserver user=mailserver password=mailserver123
取消文件中default_pass_scheme行的注释,并将其修改为如下:
default_pass_scheme = SHA512-CRYPT
取消文件中password_query行的注释,并将起修改为如下:
password_query = SELECT email as user, password FROM virtual_users WHERE email=%u;
保存退出
在命令行种输入如下内容以修改目录权限:
chown -R vmail:dovecot /etc/dovecot
修改/etc/dovecot/conf.d/10-master.conf文件
找到文件中的service lmtp并将其修改如下:
service lmtp { unix_listener /var/spool/postfix/private/dovecot-lmtp { mode = 0600 user = postfix group = postfix } # Create inet listener only if you cant use the above UNIX socket #inet_listener lmtp { #Avoid making LMTP visible for the entire internet #address = #port = #} }
找到文件中service auth并将其内容修改如下:
service auth { # auth_socket_path points to this userdb socket by default. Its typically # used by dovecot-lda, doveadm, possibly imap process, etc. Its default # permissions make it readable only by root, but you may need to relax these # permissions. Users that have access to this socket are able to get a list # of all usernames and get results of everyones userdb lookups. unix_listener /var/spool/postfix/private/auth { mode = 0666 user = postfix group = postfix } unix_listener auth-userdb { mode = 0600 user = vmail #group = } # Postfix smtp-auth #unix_listener /var/spool/postfix/private/auth { # mode = 0666 #} # Auth process is run as this user. user = dovecot }
找到文件中service auth-worker内容并修改如下:
service auth-worker { # Auth worker process is run as root by default, so that it can access # /etc/shadow. If this isnt necessary, the user should be changed to # $default_internal_user. user = vmail }
重新启动Dovecot服务:
service dovecot restart
测试邮件服务器是否正常
请注意以下内容:
- 邮箱的全称「包括后面的@mydomain.com」将作为用户名
- 邮箱密码是MySQL数据库种对应邮箱的密码
配置好客户端之后即可连接获取、发送邮件。