概念解釋
SPF:Sender Policy Framework,直譯過來就是發(fā)件人保證框架.出現(xiàn)的主要原因是SMTP協(xié)議的缺陷.XMTP中,發(fā)件人的郵箱地址是可以偽造
的,因而SPF的出現(xiàn)就是防止偽造發(fā)件人.SPF的記錄實際上就是DNS服務(wù)器上面的一個記錄.如果郵件服務(wù)器收到了一封郵件,來自主機的IP是45.76.210.63
并且生成發(fā)件人為yusengy@info
.郵件服務(wù)器會去查詢yusengy@info
的SPF記錄.如果SPF記錄的IP為45.76.210.63
,那么就認為是合法的,否則通常都會被退信.SPF記錄一般如下.

DKIM:DomainKeys Identified Mail.功能目的與SPF相似,主要是讓收件人可以通過加密解密的方式來得知發(fā)件人是否是真實的.原理就是在電子郵件的開頭插入一段簽名,然后接收方通過從DNS查詢得到公鑰以后,以進行驗證,與SSH的公鑰和密鑰類似.
記錄一般如下:

PTR:反向域名解析,可以通過發(fā)件人的IP地址反向得知域名,也是一種用以判斷發(fā)件人是否正常的方式.
MUA:Mail User Agent.用戶郵件代理,用戶通過MUA接收發(fā)送郵件.例如Outlook, formail等.
MTA: Mail Transfer Protocol.郵件傳輸代理,是SMTP的一種實現(xiàn).常用的MTA有sendmail
,Postfix
.本例中使用Postfix
.MTA僅僅負責郵件的傳輸,MDA負責把接收到的郵件保存在硬盤中.
MDA: Mail Deliver Agent,郵件分發(fā)代理.負責將接收到的郵件保存在郵件服務(wù)器上.sendmail以及Postfix默認使用的MDA是procmail
.
MRA: Mail Receive Agent,郵件接收代理,用來實現(xiàn)IMAP,POP3協(xié)議,負責與MUA
交互,將服務(wù)器上的郵件通過IMAP以及POP3傳輸給客戶端.本例中使用的MRA是Dovecot
.
LMTP:Local Mail Transfer Protocol.本地郵件傳輸協(xié)議,是SMTP協(xié)議的擴展.本例中用與同一主機內(nèi)郵件傳輸.
Postfix:一個開源的MTA服務(wù)器,負責通過SMTP協(xié)議管理發(fā)送到本機的郵件以及由本機向外發(fā)送的郵件.與sendMail相似.現(xiàn)今流行的服務(wù)器套件例如Zimbra,IRedMail內(nèi)部都采用Postfix作為MTA.
Dovecot:一個開源的IMAP以及POP3服務(wù)器.通常工作是驗證用戶身份以及郵件的處理.
MySQL:存取用戶信息,監(jiān)聽的域名信息,用戶郵箱地址以及登錄密碼等.
郵件協(xié)議簡述
SMTP
SMTP全稱是Simple Mail Transfer Protocol,直譯過來就是簡單郵件傳輸協(xié)議, 由RFC5321定義.主要的工作就是把郵件信息從發(fā)件人的郵件服務(wù)器中傳送到接收人的郵件服務(wù)器中,偶爾我們使用MUA來發(fā)送郵件的話,也承載傳輸用戶郵件到發(fā)件服務(wù)器的功能, 因而也稱作推
協(xié)議,順帶提一下,SMTP協(xié)議的出現(xiàn)是比HTTP還早的,最早在1982年中發(fā)布第一版的RFC.
因而因為提出的年代久遠,所以在當時有許多問題都考慮不全面并且也有這許多的限制,例如SMTP要求信息內(nèi)容需要是7位的ASCII
來承載,因而我們在發(fā)送以及接受的時候,都需要將其編碼解碼.
另外,SMTP還存在一個問題就是沒有對發(fā)送方進行一個身份驗證,雖然在早期的互聯(lián)網(wǎng)環(huán)境沒有很大問題,但是在垃圾郵件滿天飛的今天,這卻是一個明顯的短板.因而衍生出了SPF
, DKIM
, DMARC
等一系列用來驗證發(fā)件人身份的方法.
POP3
POP3,Post Office Protocol Version 3,直譯就是郵局協(xié)議第三版,由RFC1939進行定義.這個協(xié)議的主要服務(wù)于用戶管理郵件服務(wù)器上面的電子郵件.具體過程是:當外來郵件發(fā)送到收件人的郵件服務(wù)器上時,收件人可以使用郵件客戶端連接郵件服務(wù)器,把未閱讀的郵件服務(wù)器以及部分信息拉取回本地進行處理.在拉取的過程中,我們可以選擇拉取完刪除
以及拉取完不刪除
兩種方式,不過現(xiàn)在默認一般都是拉取完不刪除,方便我們在其他的地方也能對郵件進行閱讀以及管理.
IMAP
IMAP, Internet Message Access Protocol, 直譯過來就是網(wǎng)絡(luò)信息訪問協(xié)議,可能和現(xiàn)在主流的翻譯不太一致,不過能理解其意思就好.相對于pop3協(xié)議所有郵件的管理都需要下載下來進而管理,IMAP提供了用戶遠程訪問郵件服務(wù)器的途徑,因而通過IMAP,用戶可以直接管理郵件服務(wù)器上的郵件.
工作原理
電子郵件架構(gòu)

這里我們使用的MTA是Postfix
, MRA是Dovecot
.我們可以繪制出郵件服務(wù)器接受郵件,用戶查收郵件以及用戶發(fā)送郵件的過程.
郵件服務(wù)器接受收件
假設(shè)yusen@Foxmail.com
發(fā)送一封郵件到yusen@yusengy.info
中.

- foxmail.com服務(wù)器會通過DNS查詢到y(tǒng)usengy.info的MX記錄,然后找到Postfix所在的服務(wù)器所在.
- 郵件通過SMTP協(xié)議發(fā)送給Postfix.
- Postfix通過MySQL查詢,yusengy.info是否是本機需要處理的域名.
- MySQL通過查詢返回確認信息給Postfix.
- Postfix得到確認信息,把郵件傳送給Dovecot,由Dovecot的LMTP服務(wù)來說投遞工作.
- Dovecot把郵件的內(nèi)容保存在對應(yīng)的路徑中.
用戶查收郵件過程

- MUA向Dovecot請求IMAP連接.
- Dovecot發(fā)送自己的SSL證書.
- MUA發(fā)送用戶的賬號密碼.
- Dovecot得到賬號密碼向MySQL查詢.
- MySQL返回查詢結(jié)果.
- 如果賬號密碼正確,Dovecot讀取在改用戶路徑下的信息.
- 得到最新的郵件以及其他的一些統(tǒng)計信息.
- 通過IMAP協(xié)議發(fā)送給MUA.
用戶發(fā)送郵件的過程

- MUA請求Postfix建立SMTP連接
- Postfix發(fā)送SSL證書給MUA
- MUA發(fā)送賬號密碼給Postfix,請求驗證
- Postfix請求Dovecot驗證賬號密碼.
- Dovecot請求MySQL查詢結(jié)果
- MySQL返回查詢結(jié)果.
- Dovecot返回Postfix賬號密碼驗證結(jié)果.
- Postfix返回MUA賬號密碼驗證結(jié)果.
- MUA使用SMTP協(xié)議發(fā)送郵件到Postfix.
- Postfix把郵件進行發(fā)送.接下來的步驟參考前面服務(wù)器查收郵件的過程.
郵件服務(wù)器搭建
根據(jù)上面的幾個示意圖,我們已經(jīng)基本了解了郵件發(fā)送,接收的一般流程以及每個組件在其中的職責.了解清楚以后,郵件服務(wù)器的搭建則會變得簡單了許多,明白其中每一步的作用以及緣由.
前期準備
設(shè)置hostname
CentOS7,可以通過hostnamectl set-hostname hostname
命令設(shè)置hostname,并且修改hosts文件.這里域名是yusengy.info.
hostnamectl set-hostname mail.yusengy.info
為什么要設(shè)置hostname呢?因為一般情況下,Postfix在與其他的SMTP服務(wù)器進行通信的時候,會使用hostname來表名自己的身份.主機名有兩種形式,單名字
與FQDN(Fully Qualified Domain Name)
.如果SMTP服務(wù)器不是用FQDN來表明身份,則有可能會被拒收.
修改防火墻開放端口
修改防火墻開發(fā)相應(yīng)的端口,分別是25, 465, 587, 110, 995, 143, 993
.
域名解析配置

安裝Postfix, Dovecot以及數(shù)據(jù)庫
由于Centos中默認的源沒有MySQL,因而使用MariaDB代替,實際使用與MySQL一致.
首先更新系統(tǒng)yum update -y
.把系統(tǒng)的一些組件更新到最新,然后需要修改一些CentOS的源設(shè)置,因為CentOS默認源里面的Postfix默認是不能和MariaDB協(xié)同工作的,因而我們需要安裝擴展源里面的Postfix.
修改: /etc/yum.repos.d/CentOS-Base.repo
[base]
name=CentOS-$releasever - Base
exclude=postfix
#released updates
[updates]
name=CentOS-$releasever - Updates
exclude=postfix
修改完畢以后,我們讓擴展源生效,并且安裝我們所需要的應(yīng)用以及服務(wù).
yum --enablerepo=centosplus install postfix
yum install dovecot mariadb-server dovecot-mysql
接下來,我們配置MariaDB數(shù)據(jù)庫來處理虛擬域名以及用戶信息.
數(shù)據(jù)庫配置
MariaDB的安裝配置與MySQL有些許不同,MySQL是在安裝的時候設(shè)置root的密碼,而MariaDB則是在安裝完畢后設(shè)置密碼.
首先我們啟動MariaDB.
systemctl enable mariadb.service
systemctl start mariadb.service
然后,我們進行一些初始化的配置.
mysql_secure_installation
輸入mysql_secure_installation
后,我們可以修改root用戶的密碼,禁止外部使用root登錄,刪除匿名賬戶以及刪除test表等等.
數(shù)據(jù)庫概覽
創(chuàng)建mail數(shù)據(jù)庫用以處理郵件相關(guān)的業(yè)務(wù).并且創(chuàng)建郵件管理員.
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
替換成自己的密碼.我這里只是做示范使用,實際中應(yīng)該使用強度更大的字符串作為密碼.

mail數(shù)據(jù)庫中一共有4個表,分別是
虛擬域名
, 郵件轉(zhuǎn)發(fā)
, 用戶信息
以及傳輸路徑
四個表..
虛擬域名表
該表存儲的是本地服務(wù)器用來接收郵件的域名.

創(chuàng)建語句
CREATE TABLE domains (domain varchar(50) NOT NULL, PRIMARY KEY (domain) );
郵件轉(zhuǎn)發(fā)
可以用來轉(zhuǎn)發(fā)郵件.

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) );
在配置完數(shù)據(jù)庫以后,我們最好修改數(shù)據(jù)庫的配置文件,只允許本地訪問數(shù)據(jù)庫,提高安全性.
修改: /etc/my.cnf
bind-address=127.0.0.1
如果數(shù)據(jù)庫存儲在其他的服務(wù)器上面,我們這里的bind-address地址在后面配置Postfix的時候需要相應(yīng)的修改.不過為了安全起見,最好還是不要讓數(shù)據(jù)庫能夠直接在外部可以訪問.
配置完成了以后,我們則可以重啟數(shù)據(jù),使配置生效.
systemctl restart mariadb.service
配置Postfix
配置完成了數(shù)據(jù)庫以后,我們就需要配置Postfix,讓其可以與MariaDB協(xié)同工作.因為Postfix尋找域名,用戶賬號等需要通過數(shù)據(jù)庫來完成,但是其本身是不知道如何查詢的,因而需要我們定制化.
下面的配置中,把mys123123替換成前面數(shù)據(jù)庫管理員設(shè)置的密碼
創(chuàng)建虛擬域名配置
創(chuàng)建:/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
創(chuàng)建郵件轉(zhuǎn)發(fā)配置
創(chuàng)建:/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
創(chuàng)建虛擬郵箱配置
創(chuàng)建: /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
創(chuàng)建電子郵件與文件映射
創(chuàng)建:/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
創(chuàng)建完畢以后修改權(quán)限以及分配用戶組.
chmod o= /etc/postfix/mysql-virtual_*.cf
chgrp postfix /etc/postfix/mysql-virtual_*.cf
同時,我們創(chuàng)建一個新的用戶組以及用戶,用來處理郵件.所有的虛擬郵箱,都會存在這個用戶的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服務(wù).
修改:/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
}
因為數(shù)據(jù)庫存儲有用戶的賬號密碼信息,Dovecot的職責之一就是驗證用戶的賬號密碼,因而我們還需要創(chuàng)建一個配置文件以讓Dovecot與數(shù)據(jù)庫進行交互.
老慣例,這里也是把密碼進行替換一下.
創(chuàng)建:/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';
修改文件所屬的用戶組以及訪問權(quán)限
chgrp dovecot /etc/dovecot/dovecot-sql.conf.ext
chmod o= /etc/dovecot/dovecot-sql.conf.ext
設(shè)置Dovecot在開啟啟動并且啟動其服務(wù)
systemctl enable dovecot.service
systemctl start dovecot.service
然后我們觀察一下var/log/maillog
,確定現(xiàn)在Dovecot沒有錯誤

然后我們使用Telnet檢測一下pop3服務(wù)是否正常.
yum install telnet
telnet localhost pop3
如果你看到的和我看到的差不多,那么說明是pop3服務(wù)是正常的.

檢測Postfix
接下來則是檢測Postfix是否運行正常.
telnet localhost 25
ehlo localhost
如果連接成功,同時輸入EHLO
命令有如下返回值,則Postfix是正常的.

創(chuàng)建用戶
接下來,我們在MariaDB中的郵箱中加入新的用戶,用作日常郵件的發(fā)送.
這里的用戶密碼不要使用明文存儲.
USE mail;
INSERT INTO domains (domain) VALUES ('yusengy.info');
INSERT INTO users (email, password) VALUES ('yusen@yusengy.info', ENCRYPT('123123'));
quit
到這個時候,我們的郵件服務(wù)器基本就已經(jīng)搭建完成了,接下來只要使用MUA進行連接,就能像正常的郵件服務(wù)器一樣使用了.

嘗試給自己的QQ郵箱發(fā)件看看.是不是收到了?

如果被拒收或者在垃圾箱中,說明我們的郵件發(fā)送服務(wù)器信譽不夠,這個時候我們需要給我們的郵件服務(wù)器做一些條件,例如添加SPF
, DKIM
以及DMARC
等,以提高郵件發(fā)送的成功率,當這些完成以后,基本能夠直接發(fā)送到收件箱了.具體可以參考這一篇文章
郵件服務(wù)器添加SPF,DKIM,DMARC,PTR
至此,一個郵件服務(wù)器的搭建就完成了,通過這一系列的操作,是否對于電子郵件協(xié)議又有了進一步的理解呢?
如果沒有在收件箱收到發(fā)送的郵件,可以在垃圾箱看看,或者看看是否退件了.這篇文章中我們沒有談到SPF
, DKIM
以及DMARC
驗證的配置,因而有可能會被QQ郵箱退件的,畢竟現(xiàn)實中的郵件服務(wù)器還需要一系列的配置,以提高送達率.這些我在后面會開一篇文章專門講解.
如果MUA提示發(fā)件失敗,那么我們可以查看一下日志,分別在/var/log/maillog
以及/home/vmail/dovecot-deliver.log
,找到對應(yīng)的錯誤,然后回到文章相應(yīng)的地方看看是否配置錯了.如果還無法解決,可留言私信,我看到了會進行相應(yīng)的解答.