为什么要在VPS上自建邮件服务器
在云服务盛行的今天,许多开发者选择使用Gmail、Outlook等免费邮箱服务,或者购买腾讯企业邮、阿里企业邮等付费方案。然而,自建邮件服务器依然有着不可替代的优势:
- 完全掌控数据:邮件内容存储在自己的服务器上,不受第三方审查和隐私政策变更影响
- 无限制的邮箱账号:可以创建任意数量的邮箱地址,无需按账号付费
- 自定义域名邮箱:使用自己的域名(如 user@yourdomain.com),提升专业形象
- 学习价值:深入理解SMTP/IMAP协议和邮件系统的运作机制
- 灵活的过滤和转发规则:可以根据需求定制邮件处理逻辑
当然,自建邮件服务器的挑战也不容忽视——反垃圾邮件配置、邮件投递信誉维护、安全防护等都需要认真对待。本文将手把手带你完成一个生产级邮件服务器的搭建,涵盖所有关键环节。

系统架构与技术选型
一个完整的邮件系统由多个组件协同工作,我们选择的方案如下:
| 组件 | 软件 | 作用 |
|---|---|---|
| MTA(邮件传输代理) | Postfix | 处理SMTP协议,负责邮件的路由和投递 |
| MDA(邮件投递代理) | Dovecot | 处理IMAP/POP3协议,提供邮件存储和访问 |
| Webmail | Roundcube | 提供浏览器端邮件收发界面 |
| 数据库 | MySQL/MariaDB | 存储虚拟用户、域名和别名配置 |
| SSL证书 | Let’s Encrypt | 加密邮件传输,提升安全性 |
| 反垃圾邮件 | SpamAssassin | 邮件内容过滤和垃圾邮件识别 |
邮件的收发流程如下:
- 收信流程:外部MTA → DNS MX记录 → Postfix(25端口) → SpamAssassin过滤 → Dovecot存储 → 用户通过IMAP/Webmail读取
- 发信流程:用户通过Webmail/SMTP客户端 → Postfix(587端口+STARTTLS) → SPF/DKIM签名 → 投递到目标服务器
前置准备与DNS配置
服务器要求
建议的VPS配置:
- CPU:1核以上
- 内存:2GB以上(SpamAssassin比较吃内存)
- 存储:20GB以上SSD(取决于邮件量)
- 系统:Ubuntu 22.04 LTS 或 Debian 12
- 重要:确保VPS提供商未封禁25端口!部分云厂商(如AWS、阿里云)默认封禁25端口,需要申请解封
DNS记录配置
正确的DNS配置是邮件服务器正常工作的基础,也是最容易被忽视的环节。以下是你需要配置的所有DNS记录:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 # A记录 - 将邮件服务器域名指向VPS IP
mail.example.com. IN A 203.0.113.10
# MX记录 - 指定接收邮件的服务器
example.com. IN MX 10 mail.example.com.
# SPF记录 - 声明哪些服务器可以代表你的域名发送邮件
example.com. IN TXT "v=spf1 mx a ip4:203.0.113.10 -all"
# DKIM记录 - 邮件数字签名验证(后面配置OpenDKIM后生成)
selector._domainkey.example.com. IN TXT "v=DKIM1; k=rsa; p=MIGfMA0GCS..."
# DMARC记录 - 定义SPF/DKIM验证失败时的处理策略
_dmarc.example.com. IN TXT "v=DMARC1; p=quarantine; rua=mailto:dmarc@example.com; pct=100; adkim=r; aspf=r"
# PTR反向解析记录(rDNS)- 在VPS提供商控制台设置
10.113.0.203.in-addr.arpa. IN PTR mail.example.com.
其中PTR记录(反向DNS)非常关键——许多大型邮件服务商(Gmail、Outlook)会检查发送方IP的反向DNS是否指向正确的域名,如果不匹配,很可能将邮件标记为垃圾邮件。PTR记录通常在VPS提供商的管理面板中设置,而不是在你的DNS服务商处。

安装与配置Postfix
安装必要软件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 # 更新系统
apt update && apt upgrade -y
# 安装Postfix及依赖
DEBIAN_PRIORITY=low apt install -y postfix postfix-mysql \
dovecot-core dovecot-imapd dovecot-lmtpd dovecot-mysql \
mariadb-server mariadb-client \
nginx php8.1-fpm php8.1-mysql php8.1-mbstring php8.1-xml php8.1-intl php8.1-zip \
opendkim opendkim-tools spamassassin
# 安装Roundcube
apt install -y roundcube
# 安装certbot获取SSL证书
apt install -y certbot python3-certbot-nginx
安装Postfix时,系统会弹出配置界面,选择Internet Site,系统邮件名称填写你的主域名(如 example.com)。如果跳过了配置向导,可以用以下命令重新配置:
1 dpkg-reconfigure postfix
创建数据库和用户表
我们使用MySQL来管理虚拟用户,这样无需为每个邮箱创建系统账号:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45 # 登录MySQL
mysql -u root
# 创建邮件数据库和用户
CREATE DATABASE mailserver;
CREATE USER 'mailuser'@'127.0.0.1' IDENTIFIED BY 'YourStrongPassword123!';
GRANT SELECT ON mailserver.* TO 'mailuser'@'127.0.0.1';
FLUSH PRIVILEGES;
USE mailserver;
-- 虚拟域名表
CREATE TABLE virtual_domains (
id int(11) NOT NULL AUTO_INCREMENT,
name varchar(50) NOT NULL,
PRIMARY KEY (id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
-- 虚拟用户表
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=utf8mb4;
-- 虚拟别名表
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=utf8mb4;
-- 插入初始数据
INSERT INTO virtual_domains (id, name) VALUES (1, 'example.com');
INSERT INTO virtual_users (id, domain_id, password, email)
VALUES (1, 1, ENCRYPT('UserPassword123!', CONCAT('$6$', SUBSTRING(SHA(RAND()), -16))), 'admin@example.com');
INSERT INTO virtual_aliases (id, domain_id, source, destination)
VALUES (1, 1, 'postmaster@example.com', 'admin@example.com');
配置Postfix使用MySQL
编辑Postfix主配置文件
1 | /etc/postfix/main.cf |
:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72 # /etc/postfix/main.cf
# 基本设置
myhostname = mail.example.com
mydomain = example.com
myorigin = $mydomain
mydestination = localhost
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128
inet_interfaces = all
inet_protocols = ipv4
# 虚拟用户配置
virtual_mailbox_domains = mysql:/etc/postfix/mysql-virtual-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_mailbox_base = /var/mail/vhosts
virtual_uid_maps = static:5000
virtual_gid_maps = static:5000
# 使用Dovecot投递
virtual_transport = lmtp:unix:private/dovecot-lmtp
# SASL认证(通过Dovecot)
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
smtpd_sasl_security_options = noanonymous
# TLS加密
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_tls_loglevel = 1
smtpd_tls_received_header = yes
smtpd_tls_session_cache_timeout = 3600s
smtpd_tls_security_level = may
# 发送TLS
smtp_tls_security_level = may
smtp_tls_loglevel = 1
# 反垃圾邮件和安全设置
smtpd_helo_required = yes
smtpd_helo_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_invalid_helo_hostname,
reject_non_fqdn_helo_hostname
smtpd_recipient_restrictions =
permit_sasl_authenticated,
permit_mynetworks,
reject_unauth_destination,
reject_unauth_pipelining,
reject_non_fqdn_recipient,
reject_unknown_recipient_domain
smtpd_sender_restrictions =
permit_sasl_authenticated,
permit_mynetworks,
reject_non_fqdn_sender,
reject_unknown_sender_domain
# 邮件大小限制(50MB)
message_size_limit = 52428800
# OpenDKIM
milter_protocol = 6
milter_default_action = accept
smtpd_milters = inet:localhost:8891
non_smtpd_milters = $smtpd_milters
创建MySQL查询配置文件:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 # /etc/postfix/mysql-virtual-domains.cf
user = mailuser
password = YourStrongPassword123!
hosts = 127.0.0.1
dbname = mailserver
query = SELECT 1 FROM virtual_domains WHERE name='%s'
# /etc/postfix/mysql-virtual-mailbox-maps.cf
user = mailuser
password = YourStrongPassword123!
hosts = 127.0.0.1
dbname = mailserver
query = SELECT 1 FROM virtual_users WHERE email='%s'
# /etc/postfix/mysql-virtual-alias-maps.cf
user = mailuser
password = YourStrongPassword123!
hosts = 127.0.0.1
dbname = mailserver
query = SELECT destination FROM virtual_aliases WHERE source='%s'
保护这些配置文件的权限:
1
2 chown root:postfix /etc/postfix/mysql-*.cf
chmod 640 /etc/postfix/mysql-*.cf
安装与配置Dovecot
Dovecot负责IMAP/POP3服务和本地邮件投递(通过LMTP)。核心配置文件在
1 | /etc/dovecot/ |
目录下:
主配置文件
1
2
3
4
5
6
7 # /etc/dovecot/dovecot.conf
# 启用的协议
protocols = imap lmtp
# 包含conf.d目录下的配置
!include conf.d/*.conf
认证配置
1
2
3
4
5
6
7 # /etc/dovecot/conf.d/10-auth.conf
disable_plaintext_auth = yes
auth_mechanisms = plain login
# 禁用系统用户认证,仅使用SQL
!include auth-sql.conf.ext
SQL认证后端
1
2
3
4
5 # /etc/dovecot/dovecot-sql.conf.ext
driver = mysql
connect = host=127.0.0.1 dbname=mailserver user=mailuser password=YourStrongPassword123!
default_pass_scheme = SHA512-CRYPT
password_query = SELECT email as user, password FROM virtual_users WHERE email='%u';
邮件存储配置
1
2
3
4
5
6
7
8
9
10 # /etc/dovecot/conf.d/10-mail.conf
mail_location = maildir:/var/mail/vhosts/%d/%n/Maildir
mail_uid = 5000
mail_gid = 5000
first_valid_uid = 5000
last_valid_uid = 5000
first_valid_gid = 5000
last_valid_gid = 5000
SSL/TLS配置
1
2
3
4
5
6
7
8 # /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_protocols = !SSLv3 !TLSv1 !TLSv1.1
ssl_cipher_list = ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384
ssl_prefer_server_ciphers = yes
LMTP和SASL认证
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 # /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 = 0660
user = postfix
group = postfix
}
unix_listener auth-userdb {
mode = 0600
user = vmail
group = vmail
}
}
service auth-worker {
user = vmail
}
创建vmail用户和邮件存储目录:
1
2
3
4
5 groupadd -g 5000 vmail
useradd -g vmail -u 5000 vmail -s /usr/sbin/nologin -d /var/mail/vhosts
mkdir -p /var/mail/vhosts/example.com/admin
chown -R vmail:vmail /var/mail/vhosts
chmod -R 770 /var/mail/vhosts
DKIM签名与反垃圾邮件
配置OpenDKIM
DKIM(DomainKeys Identified Mail)是邮件投递信誉的关键。它在发出的邮件中添加数字签名,接收方可以通过DNS中的公钥验证邮件确实来自你的域名:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 # /etc/opendkim.conf
AutoRestart Yes
AutoRestartRate 10/1h
Syslog yes
SyslogSuccess yes
LogWhy yes
Canonicalization relaxed/simple
Mode sv
SubDomains no
OversignHeaders From
# 密钥和签名表
KeyTable refile:/etc/opendkim/key.table
SigningTable refile:/etc/opendkim/signing.table
ExternalIgnoreList refile:/etc/opendkim/trusted.hosts
InternalHosts refile:/etc/opendkim/trusted.hosts
Socket inet:localhost:8891
PidFile /run/opendkim/opendkim.pid
UMask 007
UserID opendkim
生成DKIM密钥:
1
2
3
4
5
6
7
8
9 # 创建目录结构
mkdir -p /etc/opendkim/keys/example.com
# 生成密钥对
opendkim-genkey -b 2048 -d example.com -D /etc/opendkim/keys/example.com/ -s default -v
# 设置权限
chown -R opendkim:opendkim /etc/opendkim
chmod go-rw /etc/opendkim/keys/example.com/default.private
配置签名表和密钥表:
1
2
3
4
5
6
7
8
9
10 # /etc/opendkim/signing.table
*@example.com default._domainkey.example.com
# /etc/opendkim/key.table
default._domainkey.example.com example.com:default:/etc/opendkim/keys/example.com/default.private
# /etc/opendkim/trusted.hosts
127.0.0.1
localhost
mail.example.com
生成完成后,将公钥添加到DNS记录:
1
2
3
4
5 # 查看生成的公钥
cat /etc/opendkim/keys/example.com/default.txt
# 将输出的TXT记录添加到DNS(格式如下)
default._domainkey.example.com. IN TXT "v=DKIM1; h=sha256; k=rsa; p=MIIBIjANBg..."
配置SpamAssassin
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 # 启用SpamAssassin
sed -i 's/ENABLED=0/ENABLED=1/' /etc/default/spamassassin
# 启用自动规则更新
crontab -e
# 添加:0 2 * * * sa-update && systemctl restart spamassassin
# 配置Postfix集成SpamAssassin
# /etc/postfix/master.cf 在smtp条目后添加:
smtp inet n - y - - smtpd
-o content_filter=spamassassin
spamassassin unix - n n - - pipe
user=debian-spamd argv=/usr/bin/spamc -f -e /usr/sbin/sendmail -oi -f ${sender} ${recipient}
# 启动服务
systemctl enable spamassassin
systemctl start spamassassin

获取SSL证书与配置Roundcube
Let’s Encrypt证书
1
2
3
4
5
6
7
8
9 # 获取证书
certbot certonly --nginx -d mail.example.com
# 设置自动续期(certbot已自动添加cron)
certbot renew --dry-run
# 确保证书权限正确
chmod 644 /etc/letsencrypt/live/mail.example.com/fullchain.pem
chmod 600 /etc/letsencrypt/live/mail.example.com/privkey.pem
配置Roundcube Webmail
Roundcube是一个现代化的Web邮件客户端,提供类似Gmail的用户体验:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32 # /etc/roundcube/config.inc.php 关键配置
$config['db_dsnw'] = 'mysql://roundcube:RoundcubePass123!@localhost/roundcube';
$config['default_host'] = 'tls://mail.example.com';
$config['default_port'] = 993;
$config['smtp_server'] = 'tls://mail.example.com';
$config['smtp_port'] = 587;
$config['smtp_user'] = '%u';
$config['smtp_pass'] = '%p';
$config['support_url'] = 'https://mail.example.com/support';
$config['product_name'] = 'My Mail Server';
$config['plugins'] = array(
'archive',
'zipdownload',
'markasjunk',
'password'
);
$config['des_key'] = 'rcmail-!24ByteDESkey*Str'; // 请替换为随机字符串
$config['imap_conn_options'] = array(
'ssl' => array(
'verify_peer' => true,
'verify_peer_name' => true,
'peer_name' => 'mail.example.com',
),
);
$config['smtp_conn_options'] = array(
'ssl' => array(
'verify_peer' => true,
'verify_peer_name' => true,
'peer_name' => 'mail.example.com',
),
);
配置Nginx反向代理:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41 # /etc/nginx/sites-available/mail.example.com
server {
listen 80;
server_name mail.example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name mail.example.com;
ssl_certificate /etc/letsencrypt/live/mail.example.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/mail.example.com/privkey.pem;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
ssl_prefer_server_ciphers on;
root /var/lib/roundcube;
index index.php;
location / {
try_files $uri $uri/ /index.php?$args;
}
location ~ \.php$ {
include snippets/fastcgi-php.conf;
fastcgi_pass unix:/run/php/php8.1-fpm.sock;
fastcgi_param HTTPS on;
}
location ~ /\.(ht|svn|git) {
deny all;
}
# 安全头
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
}
启动服务与测试验证
启动所有服务
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 # 创建邮件存储目录并设置权限
mkdir -p /var/mail/vhosts
chown -R vmail:vmail /var/mail/vhosts
# 启动并启用所有服务
systemctl restart postfix
systemctl restart dovecot
systemctl restart opendkim
systemctl restart spamassassin
systemctl restart nginx
systemctl restart php8.1-fpm
systemctl enable postfix dovecot opendkim spamassassin nginx php8.1-fpm
# 检查服务状态
systemctl status postfix dovecot opendkim nginx
验证配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14 # 测试SMTP
swaks --to test@gmail.com --from admin@example.com \
--server mail.example.com:587 --tls \
--auth LOGIN --auth-user admin@example.com
# 测试IMAP
openssl s_client -connect mail.example.com:993 -quiet
# 登录:a001 LOGIN admin@example.com YourPassword
# 检查端口监听
ss -tlnp | grep -E '(25|587|993|995|443)'
# 查看Postfix日志
tail -f /var/log/mail.log
验证DNS和信誉
使用以下在线工具验证你的邮件服务器配置:
- MXToolbox(mxtoolbox.com):检查MX记录、SPF、DKIM、DMARC、黑名单
- Mail Tester(mail-tester.com):发送测试邮件到其地址,获取10分制评分
- DMARC Analyzer(dmarcanalyzer.com):DMARC报告分析
- Google Postmaster Tools:监控Gmail投递信誉
一个配置良好的邮件服务器应该在Mail Tester上获得9/10分以上的评分。如果分数较低,根据反馈逐步优化。
邮件投递信誉维护
搭建好邮件服务器只是第一步,维护良好的投递信誉才能确保邮件不被拒收:
- 预热IP:新IP地址需要逐步增加发信量,第一天不超过50封,一周内逐步增加到正常量
- 处理退信:及时清理无效邮箱地址,高退信率会严重影响信誉
- 监控黑名单:定期检查IP是否被列入RBL黑名单,一旦发现立即申请移除
- 设置DMARC报告:配置rua参数接收DMARC聚合报告,了解邮件认证情况
- 避免突发大量发送:即使是合法邮件,短时间内大量发送也会触发垃圾邮件过滤
- 响应退订请求:确保邮件中有明确的退订链接,并及时处理退订
安全加固建议
邮件服务器是互联网上最常被攻击的服务之一,以下是关键的安全措施:
- Fail2Ban:自动封禁暴力破解IP
- 防火墙:仅开放必要端口(25, 587, 993, 443)
- 关闭开放中继:确保Postfix不充许未认证的外部发信
- 定期更新:保持所有组件的最新安全补丁
- 日志监控:设置异常登录和大量发信的告警
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 # 安装Fail2Ban
apt install -y fail2ban
# /etc/fail2ban/jail.local
[postfix]
enabled = true
port = smtp,ssmtp
filter = postfix
logpath = /var/log/mail.log
maxretry = 5
bantime = 3600
[dovecot]
enabled = true
port = smtp,ssmtp,imap2,imap3
filter = dovecot
logpath = /var/log/mail.log
maxretry = 5
bantime = 3600
# 启动
systemctl enable fail2ban
systemctl start fail2ban
# UFW防火墙规则
ufw allow 22/tcp # SSH
ufw allow 25/tcp # SMTP
ufw allow 587/tcp # Submission
ufw allow 993/tcp # IMAPS
ufw allow 443/tcp # HTTPS
ufw enable
常见问题排查
自建邮件服务器难免遇到问题,以下是最常见的问题和解决方案:
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| 邮件被Gmail拒收 | 缺少SPF/DKIM/PTR记录 | 完善DNS记录,检查rDNS |
| 无法发送邮件 | 25端口被封或SASL配置错误 | telnet测试25端口,检查Dovecot认证 |
| IMAP登录失败 | 密码加密方式不匹配 | 确认default_pass_scheme与数据库中密码格式一致 |
| DKIM签名失败 | 权限问题或配置路径错误 | 检查opendkim用户对密钥文件的读取权限 |
| 大量垃圾邮件 | SpamAssassin未启用或规则过时 | 确认spamc集成,更新规则库 |
| 连接超时 | 防火墙阻止或服务未启动 | 检查ufw规则和systemctl状态 |
自建邮件服务器是一项需要耐心和持续维护的工作,但掌握它不仅能获得完全自主的通信能力,更能深入理解互联网邮件系统的运作机制。按照本文的步骤操作,你将在一台VPS上搭建起一个生产级的邮件系统,足以满足个人或小型团队的日常邮件需求。
汤不热吧