转载:原文链接
前言
关于邮件服务器的工作原理我就不再赘述了。Postfix是优秀的MTA,而Dovecot则是优秀的MDA。前者负责发信、收信,提供smtp服务;后者负责邮件保存到邮箱,提供pop3和imap服务。
这里介绍使用Postfix+Dovecot模式的邮件服务系统,同时Postfix使用Dovecot提供的SASL完成用户认证。用户使用MySQL存储的虚拟用户,而不是服务器的实际用户。同时使用opendkim完成邮件的dkim签名,SpamAssassin完成反垃圾邮件。也会阐述如何为smtp、pop3和imap配置SSL。
准备一台服务器
-
需要一台服务器,尽量使用有公网ip的服务器而不是使用内网穿透(否则发邮件的时候对方发现ip是非静态ip可能会当作垃圾邮件)。
-
要保证服务器的25端口开放。我选择了腾讯云的服务器,1核1G,申请开放了25端口(腾讯云申请比阿里云容易)。
-
主机名设置为你的域名或者
mx.xxxx.com
这样的子域名。 -
修改主机的时区,设为北京时间。
准备一个域名
准备一个域名,最好已经申请超过28天(否则容易被当作垃圾邮件)。
-
添加一个A记录(例如
mx.xxxx.com
)指向服务器的ip,添加一个mx记录(主机记录为@)指向上述添加的A记录(优先级可设定为5,具体作用可自行百度)。 -
可以为smtp、pop3和imap分别添加一些记录(例如
smtp.xxxx.com
),指向你的服务器(你也可以不这么做,这个看个人喜好,在登录邮箱的时候需要输入smtp服务器的地址,你可以输入ip也可以输入你现在设定的域名,如果要做SSL则最好是设定域名。你也可以smtp,pop3和imap都是用mx.xxxx.com
这个域名)。 -
添加一个txt记录作为SPF记录(主机记录为@),内容可以写
v=spf1 mx ~all
。这表示当对方收到一封来自你这个域名的邮件时,先检查发件方对方的ip是否为mx记录中定义的ip(或A记录对应的ip),如果不是则标记为软拒绝。具体可以自行查询SPF记录的语法。如果你发邮件的机器没有公网ip,也就是你是通过本地机器内网穿透实现的邮件服务,那么SPF则写为v=spf1 +all
表示接受所有的ip。 -
添加一个txt记录为DMARC记录(主机记录为_dmarc),内容可以写
v=DMARC1; p=reject; fo=1; rua=mailto:你的邮箱
。表示当出现仿造的邮件时,对方reject邮件,并通知你的邮箱。具体可以百度DMARC的语法。
申请SSL证书
如果不想使用SSL也可以跳过这一步骤。
-
申请一个SSL证书,包括上面步骤所创建的所有A记录(例如
mx.xxxx.com
和smtp.xxxx.com
)。可以使用acme.sh在Let's或者ZeroSSL申请证书,我是在后者申请的。 -
证书的fullchain文件放到服务器的
/etc/ssl/certs/xxxx.com.pem
下。 -
证书的密钥文件放到服务器的
/etc/ssl/private/xxxx.com.key
下。 -
上述二者权限设置为
400
,属主设置为root:root
。
配置postfix和dovecot
- 安装postfix和dovecot
swift
apt update
apt install postfix postfix-mysql dovecot-core dovecot-pop3d dovecot-imapd dovecot-lmtpd dovecot-mysql
-
安装配置MySQL,新建数据库mailserver(名字可以根据喜好来,下同),并创建用户mail,注意分配权限。
-
创建数据表:
sql
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(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;
- 为数据库添加内容,具体按照自己喜好来
sql
-- 插入一个域名(1表示序号, 注意递增)
insert into virtual_domains values(1,'xxxx.com')
-- 插入用户(1表示序号, 注意递增)
insert into virtual_users values(1,域名序号,md5('密码'),'yyyy@xxxx.com');
-- 为用户设置一个别名(1表示序号, 注意递增),发送给zzzz的邮件都会发给yyyy了。
-- 注意这一步好像要先为zzzz插入一个用户,你也可以试一下不这么做,具体要不要我没试验过
insert into virtual_aliases values(1,域名序号,'zzzz@xxxx.com','yyyy@xxxx.com')
-
配置
/etc/postfix/main.cf
,这是postfix的主配置文件。 -
添加SSL代码
ini
smtpd_tls_cert_file=/etc/ssl/certs/xxxx.com.pem
smtpd_tls_key_file=/etc/ssl/private/xxxx.key
smtpd_use_tls=yes
#smtpd_tls_auth_only = yes
smtp_tls_cert_file=/etc/ssl/certs/xxxx.com.pem
smtp_tls_key_file=/etc/ssl/private/xxxx.com.key
smtp_use_tls=yes
smtpd_tls_CApath=/etc/ssl/certs
smtpd_tls_security_level=may
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_scache
smtp_tls_CApath=/etc/ssl/certs
smtp_tls_security_level=may
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
- 使用dovecot来做身份认证
ini
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
# smtpd_client_restrictions = permit_mynetworks permit_sasl_authenticated reject_rbl_client reject_rhsbl_client reject_unknown_client
# smtpd_sender_restrictions = reject_unknown_sender_domain
smtpd_recipient_restrictions = permit_sasl_authenticated permit_mynetworks reject_unauth_destination
smtpd_relay_restrictions = permit_mynetworks permit_sasl_authenticated defer_unauth_destination
restrictions结尾的是一些规则,表示smtp处理怎样的邮件。有兴趣的可以百度一下
- 其次是域名的一些配置和一些常规配置
ini
myhostname = xxxx.com
myorigin = $myhostname
mydomain = $myhostname
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
mydestination = localhost
relayhost =
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
mailbox_command = procmail -a "$EXTENSION"
mailbox_size_limit = 0
recipient_delimiter = +
inet_interfaces = all
inet_protocols = all
smtp_helo_name = xxxx.com
其中,myhostname设置为主机名,myorigin和mydomain设置为邮箱的域名(yyyy@xxxx.com的那个xxxx.com)。mynetworks指定来自哪里的ip允许直接发邮件,不需要SASL认证。如果你使用内网穿透,需要把mynetworks设置为空,否则经过内网穿透下来的请求来自的ip都会变成127.0.0.1,这样他们就统统不用走SASL就能发邮件了。
- 最后设置一些和Dovecot以及MySQL协同工作所需要的选项。
ini
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
virtual_transport = lmtp:unix:private/dovecot-lmtp
-
配置Postfix的MySQL文件
-
创建/etc/postfix/mysql-virtual-mailbox-domains.cf,内容如下:
ini
user = admin
password = 123456
hosts = 127.0.0.1:3306
dbname = mailserver
query = SELECT 1 FROM virtual_domains WHERE name='%s'
- 创建/etc/postfix/mysql-virtual-mailbox-maps.cf,内容如下
ini
user = admin
password = 123456
hosts = 127.0.0.1:3306
dbname = mailserver
query = SELECT 1 FROM virtual_users WHERE email='%s'
- 最后创建/etc/postfix/mysql-virtual-alias-maps.cf,内容如下:
ini
user = admin
password = 123456
hosts = 127.0.0.1:3306
dbname = mailserver
query = SELECT destination FROM virtual_aliases WHERE source='%s'
- 重启服务(
systemctl restart postfix
),然后做一些验证
perl
postmap -q xxxx.com mysql:/etc/postfix/mysql-virtual-mailbox-domains.cf
# 输出1
postmap -q yyyy@xxxx.com mysql:/etc/postfix/mysql-virtual-mailbox-maps.cf
# 输出1
postmap -q zzzz@xxxx.com mysql:/etc/postfix/mysql-virtual-alias-maps.cf
# 输出zzzz是谁的别名
-
配置
/etc/postfix/master.cf
文件 -
取消注释submission,开启587端口的服务,后面的inet, n, y, -o等可看作是参数
ini
submission inet n - y - - smtpd
-o syslog_name=postfix/submission
- 取消smtps,开启SSL的465端口的服务
ini
smtps inet n - y - - smtpd
-o syslog_name=postfix/smtps
-o smtpd_tls_wrappermode=yes
- 配置
/etc/dovecot/dovecot.conf
,确保有如下内容:
ini
!include conf.d/*.conf
protocols = imap lmtp pop3
- 创建一个用户,用户名和组名可以自己喜好决定,Home目录可放在
/var/mail
或者/home/mail
。下文以/var/mail
为例。
yaml
groupadd -g 5000 vmail
useradd -g vmail -u 5000 vmail -d /家目录
chown -R vmail:vmail /家目录
- 修改
/etc/dovecot/conf.d/10-mail.conf
,确保配置为(注意/var/mail
为上文所说的家目录,mail_privileged_group
的值为mail是固定的,不是上文所创建的组名):
ini
mail_location = maildir:/var/mail/vhosts/%d/%n
mail_privileged_group = mail
- 修改
/etc/dovecot/conf.d/10-auth.conf
,确保配置为
ini
disable_plaintext_auth = no
auth_mechanisms = plain login
有的教程把disable_plaintext_auth设置为yes,这表示拒绝明文密码登录,会使得一些客户端登陆不上,所以我选择为no。
拖动到最下方,确保启用SQL设置,其他注释掉。
makefile
#!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
,确保如下配置:
ini
passdb {
driver = sql
args = /etc/dovecot/dovecot-sql.conf.ext
}
userdb {
driver = static
args = uid=vmail gid=vmail home=/var/mail/vhosts/%d/%n
}
其中,vmail、/var/mail为上面步骤创建的用户的相关信息。
- 修改
/etc/dovecot/dovecot-sql.conf.ext
,确保如下配置,connect表示mysql的登录信息
ini
driver = mysql
connect = host=127.0.0.1 port=3306 dbname=mailserver user=xxxx password=xxxx
default_pass_scheme = MD5
password_query = SELECT email as user, password FROM virtual_users WHERE email='%u';
- 修改
/etc/dovecot/conf.d/10-master.conf
,确保存在配置:
ini
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
mode = 0600
user = postfix
group = postfix
}
# Create inet listener only if you can't use the above UNIX socket
#inet_listener lmtp {
# Avoid making LMTP visible for the entire internet
#address =
#port =
#}
}
service auth {
unix_listener /var/spool/postfix/private/auth {
mode = 0666
user = postfix
group = postfix
}
unix_listener auth-userdb {
mode = 0600
user = vmail
#group =
}
user = dovecot
}
service auth-worker {
# Auth worker process is run as root by default, so that it can access
# /etc/shadow. If this isn't necessary, the user should be changed to
# $default_internal_user.
user = vmail
}
- 修改
/etc/dovecot/conf.d/10-ssl.conf
,以开启ssl认证,确保存在一下配置
ini
ssl = required
ssl_cert = <fullchain位置
ssl_key = <密钥位置
ssl使用required应该是说ssl是必须的意思,也可以使用yes表示开启ssl也允许非ssl。
ssl_cert和ssl_key的<
符号是必须的,位置写绝对路径
-
ssl=no
: SSL/TLS 完全禁用。 -
ssl=yes
且disable_plaintext_auth=no
: SSL/TLS 提供给客户端,但客户端不需要使用它。即使在连接上未启用 SSL/TLS,客户端也可以使用纯文本身份验证登录。这是不安全的,因为明文密码暴露在互联网上。 -
ssl=yes
且disable_plaintext_auth=yes
: SSL/TLS 提供给客户端,但客户端不需要使用它。不允许客户端使用明文身份验证,除非先启用 SSL/TLS。但是,如果启用了非明文身份验证机制,即使没有 SSL/TLS,它们仍然是允许的。根据它们的安全程度,身份验证要么是完全安全的,要么可能有一些方法使其受到攻击。 -
ssl=required
:即使使用非明文身份验证机制,也始终需要 SSL/TLS。任何在启用 SSL/TLS 之前进行身份验证的尝试都将导致身份验证失败。请注意,此设置与 STARTTLS 命令无关 - 允许使用隐式 SSL/TLS 或 STARTTLS 命令。 -
修改
/etc/dovecot
的权限,其中vmail为上面创建的用户
bash
chown -R vmail:dovecot /etc/dovecot
chmod -R o-rwx /etc/dovecot
- 重启postfix和dovecot,如此一postfix和dovecot就配置完成了。
OpenDKIM配置
-
安装OpenDKIM
sudo apt install opendkim opendkim-tools
-
修改配置文件
/etc/opendkim.conf
,确保有以下内容
bash
Domain xxxx.com
KeyFile /etc/dkimkeys/dkim.key
Selector dkim
SOCKET inet:8891@localhost
其中,SOCKET的端口可以使用8891,也有人使用8892,我没发现区别。
- 修改
/etc/default/opendkim
,确保有以下内容
ini
SOCKET="inet:8891@localhost"
-
生成dkim密钥对(一般在用户的家目录下生成,再复制到指定位置)
sudo opendkim-genkey -t -s dkim -d xxxx.com
然后执行移动操作
bash
sudo mv dkim.key /etc/dkimkeys/
sudo chown opendkim:opendkim dkim.key
- 在postfix的配置文件
/etc/postfix/main.cf
添加如下配置
ini
smtpd_milters = inet:localhost:8891
non_smtpd_milters = inet:localhost:8891
milter_protocol = 2
milter_default_action = accept
- 关注到第四步生成密钥对时产生的dkim.txt文件。
ini
dkim._domainkey IN TXT ( "v=DKIM1; k=rsa; t=y; "
"p=xxxxxxxxxx" ) ; ----- DKIM key dkim for Example Domain
复制双引号的内容,去除双引号和换行,整理为:v=DKIM1; k=rsa; t=y; p=xxxxxxxxxx
的形式。在域名添加为txt记录(主机记录为dkim._domainkey)。
- 重启postfix和opendkim,如此一来就配置完成了。
配置SpamAssassin
SpamAssassin为Postfix实现反垃圾的功能。
- 安装SpamAssassin
arduino
sudo apt-get install spamassassin spamc
- 添加用户
css
sudo adduser spamd --disabled-login
- 修改配置文件
/etc/default/spamassassin
,确保有如下配置:
ini
ENABLED=1
SAHOME="/var/log/spamassassin/"
OPTIONS="--create-prefs --max-children 5 --username spamd --helper-home-dir /home/spamd/ -s /home/spamd/spamd.log"
PIDFILE="/var/run/spamd.pid"
CRON=1
- 修改
/etc/spamassassin/local.cf
,确保有如下配置:
markdown
rewrite_header Subject ***** SPAM _SCORE_ *****
required_score 5.0
use_bayes 1
bayes_auto_learn 1
- 修改
/etc/postfix/master.cf
文件
添加配置:
ruby
spamassassin unix - n n - - pipe
user=spamd argv=/usr/bin/spamc -f -e
/usr/sbin/sendmail -oi -f ${sender} ${recipient}
为smtp,smtps和submission添加参数
ini
-o content_filter=spamassassin
有些教程只为smtp添加参数,我认为应该都添加。
添加之后,应该看上去像:
ini
smtp inet n - y - - smtpd
-o content_filter=spamassassin
- 执行
update-rc.d spamassassin enable
,然后重启postfix和spamassassin即可完成配置。
客户端连接服务器
客户端可以使用FoxMail或者雷鸟。
填写登录名为yyyy@xxxx.com以及密码,然后输入正确的smtp和pop3服务器地址以及端口号即可。
-
smtp默认25端口,SSL则是465端口。
-
pop3默认110端口,SSL则是995端口。
-
imap默认143端口,SSL则是993端口。
写在最后
以上是根据我配置邮件服务器的过程所总结的文章,我也折腾了快两个星期了。可能会有错误,欢迎留言咨询也以便我更正错误。