Postfix邮件服务器
邮件服务器
邮件服务器核心组件与协议
核心组件:
- MUA (Mail User Agent):用户直接交互的客户端软件,也就是负责撰写、发送、接收和管理邮件(比如:QQ邮箱、网易邮箱、outlook等)。
- MTA (Mail Transfer Agent):负责邮件路由和转发(服务器间通信)。
Postfix就是典型的MTA。 - MDA (Mail Delivery Agent):负责将MTA收到的邮件投递到用户邮箱(存储)。常与MTA集成或由MRA兼任。
- MRA (Mail Retrieval Agent):负责让用户读取已存储的邮件。
Dovecot是典型的MRA,提供POP3/IMAP服务。
关键协议:
- SMTP(Simple Mail Transfer Protocol):用于发送和接收邮件,默认端口25(SSL加密端口465/587)。
- POP3(Post Office Protocol 3):下载邮件到本地,默认端口110(加密端口995)。
- IMAP(Internet Message Access Protocol):远程管理邮件并同步多设备,默认端口143(加密端口993)。
- MIME(Multipurpose Internet Mail Extensions):多用途互联网邮件扩展,也就是扩展了SMTP协议,允许电子邮件传输多种内容(比如:文本、图片、音频、视频等)。
邮件发送接收流程
邮件服务发送和接收的架构图:

邮件服务发送与接收全过程解析:
1.用户撰写邮件(MUA层)
用户在客户端(Outlook、Thunderbird、手机邮箱)填写:发件人 From: xxx@aaa.com、收件人 To: xxx@bbb.com、主题 Subject、正文和附件。
2.客户端提交发送到SMTP服务器(第一步)
客户端提交给发送邮件服务器,服务器允许认证用户提交邮件,防止开网关中继(open relay)。
MTA的工作:
-
- 在队列中写入邮件(队列文件)
- 添加 Received: 头(记录传输路径、时间、IP)
- 做本地策略检查(是否允许中继、配额检查)
- 反垃圾/病毒扫描(SpamAssassin、ClamAV)
- DKIM 签名(如果配置),即在发出的邮件加入 DKIM-Signature: 头
- 如果目标在同域可能直接本地投递,否则为远程投递做准备
注意:端口25是MTA之间的传输端口(通常不用于客户端提交);很多ISP会阻止入站或出站25端口以防滥用。
3.发件MTA决定发送去向是本地投递还是远程投递(第二步、第三步)
如果收件域是bbb.com(非 aaa.com),MTA要发到外网。
查询bbb.com的MX记录(返回多个MX,带优先级numeric)。选择优先级最低(数字最小)的MX。若没有MX,则回退到A/AAAA 记录(RFC 5321 规定)。解析到目标MX的IP(A/AAAA)并选择一个作为目标SMTP服务器。
4.发件MTA与收件域的MX建立SMTP连接并传输邮件(第四步)
发件MTA打开TCP连接到邮件目的地址的SMTP服务器,经过重要的安全/验证检查(通常由收件MTA在这里做)。
如果收件MAT接收了邮件(返回250),将把邮件加入到本地投递队列,经过本地策略、反垃圾过滤、病毒扫描,最终本地投递给用户的邮箱存储(使用LDA/LMTP,如 Dovecot LMTP、procmail、maildrop等)
5.邮件存储(第五步)
邮件服务器将以常见的邮箱格式对收到的邮件进行存储,比如:Maildir(目录结构:tmp/ → new/ → cur/,安全避免并发文件写入),典型路径 /home/bob/Maildir/new/xxxx或者- - mbox(单文件追加,较旧)
6.收件人客户端取信(第六步)
收件人客户端连接到收件服务器,使用IAMP协议(默认端口143,加密端口993)或者POP3协议(默认端口110,加密端口995)。
客户端进行同步或者下载邮件,若是IMAP,会保留服务器上的邮件(并标记已读/删除等);若是POP3 常常默认下载后删除。
7.失败、重试和退信(Bounce / NDR)
- 如果某一步遇到临时错误(4xx),发件 MTA 会按重试策略轮询 MX 并重试(指数回退,一段时间后仍失败则生成退信或保留在队列)。
- 永久错误(5xx)通常会立即返回退信(NDR)给 信封地址(MAIL FROM),而非 From: 头中的地址。
- 若发件人使用空信封 MAIL FROM:<>(系统退信),则收件端不会对其返回退信,以避免循环。
核心概念与角色类比
邮件系统是一个典型的C/S(客户端/服务器)架构,涉及多个服务器和协议协同工作。一个经典的类比是传统邮政系统:
| 邮政系统 | 邮件系统 | 说明 |
|---|---|---|
| 写信人 | 邮件客户端 (MUA) | 如 Outlook, Foxmail, Thunderbird, 手机邮件App |
| 本地邮局 | 发件服务器 (MTA) | 如 Postfix, Exim。负责接收用户邮件并转发出去 |
| 运输网络 | 互联网 (SMTP) | 邮件服务器之间通过SMTP协议通信 |
| 目的地邮局 | 收件服务器 (MTA) | 如 Postfix。接收来自其他服务器的邮件 |
| 邮局邮箱 | 邮件存储 (MDA) | 服务器上的存储空间,如 Maildir/目录 |
| 邮递员 | 收件服务器 (MRA) | 如 Dovecot。负责将邮箱里的邮件交给最终用户 |
| 收信人 | 邮件客户端 (MUA) | 用户最终在自己的设备上阅读邮件 |
Postfix服务简介
什么是Postfix服务?
Postfix(MTA, Mail Transfer Agent)是一个开源的邮件传输代理,它的主要功能是接收、路由和发送电子邮件。在整个邮件系统里,Postfix 是负责“传递邮件”的核心组件,属于邮件服务器的“大脑和中枢”。
Postfix的扮演角色
- 发送邮件:当本地主机或客户端提交邮件给 Postfix,它会决定该邮件是本地投递(交给本地用户邮箱)还是远程投递(通过 SMTP 发往其他邮件服务器)。
- 接收邮件:它监听 SMTP 端口(25、587、465),接受来自外部邮件服务器或者内部客户端的邮件。
- 队列管理:如果对方服务器暂时不可达,Postfix 会把邮件放到队列中,按照一定重试策略再次发送。
- 邮件过滤和安全:可以结合 SpamAssassin、Amavis、ClamAV 做反垃圾邮件、反病毒扫描。支持 TLS 加密、SASL 用户认证,保障传输安全。
- 日志与监控:提供详细的日志,方便运维人员排查邮件收发问题。
补充说明:Postfix服务在架构中扮演的角色主要就是SMTP服务器的应用。SMTP协议=一种传输邮件的“规则”。Postfix=一个完整的软件,实现了SMTP协议,并在此基础上扩展了队列管理、本地投递、策略控制等功能。
个人邮件服务搭建示例
搭建思路构思
主要架构采用Postfix+Dovecot来实现邮件服务系统的搭建,由于不是在公网上,在内部虚拟环境下,所以还需要自己搭建一个DNS服务来完成解析。
搭建环境实验步骤:
- 1.准备服务器,系统为
Rocky Linux,IP地址为192.168.101.201,准备在上面搭建邮件服务和DNS服务。 - 2.设置域名解析,解析域名为
example.com,邮件服务为mail.example.com,IP地址为192.168.101.201。 - 3.安装Postfix服务,然后配置相关配置文件(由于测试,所以不开启ssl认证)。
- 4.安装Dovecot服务,然后配置相关配置文件(由于测试,所以不开启ssl认证)。
- 创建测试用户,并使用Telnet工具进行邮件发送和接收测试。
完整邮件服务器DNS检查清单
| 记录类型 | 主机名 | 值 | 设置位置 | 验证命令 |
|---|---|---|---|---|
| A | mail |
192.168.101.201 |
您的DNS服务商 | dig mail.example.com |
| MX | @ |
mail.example.com. |
您的DNS服务商 | dig MX example.com |
| TXT (SPF) | @ |
v=spf1 mx ~all |
您的DNS服务商 | dig TXT example.com |
| TXT (DKIM) | default._domainkey |
v=DKIM1; p=... |
您的DNS服务商 | dig TXT default._domainkey.example.com |
| TXT (DMARC) | _dmarc |
v=DMARC1; p=none... |
您的DNS服务商 | dig TXT _dmarc.example.com |
| PTR | 192.168.101.201 |
mail.example.com |
IP提供商控制台 | dig -x 192.168.101.201 |
DNS服务搭建
首先我们需要先安装DNS软件包
yum -y install bind bind-utils
配置DNS配置文件加入正向解析区域和反向解析区域相关配置,如下所示:
// 正向解析配置
zone "example.com" IN {
type master;
file "example.com.zone";
allow-update { none; };
};
// 反向解析配置
zone "101.168.192.in-addr.arpa" IN {
type master;
file "192.168.101.zone";
allow-update { none; };
};
正向解析文件:example.com.zone,默认配置中设置路径在/var/name目录下,如下所示:
$TTL 86400 ; 默认TTL(1天)
@ IN SOA dns.example.com. admin.example.com. (
2024090101 ; 序列号 (格式:YYYYMMDDNN)
3600 ; 刷新时间 (1小时)
1800 ; 重试时间 (30分钟)
604800 ; 过期时间 (1周)
86400 ; 最小TTL (1天)
)
; ------------ 基础记录 ------------
@ IN NS dns.example.com. ; 域名服务器记录
dns IN A 192.168.101.201 ; DNS服务器IP
; ------------ 邮件服务器必需记录 ------------
@ IN MX 10 mail.example.com. ; MX记录(优先级10)
mail IN A 192.168.101.201 ; 邮件服务器IP
; ------------ 反垃圾邮件记录(SPF/DKIM/DMARC)------------
@ IN TXT "v=spf1 mx ~all" ; SPF记录
mail._domainkey IN TXT "v=DKIM1; k=rsa; p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC..." ; DKIM公钥
_dmarc IN TXT "v=DMARC1; p=none; rua=mailto:postmaster@example.com" ; DMARC策略
; ------------ 其他常用记录 ------------
@ IN A 192.168.101.201 ; 根域名A记录(网站)
; ------------ CNAME类型记录 ------------
www IN CNAME example.com. ; WWW别名
反向解析文件:101.168.192.in-addr.arpa,默认配置中设置路径在/var/name目录下,如下所示:
$TTL 86400
@ IN SOA dns.example.com. admin.example.com. (
2025082701 ; 序列号
3600 ; 刷新
1800 ; 重试
604800 ; 过期
86400 ) ; 最小TTL
; ---------- 名称服务器 ----------
IN NS dns.example.com.
; ----------- PTR 记录 -----------
201 IN PTR email.example.com.
安装配置Postfix
安装postfix软件包
yum -y install postfix
配置postfix配置文件:/etc/postfix/main.cf
如果有以#符号为头的需要在配置文件中注释掉。
# 指定邮件服务器的主机名(FQDN,全限定域名)
myhostname = mail.example.com
# 设置本地域名(通常是主机名去掉前缀部分)
mydomain = example.com
# 指定本地用户发信时,邮件地址的“域”部分
myorigin = $myhostname
# 控制Postfix在哪些网络接口上监听SMTP
inet_interfaces = all
#inet_interfaces = localhost
#mydestination = $myhostname, localhost.$mydomain, localhost
# 定义哪些域名算作“本地域”
mydestination = $myhostname, localhost.$mydomain, localhost, $mydomain
# 定义哪些IP地址/网段被认为是“可信网络”
mynetworks = 192.168.101.0/24, 127.0.0.0/8
#home_mailbox = Mailbox
# 定义用户邮件的存储格式,每封邮件一个文件,存放在~/Maildir/目录下,常配合Dovecot使用
home_mailbox = Maildir/
# SASL(身份认证)配置
smtpd_tls_security_level = none
smtpd_sasl_type = dovecot
smtpd_sasl_path = private/auth
smtpd_sasl_auth_enable = yes
smtpd_sasl_security_options = noanonymous
broken_sasl_auth_clients = yes
# 收件限制策略
smtpd_recipient_restrictions = permit_mynetworks, permit_sasl_authenticated, reject_unauth_destination
# 控制Postfix发送端(smtp)的TLS策略
smtp_tls_security_level = none
配置:启用Submission端口(明文587):/etc/postfix/master.cf
submission inet n - n - - smtpd
-o syslog_name=postfix/submission
-o smtpd_tls_security_level=none # 禁用加密
-o smtpd_sasl_auth_enable=yes
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
启动服务
systemctl enable postfix --now
安装配置Dovecot
安装dovecot软件服务。
yum -y install dovecot dovecot-devel clucene-core
配置dovecot配置文件:/etc/dovecot/dovecot.conf
!include conf.d/*.conf
protocols = imap pop3 lmtp
配置认证:/etc/dovecot/conf.d/10-auth.conf
auth_mechanisms = plain login
!include auth-system.conf.ext # 使用系统用户认证
disable_plaintext_auth = no
配置邮件存储:/etc/dovecot/conf.d/10-mail.conf
mail_location = maildir:~/Maildir
禁用SSL/TLS:/etc/dovecot/conf.d/10-ssl.conf
ssl = no
配置Postfix认证集成:/etc/dovecot/conf.d/10-master.conf
service auth {
unix_listener /var/spool/postfix/private/auth {
mode = 0660
user = postfix
group = postfix
}
}
修改完需要的配置之后启动服务,如下所示:
systemctl enable dovecot --now
测试阶段
新增用户
创建两个用户作为测试用户
useradd -m user1 -s /sbin/nologin
useradd -m user2 -s /sbin/nologin
登录邮件服务器
登录具体操作
# 步骤一:连接STMP服务器
telnet mail.example.com 25
# 步骤二:标注信息
EHLO test
# 步骤三:登录账号
AUTH LOGIN
# 步骤四:输入用户账号和密码
用户账号的base64字符串
用户密码的base64字符串
具体登录邮件服务器的操作过程,如下所示:
$ telnet mail.example.com 25
Trying 192.168.101.201...
Connected to mail.example.com.
Escape character is '^]'.
220 mail.example.com ESMTP Postfix
EHLO test
250-mail.example.com
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-AUTH PLAIN LOGIN
250-AUTH=PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250-SMTPUTF8
250 CHUNKING
AUTH LOGIN
334 VXNlcm5hbWU6
dXNlcjE=
334 UGFzc3dvcmQ6
MTIzNDU2
235 2.7.0 Authentication successful
发送邮件
发送邮件具体操作
# 步骤一:标注信息
EHLO test
# 步骤二:指定发件人地址
MAIL FROM: <user1@example.com>
# 步骤三:指定收件人地址
RCPT TO: <user2@example.com>
# 步骤四:撰写邮件内容
DATA
# 步骤五:撰写标题
Subject: Test Email
# 步骤六:撰写邮件内容
This is a test email.
# 步骤七:使用.标明撰写结束
.
# 步骤八:退出
QUIT
具体发送邮件的操作过程,如下所示:
EHLO test send email
250-mail.example.com
250-PIPELINING
250-SIZE 10240000
250-VRFY
250-ETRN
250-AUTH PLAIN LOGIN
250-AUTH=PLAIN LOGIN
250-ENHANCEDSTATUSCODES
250-8BITMIME
250-DSN
250-SMTPUTF8
250 CHUNKING
MAIL FROM: <user1@example.com>
250 2.1.0 Ok
RCPT TO: <user2@example.com>
250 2.1.5 Ok
DATA
354 End data with <CR><LF>.<CR><LF>
Subject: Test Email
This is a test email.
.
250 2.0.0 Ok: queued as 2E9282098164
QUIT
221 2.0.0 Bye
Connection closed by foreign host.
查收邮件
查收邮件具体步骤(下面的a1、a2...是客户端生成的任意标签)
# 步骤一:连接到IMAP服务器
$ telnet 服务地址 服务端口
# 步骤二:登录账号
a1 LOGIN 用户名 用户密码
# 步骤三:列出邮箱文件夹
a2 LIST "" "*"
# 步骤四:选择收件箱
a3 SELECT INBOX
# 步骤五:查看邮件列表
a4 FETCH 1:* (FLAGS BODY.PEEK[HEADER])
# 步骤六:读取具体邮件内容
a5 FETCH 1 BODY[]
# 步骤七:退出登录
a6 LOGOUT
具体查收邮件的操作过程,如下所示:
$ telnet 192.168.101.201 143
Trying 192.168.101.201...
Connected to email.example.com.
Escape character is '^]'.
* OK [CAPABILITY IMAP4rev1 SASL-IR LOGIN-REFERRALS ID ENABLE IDLE LITERAL+ AUTH=PLAIN AUTH=LOGIN] Dovecot ready.
a1 LOGIN user2 1234567
a1 OK [CAPABILITY IMAP4rev1 SASL-IR LOGIN-REFERRALS ID ENABLE IDLE SORT SORT=DISPLAY THREAD=REFERENCES THREAD=REFS THREAD=ORDEREDSUBJECT MULTIAPPEND URL-PARTIAL CATENATE UNSELECT CHILDREN NAMESPACE UIDPLUS LIST-EXTENDED I18NLEVEL=1 CONDSTORE QRESYNC ESEARCH ESORT SEARCHRES WITHIN CONTEXT=SEARCH LIST-STATUS BINARY MOVE SNIPPET=FUZZY PREVIEW=FUZZY PREVIEW STATUS=SIZE SAVEDATE LITERAL+ NOTIFY SPECIAL-USE] Logged in
a2 LIST "" "*"
* LIST (\HasNoChildren) "." INBOX
a2 OK List completed (0.006 + 0.000 + 0.005 secs).
a3 SELECT INBOX
* FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
* OK [PERMANENTFLAGS (\Answered \Flagged \Deleted \Seen \Draft \*)] Flags permitted.
* 1 EXISTS
* 1 RECENT
* OK [UNSEEN 1] First unseen.
* OK [UIDVALIDITY 1757870899] UIDs valid
* OK [UIDNEXT 2] Predicted next UID
a3 OK [READ-WRITE] Select completed (0.004 + 0.000 + 0.003 secs).
a4 FETCH 1:* (FLAGS BODY.PEEK[HEADER])
* 1 FETCH (FLAGS (\Recent) BODY[HEADER] {439}
Return-Path: <user1@example.com>
X-Original-To: user2@example.com
Delivered-To: user2@example.com
Received: from test?send?email (unknown [192.168.101.201])
by mail.example.com (Postfix) with ESMTPA id 2E9282098164
for <user2@example.com>; Mon, 15 Sep 2025 01:17:01 +0800 (CST)
Subject: Test Email
Message-Id: <20250914171718.2E9282098164@mail.example.com>
Date: Mon, 15 Sep 2025 01:17:01 +0800 (CST)
From: user1@example.com
)
a4 OK Fetch completed (0.002 + 0.000 + 0.001 secs).
a5 FETCH 1 BODY[]
* 1 FETCH (FLAGS (\Seen \Recent) BODY[] {462}
Return-Path: <user1@example.com>
X-Original-To: user2@example.com
Delivered-To: user2@example.com
Received: from test?send?email (unknown [192.168.101.201])
by mail.example.com (Postfix) with ESMTPA id 2E9282098164
for <user2@example.com>; Mon, 15 Sep 2025 01:17:01 +0800 (CST)
Subject: Test Email
Message-Id: <20250914171718.2E9282098164@mail.example.com>
Date: Mon, 15 Sep 2025 01:17:01 +0800 (CST)
From: user1@example.com
This is a test email.
)
a5 OK Fetch completed (0.002 + 0.000 + 0.001 secs).
a6 LOGOUT
* BYE Logging out
a6 OK Logout completed (0.001 + 0.000 secs).
Connection closed by foreign host.