Ubuntu 22.04搭建Postfix+Dovecot邮件系统:内网SMTP与IMAP全配置指南
2026/9/13 6:06:41 网站建设 项目流程

最近有个需求折腾了我一晚上——要在内网快速搭一套邮件系统,用于测试环境的通知发送、定时报告投递,顺带承接一个旧应用残留的SMTP调用。本来想直接用现成的第三方邮件服务,结果测试环境出于安全考虑不允许出公网,只能在本地方案里选。对比了一圈,最省事、最稳的仍然是Postfix + Dovecot这个老牌组合。

Postfix负责SMTP发信和收信,Dovecot负责IMAP/POP3取信,两个加起来就是一套完整的邮件系统。Ubuntu 22.04(标题里写成22.40,实际对应的是Jammy,22.04 LTS)的软件源里这两个包都有现成版本,装完做基础配置就能跑,完全不需要商业组件。这篇就把我这次的完整操作记录下来,从环境准备到收发信验证,再到最常见的坑,一次说清楚。

1. 先想清楚:本地邮件系统到底解决了什么问题

很多人一听自建邮件系统就觉得麻烦,其实得看场景。如果你只是想让某台服务器能往外发告警邮件,那Postfix一个就够,Dovecot根本不用上。但如果你的应用需要IMAP去拉取特定邮箱的内容,或者团队内部需要几个真实可用的邮箱账号互相收发信来联调业务流程,那Postfix+Dovecot是必须的组合。

我这次的需求就属于后者:一套内部系统要向若干个虚拟用户邮箱发通知,同时有一个服务会通过IMAP去轮询某个收件箱里的邮件做后续自动化处理。两个需求叠在一起,任何单一组件都搞不定,只能配合使用。

再聊聊方案选型。邮件系统的开源方案其实不少,除了Postfix+Dovecot,还有OpenSMTPD、Haraka、Mailcow这种全家桶。我选Postfix+Dovecot的理由很朴素:

  • 两者都是Linux邮件系统的事实标准,文档多,踩坑经验好搜。
  • 包管理直接安装,不引入容器、数据库等额外依赖。
  • 配置结构清晰,一个发信、一个取信,职责分开,出了问题好定位。
  • 对低配虚拟机很友好,512MB内存跑这两个服务毫无压力。

Mailcow这类全家桶固然省事,但它需要Docker和Compose,还自带数据库、Web界面和一堆容器服务,在纯内网测试环境里属于杀鸡用牛刀,而且问题排查链路太长。Postfix+Dovecot这种拆分式架构反而更适合需要搞清楚每一封邮件流转的场合。

2. 环境准备和主机名规划:这部分偷懒后面必踩坑

2.1 系统版本和软件源确认

先在服务器上确认系统版本,Ubuntu 22.04的代号是jammy,对应内核6.x。执行下面命令看下:

lsb_release -a

如果是Ubuntu 22.04.1到22.04.4之间的任意一个小版本,软件源里的postfix版本都是3.6.x,dovecot版本是2.3.16,这套组合已经经过大量生产环境验证,直接用没问题。

安装前先做两件事:更新软件源缓存、确保时区正确。邮件头里的Date字段依赖系统时间,如果服务器时区或时间不对,邮件客户端显示的时间会混乱,排查问题的时候也容易产生误导。

sudo apt update sudo timedatectl set-timezone Asia/Shanghai

2.2 主机名与域名规划:最容易被忽略的坑

这是整篇里我最想强调的部分。邮件系统对主机名(hostname)和域名(domain)极其敏感,服务启动时会用hostname来标识自己,发出去的邮件头里会带上这个标识,收件方的邮件服务器也会根据这个标识来反查服务器身份。

我这里有一个反例。第一次部署时图省事,直接用了默认的hostname,结果Postfix起来后只认本机的短主机名,发出去的邮件From字段变成了user@ubuntu,在Dovecot里配置的虚拟域名完全不生效,联调了半天才发现是主机名的问题。

正确的做法是:先规划好一个完整的邮件域名,比如mail.local(内网环境用.local或.internal这类保留域名最安全,但注意不要和公网真实域名冲突),然后把服务器的主机名设为该域名的主机部分。

sudo hostnamectl set-hostname mail.local

同时编辑/etc/hosts,把主机名解析写进去:

127.0.0.1 localhost 127.0.0.1 mail.local mail

这条hosts记录很关键。Postfix在启动时会查hostname对应的IP,如果解析不到,它会回退到一种保守模式,日志里不断报unable to look up hostname之类的问题,所有收发信全部异常。不要指望去依赖内网DNS,编辑hosts是最快最稳的解决办法。

2.3 安装软件包

确认好主机名后,安装就很直接:

sudo apt install postfix dovecot-imapd dovecot-pop3d -y

安装Postfix过程中,安装器会弹出一个配置界面,问你邮件服务器类型。这里选择"Internet Site",系统类型填你规划的域名mail.local。如果这一步不小心选错了也没关系,后续可以通过dpkg-reconfigure postfix重新配置。

这里顺手装dovecot-imapd和dovecot-pop3d两个子包,它们会把dovecot核心和对应协议的插件一起装进来。如果只装dovecot-core,后面还需要手动装协议扩展,很麻烦。

3. Postfix部分:一封邮件的SMTP之旅从这开始

3.1 main.cf里值得改的几个关键参数

Postfix的主配置文件是/etc/postfix/main.cf,Ubuntu安装好以后会有一个默认配置。这个默认配置可以直接跑起来,但不适合我们的场景,需要做几处调整。

先看几个核心参数的意义:

  • myhostname:Postfix用来标识自己主机身份的完全限定域名,默认读取系统hostname,但显式写出来更清晰。
  • mydomain:邮件域。
  • myorigin:发出去的邮件From地址里@后面的部分。希望所有本机发的邮件都显示为user@mail.local,就把myorigin设为$mydomain
  • mydestination:Postfix接受的本机投递域名列表。当一个邮件发往user@mail.local时,Postfix发现自己就是mail.local的权威服务器,才会接收这封邮件。如果不配置这个,Postfix会拒绝掉所有发给自己域的邮件。
  • home_mailbox:决定用户邮件保存在家目录的哪个文件。
  • inet_interfaces:监听网络接口。测试环境希望内网其他机器也能通过SMTP来中继发信,就要设为all,不能只监听loopback。

我最后使用的配置关键段落如下:

sudo nano /etc/postfix/main.cf
myhostname = mail.local mydomain = mail.local myorigin = $mydomain mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain inet_interfaces = all inet_protocols = ipv4 home_mailbox = Maildir/ mailbox_command =

这里重点说下home_mailbox = Maildir/。传统Linux邮箱格式是mbox,所有邮件堆在一个文件里,Dovecot读取、应用遍历都不方便,锁竞争也严重。Maildir格式每封邮件一个独立文件,更稳,也符合现代邮件系统的主流用法。设置成Maildir后,每个系统用户的邮件会落在/home/用户名/Maildir/目录里。

inet_protocols = ipv4要单拎出来说。如果服务器没有IPv6环境,而Postfix默认同时监听IPv4和IPv6,启动时虽然会成功,但日志里会有地址绑定警告。强制只用IPv4可以避免这些无谓的告警,也让后续排错更省心。

3.2 真正的用户:邮件账号从哪来

这里涉及一个关键设计决策。默认情况下,Postfix+Dovecot配合系统用户使用,即每个Linux用户就对应一个邮箱账号,密码就是系统密码。这种模式的好处是配置简单,但有一个天然的坏处:系统安全的暴露面增大了。举个例子,需要新增一个邮箱账号时,就有责任给它分配一个系统shell、一个家目录,这可能带来安全风险。

测试环境我没这么讲究,直接用系统用户模式。后续如果想上虚拟用户模式,还需要引入数据库表来映射账号和密码,Postfix里要用virtual_alias_domains和virtual_mailbox_domains那一套配置,复杂度会明显上来。

创建邮件用户的命令很简单:

sudo useradd -m -s /usr/sbin/nologin alice sudo passwd alice

-s /usr/sbin/nologin的作用是让这个用户无法登录shell,只能收邮件,更安全些。家目录要保留,因为Dovecot要把邮件写到用户的家目录里。

按照plan我会创建两个测试账号,一个用于发信测试,一个用于IMAP轮询测试:

sudo useradd -m -s /usr/sbin/nologin alice sudo passwd alice sudo useradd -m -s /usr/sbin/nologin bob sudo passwd bob

3.3 启动和验证Postfix

配置完毕,先语法检查再重启:

sudo postfix check sudo systemctl restart postfix sudo systemctl status postfix

postfix check这个命令会检查配置文件里所有引用的路径和权限。如果有错误,它会直接指出具体是哪一行配置有问题,这是定位配置错误最高效的手段,比看日志快得多。

如果状态显示active,可以通过本地发送测试邮件来看基本功能是否正常:

echo "test email body" | mail -s "test subject" alice@localhost

这条命令会调用本机的sendmail接口,把邮件投递给本地用户alice。然后去检查alice的Maildir:

sudo ls -la /home/alice/Maildir/ sudo ls -la /home/alice/Maildir/new/

如果new目录下有文件,说明Postfix的投递链路已经通了。这封邮件现在躺在alice的Maildir队列里,等Dovecot起来后就可以通过IMAP读出来。

4. Dovecot部分:让邮件能读出来才是完整闭环

Postfix解决了邮件的收发和投递,但它不提供读取接口。就像快递公司把包裹送到你家门口,但你没有钥匙打开邮箱拿信。Dovecot就是那把钥匙,为邮件客户端提供IMAP和POP3的访问入口。

4.1 Dovecot的配置文件结构

Dovecot的配置和Postfix有很大不同,它采用多个文件分散配置的方式,主配置在/etc/dovecot/dovecot.conf,其他模块则通过conf.d目录下的文件管理。这种设计的好处是模块清晰,坏处是新手容易找不到设置项到底在哪个文件。

我这次主要改的文件:

  • /etc/dovecot/dovecot.conf:开启协议支持。
  • /etc/dovecot/conf.d/10-mail.conf:配置邮件存储位置。
  • /etc/dovecot/conf.d/10-auth.conf:配置认证方式。
  • /etc/dovecot/conf.d/10-master.conf:配置服务监听端口和Postfix的权限对接。

4.2 核心配置:邮件位置和认证模式

先改10-mail.conf,把Dovecot识别的邮件目录格式和Postfix写入的格式对齐。因为我们在Postfix里用了Maildir,这边也必须告诉Dovecot用Maildir去读:

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

mail_location设为:

mail_location = maildir:~/Maildir

然后改10-auth.conf,启用系统用户PAM认证,并允许明文认证(内网环境可以先这样跑,测试没问题再上TLS):

sudo nano /etc/dovecot/conf.d/10-auth.conf
disable_plaintext_auth = no auth_mechanisms = plain login

注意disable_plaintext_auth = no是内网测试环境起步用的配置。一旦对外开放,明文密码就等于裸奔,必须配合TLS加密并且把这项改回yes。这部分我在第6节专门展开。

主配置文件里确认协议是激活的:

sudo nano /etc/dovecot/dovecot.conf
protocols = imap pop3

4.3 让Postfix投递的邮件能进Dovecot的权限圈

接下来是整套系统里最常见的一个坑:权限。Postfix以postfix用户身份投递邮件,写的邮件文件属主是postfix。Dovecot以后台dovecot用户身份尝试读取邮件,结果没有权限,直接报错,客户端登录后看不到任何邮件。

解决方式是在10-master.conf里,把Postfix投递服务对应的unix socket配置一下,让邮件投递后Dovecot有权限读取。具体来说,找到service postfix相关的段落,确保它的组和权限设置允许dovecot访问。

实际操作中我是这样改的:

sudo nano /etc/dovecot/conf.d/10-master.conf
service postfix { unix_listener /var/spool/postfix/private/auth { mode = 0660 user = postfix group = postfix } }

这段配置实际上是给Postfix的SMTP认证(SASL)用的。如果你不需要客户端通过SMTP发送认证(比如只允许内网IP中继发信),这个可以暂时不配。但既然要走完整流程,我建议直接配上,因为它也顺带解决了dovecot-lda投递的权限衔接问题。

Dovecot自带一个LDA(Local Delivery Agent)工具,可以代替Postfix自己往Maildir里丢邮件,它更懂Maildir格式,还能自动创建目录,是更推荐的做法。想让Postfix用Dovecot的LDA来做本地投递,需要在main.cf里加一行:

sudo nano /etc/postfix/main.cf
mailbox_command = /usr/lib/dovecot/dovecot-lda -f "$SENDER" -- "$RECIPIENT"

这行配置的意思是:Postfix收到本域邮件后,不自己往用户邮件目录里塞,而是交给dovecot-lda处理。这样做的好处很多,包括自动创建Maildir目录、正确维护索引、支持sieve脚本过滤等。配合前面的权限配置,dovecot-lda能以对应用户的身份投递,用户自己的邮件自己读,权限问题从根上消失。

改完重启Dovecot和Postfix:

sudo systemctl restart dovecot postfix

4.4 用telnet实测Dovecot的IMAP功能

不看配置自信直接上客户端是个坏习惯。我习惯先用telnet或nc手动测一遍IMAP端口,确认服务真的在工作。

sudo apt install telnet -y telnet 127.0.0.1 143

连上后输入:

a1 LOGIN alice 密码 a2 LIST "" "*" a3 SELECT INBOX a4 LOGOUT

如果登录成功并且能SELECT INBOX,说明Dovecot的认证和邮件访问链路都是通的。我之前遇到过一种情况:Postfix那边能投递,但Dovecot登录后看不到邮件,最后排查下来就是10-master.conf里权限配置没到位。telnet这条手动链路测试能让你快速区分问题出在认证环节还是邮件读取环节。

5. 联调验证和排错:这五个坑几乎每次都会遇到

5.1 第一封真正的全链路邮件:从SMTP发送到IMAP读取

配置全部就位后,我开始做全链路验证。在一台内网客户端上,用telnet直接跑一遍SMTP发信,绕开任何客户端自动补全的干扰,最干净:

telnet 192.168.1.100 25
EHLO test.local MAIL FROM: <alice@mail.local> RCPT TO: <bob@mail.local> DATA Subject: test from alice Hello bob, this is a test. . QUIT

如果Postfix返回250 OK,说明服务器已经接受这封邮件。接着登录bob的邮箱就能看到。这一步走通,整个闭环就成立了:Alice发出邮件,Postfix接收投递,Dovecot提供读信接口,Bob用任何邮件客户端登录就能看到。

5.2 坑一:防火墙没放行端口

Ubuntu默认开启ufw防火墙时,25、143、110这些端口不会自动放行。如果邮件客户端连接超时,多半是这里的问题:

sudo ufw allow 25/tcp sudo ufw allow 143/tcp sudo ufw allow 110/tcp sudo ufw allow 587/tcp sudo ufw allow 993/tcp sudo ufw allow 995/tcp

25是SMTP,143是IMAP,110是POP3,587是SMTP提交端口(带认证),993和995是SSL加密版的IMAP和POP3。测试环境可以先把前三个放开,加密端口等上TLS时再开。

5.3 坑二:IPv6监听导致的日志混乱

前面提到的inet_protocols = ipv4,如果在Postfix配置里没处理,系统日志会刷类似no IPv6 addresses available的警告,虽然不影响发信,但是会严重干扰排错时看日志的效率。在干净的环境里一次性配置好,后面少很多麻烦。

5.4 坑三:Dovecot认证失败的排查步骤

客户端登录提示认证失败,可能的原因太多。我遇到最多的是password没同步,或者系统用户没有密码。用sudo passwd alice重新设置一下密码,然后看日志:

sudo tail -f /var/log/mail.log

Dovecot的认证失败信息会非常明确地出现在这里,比如authentication failure,它会告诉你用户名是否存在、密码是否为空。不要瞎猜,直接看日志是最快的路。

5.5 坑四:Postfix mydestination没配好导致拒收本域邮件

发往bob@mail.local的邮件,Postfix如果返回Relay access denied,基本可以断定是mydestination里没有包含mail.local。Postfix的逻辑是:收到一封信,先看收件域名是否属于自己管理(mydestination),如果属于就接收投递;不属于,就看是否允许中继转发;再不行就拒绝。所以自己的域名一定得写进mydestination,否则系统会认为你在尝试转发陌生域名的邮件,安全策略直接拦下。

5.6 坑五:邮件客户端发信还需要SMTP认证

如果配置完成后,邮件客户端连接时提示SMTP需要认证,但Postfix还没开SASL,客户端会弹出反复输密码的窗口。这时需要确认两点:一是前面10-master.conf里的auth socket配置存在且进程监听正常;二是在main.cf里确认真实开启了对客户端SMTP认证的接受:

sudo nano /etc/postfix/main.cf
smtpd_sasl_type = dovecot smtpd_sasl_path = private/auth smtpd_sasl_auth_enable = yes smtpd_relay_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination

permit_mynetworks允许内网段机器免认证发信,permit_sasl_authenticated允许通过认证的客户端发信,reject_unauth_destination拒绝所有未知目标域名的邮件。这三条加在一起,既能保障内网方便,又能杜绝开放中继变成垃圾邮件跳板。

6. TLS加密和后续加固:内网不等于安全豁免区

测试环境很多人会忽略TLS,但我的建议是,既然要搭就把TLS一起配上,理由有两个:一是邮件客户端默认对未加密连接会有安全弹窗,很烦;二是Dovecot配置一次TLS之后,以后生产环境迁移省得再折腾。

6.1 自签名证书生成和配置

内网环境没必要去买公网证书,用openssl自签一个就行。生成一个同时包含私钥和证书的文件:

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -keyout /etc/dovecot/private/dovecot.pem \ -out /etc/dovecot/private/dovecot.pem \ -subj "/C=CN/ST=Local/L=Local/O=Local/CN=mail.local"

Postfix也需要一份,可以直接复用同一个文件,也可以单独生成一份:

sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -keyout /etc/postfix/smtpd.pem \ -out /etc/postfix/smtpd.pem \ -subj "/C=CN/ST=Local/L=Local/O=Local/CN=mail.local"

注意自签名证书在客户端第一次连接时会有不可信告警,内网测试环境属于正常现象,点信任即可。

6.2 Postfix开启SMTPS和Submission

Postfix的TLS配置在main.cf追加:

smtpd_tls_cert_file = /etc/postfix/smtpd.pem smtpd_tls_key_file = /etc/postfix/smtpd.pem smtpd_tls_security_level = may smtpd_tls_auth_only = yes

security_level = may表示兼容明文和TLS连接,客户端想加密就加密,不想加密也能发(测试阶段方便)。auth_only = yes表示SMTP认证必须发生在TLS加密通道上,避免密码被明文截获。

同时还要在master.cf里启用submission端口(587),这是客户端发信的标准端口:

sudo nano /etc/postfix/master.cf

找到submission相关行,取消注释:

submission inet n - y - - smtpd -o syslog_name=postfix/submission -o smtpd_tls_security_level=encrypt -o smtpd_sasl_auth_enable=yes

6.3 Dovecot启用IMAPS和POP3S

Dovecot的TLS配置在10-ssl.conf里:

sudo nano /etc/dovecot/conf.d/10-ssl.conf
ssl = required ssl_cert = </etc/dovecot/private/dovecot.pem ssl_key = </etc/dovecot/private/dovecot.pem

ssl = required表示所有连接必须走TLS,这样明文密码的担忧就可以放下。配置完后,IMAP客户端要连993端口而不是143,POP3要连995而不是110。

全部改完,重启服务:

sudo systemctl restart postfix dovecot

用之前telnet的方式再测一遍,这次连993端口,并带上TLS:

openssl s_client -connect 127.0.0.1:993 -quiet

如果证书链正常,握手成功,说明TLS已经生效。

6.4 关于开放中继的最后提醒

邮件服务器最危险的一件事就是变成开放中继:任何外部服务器都能通过你的机器转发垃圾邮件,结果就是IP被各类黑名单封禁。之前配过reject_unauth_destination,这条规则已经把大部分风险拦住了。如果你只用mynetworks里的IP段做中继,还可以在main.cf的mynetworks里明确只写自己内网段:

mynetworks = 127.0.0.0/8 192.168.0.0/16 10.0.0.0/8

最后可以用这个命令快速自测是否开放中继:

telnet 127.0.0.1 25

输入:

MAIL FROM: <spam@example.com> RCPT TO: <victim@example.org>

如果返回554 Relay access denied,说明中继限制生效,这很关键。

7. 进程自启和日志监控:系统跑起来只是开始

邮件系统不是配完就完事的,它需要7x24小时在后台默默工作。这里有几个我在实际使用中离不开的后勤动作。

第一是确保开机自启:

sudo systemctl enable postfix dovecot

第二是日志监控。邮件系统的所有活动都记录在/var/log/mail.log,这是排查问题的第一现场。我习惯用跟踪模式实时看日志:

sudo tail -f /var/log/mail.log

日志会记录每个连接、每封邮件的来源、去向、状态、错误信息。收到一封邮件,日志里的每一行都能还原它的完整旅程:哪台机器连上来,用哪个账号发的信,发到哪个域,投递结果如何。

第三是配置a定时清理。测试环境邮件会越积越多,长期不清理会占用大量磁盘。可以简单写个cron,定时把超过30天的邮件清除:

sudo crontab -e
0 2 * * * find /home/*/Maildir/cur -type f -mtime +30 -delete 0 3 * * * find /home/*/Maildir/new -type f -mtime +30 -delete

这一步虽小,但能让你的邮件服务器不至于运行半年后把磁盘塞满。

整套系统跑通之后,我在实际使用中发现几个顺手的改进空间:

如果后续要支持邮件别名,比如ops@mail.local同时投递给多个运维成员,可以在Postfix里配aliases文件,修改/etc/aliases然后执行newaliases生效。如果要做更细粒度的邮件过滤,比如自动把特定主题的邮件归档,Dovecot可以接sieve插件,在用户家目录放一个.dovecot.sieve就能实现规则过滤。这些属于解锁完整邮件服务后的外延功能,每一步都有对应的官方文档支持。

还有就是如果你希望这套系统后续能对外收发公网邮件,那必须有一个真实域名和公网IP,还要配置MX记录、PTR反向解析以及SPF、DKIM、DMARC这三件套,否则你发的邮件基本都会进别人的垃圾箱。这次我是在纯内网环境测试,没涉及这些,但如果你是有公网需求的场景,答应我,一定提前了解这三件套,别等邮件被退信了再临时补课。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询