惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Recent Commits to openclaw:main
Recent Commits to openclaw:main
Simon Willison's Weblog
Simon Willison's Weblog
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
S
Schneier on Security
Cyberwarzone
Cyberwarzone
NISL@THU
NISL@THU
The Last Watchdog
The Last Watchdog
Security Archives - TechRepublic
Security Archives - TechRepublic
The Hacker News
The Hacker News
Schneier on Security
Schneier on Security
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
Help Net Security
Help Net Security
Scott Helme
Scott Helme
SecWiki News
SecWiki News
Security Latest
Security Latest
T
Threat Research - Cisco Blogs
L
LINUX DO - 最新话题
L
Lohrmann on Cybersecurity
TaoSecurity Blog
TaoSecurity Blog
K
Kaspersky official blog
Attack and Defense Labs
Attack and Defense Labs
P
Privacy & Cybersecurity Law Blog
Hacker News - Newest:
Hacker News - Newest: "LLM"
L
LINUX DO - 热门话题
N
News and Events Feed by Topic
Know Your Adversary
Know Your Adversary
Forbes - Security
Forbes - Security
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Google DeepMind News
Google DeepMind News
T
Tor Project blog
P
Palo Alto Networks Blog
Cisco Talos Blog
Cisco Talos Blog
A
Arctic Wolf
O
OpenAI News
T
The Exploit Database - CXSecurity.com
C
CXSECURITY Database RSS Feed - CXSecurity.com
AI
AI
N
News and Events Feed by Topic
博客园 - Franky
T
Threatpost
D
Darknet – Hacking Tools, Hacker News & Cyber Security
Engineering at Meta
Engineering at Meta
S
SegmentFault 最新的问题
C
Cyber Attacks, Cyber Crime and Cyber Security
N
Netflix TechBlog - Medium
V2EX - 技术
V2EX - 技术
B
Blog RSS Feed
Hacker News: Ask HN
Hacker News: Ask HN
D
Docker
博客园 - 三生石上(FineUI控件)

qlAD 的技术笔记

2026 年 6 月 7 日 -- 我有社交恐惧症,恐惧外面到处雷电风雨声(大学生活记录) 手把手带你实现哈希表(C/C++ 数据结构) 手把手带你实现图结构(C/C++ 数据结构) 手把手带你实现二叉树(C/C++ 数据结构) 手把手带你实现栈和队列(C/C++ 数据结构) 手把手带你实现单/双链表(C/C++ 数据结构) 手把手带你实现动态数组(C/C++ 数据结构) 2026 年 1 月 2 日 -- 我不怕冷,因为我内心炽热 【2025 年度总结】(大学生活记录) 2025 年 12 月 2 日 -- 省电模式:大一 100 天耗电日志(大学生活记录) 蓝桥杯备赛第一期 —— 枚举与模拟 2025 年 11 月 3 日 -- 用爱发电、大爱无私(大学生活记录) 使用循环嵌套输出规则图形找规律讲解(嵌套循环-图形输出) 2025 年 10 月 1 日 -- 二字开头第一年的生日记录及感悟随笔(大学生活记录) Python 初级 04 -- 目前为止 Python 中你们做题可能会遇到的问题以及七七八八 2025 年 9 月 24 日 -- 开学后的第一课及军训汇演(大学生活记录) Python 初级 03 -- 程序设计的三种结构之选择结构和循环结构 Python 初级 02 -- 基础的数据类型和输入输出 2025 年 9 月 17 日 -- 大连 2025 国际大体联足球世界杯(大学生活记录) Python 初级 01 -- 初识编程、理解计算机语言及程序运行方式 适合大一新生学习编程的前一课 -- 编程先导(编程的本质) 2025 年 9 月 12 日 -- 三天军训感受以及一些七七八八(大学生活记录) 2025 年 9 月 9 日 -- 体检、军训前的准备(大学生活记录) 适合大一新生的计算机基础知识 -- 个人认为足够版 2025 年 9 月 7 日 -- 既来之、则安之(大学生活记录) C++ 程序的内存布局 —— 代码区、全局/静态区、栈区和堆区 联想小新 pro 16 2025 开箱记录:跳过联网、office 激活、更换 win 11 专业版 R 语言中的数学函数 计算机软件著作权申请过程记录 从聚类到回归:用 Python 解析鸢尾花数据集的完整数据科学流程 条件概率、全概率与贝叶斯公式 —— 一篇文章带你死磕概率公式 高中化学物质反应规则表 —— 方程式之间也有规律可循 集合元素性质、关系、子集公式、基本运算 —— 一篇文章带你全方面死磕集合 如何为你的项目选择合适的许可证 -- 全方位指南 解释 3:1 和 9:3:3:1 的详细来源 —— 建立减数分裂与孟德尔遗传学定律之间的联系 重新设置磁盘分区以及 Btrfs 子卷(subvolume)布局的无损方案 基于 GitHub Actions + OSS 的自托管 APT 仓库全面指南 如何在安装 Debian 时配置 Btrfs 子卷 | 详细分步指南 一个合格的个人网站站长应该知道哪些事? CSS 基础入门教程 —— 选择器、样式声明 HTML 基础入门 —— 基本结构和语法 给博客添加一个文章数据统计的页面 Git 学习笔记(命令备忘表) Anki 牌组选项详细解释与设置 手动编译带有 KernelSU 的 OnePlus 6 内核 安卓类原生系统补全计划 —— PixelExperience(一加 OnePlus) 如何使用 use-sound 为 React 应用添加声音效果 标准化项目的 GitHub Flow 工作流 如何搭建设计自己的博客网站? 使用安知鱼主题同款的 Twikoo 评论组件 配置 GitHub Actions 实现自动化提交百度收录 第00期 | 环境搭建 & 递归 (一) | 基本数列递归 逐字符讲解 C 语言 HelloWorld 程序 2023 年回顾 🤟 Anki:记忆神器,助你高效学习 Gentoo 学习笔记 美化你的 PixelExperience OS Markdown 语法指南 搭建 OneDrive 目录索引 为什么用 65 表示大写字母 A
零基础实战:用 Docker 启动 dockermailserver 绕过 25 端口封锁搭建个人邮箱服务器
qlAD · 2025-05-01 · via qlAD 的技术笔记

cover

一、为什么需要这套方案?

当你在云服务器尝试搭建邮箱服务时,常常会遇到运营商封锁 25 端口的难题,25 端口就像邮局的发货通道,一旦被封,你的邮件服务器就像被没有腿的邮递员,无法对外发送信件

如果无法解除此端口的屏蔽,需要通过其他服务来转发出站邮件,以便其他服务代您发送。我的解决方案是使用 Resend,也就是让人帮他送

并且我需要一台可以创建无限邮箱地址的服务器,因为有个网站会每隔一段时间给账户发兑换码:)方便我白嫖,还有我用邮箱注册了数百个网站,验证码都发在一堆不方便管理,有了自己的服务器后可以按照网站随便注册

比如说,我需要注册 Bilibili,那么邮箱就填 bilibili@qladgk.com ,我不用在服务器中手动添加这个邮箱,可以直接设置一个规则,让不存在的邮箱接受的邮件全部转发给 info@qladgk.com,这样所有的验证码都在 info 这个邮箱。如果哪天我的邮箱泄露,可以很方便的知道是哪个网站对应的邮箱

二、准备你的工具箱

工具/服务作用说明获取方式
Docker容器化部署环境官网下载
Resend 账户邮件中继服务(每月免费额度 3000 封)注册
域名邮箱域名(如 qladgk.com)域名注册商购买
SSL 证书加密通信保障使用受信任的 CA 颁布的证书

三、五步搭建实战

步骤 1:创建目录结构

mkdir -p mail.qladgk.com/docker-data/{dms/config,certs}
cd mail.qladgk.com

我个人喜欢在服务器的 ~ 位置创建用具体域名的文件夹来管理,所以就用了 mail.qladgk.com,然后需要确认你的 SSL 证书中有这个域名

步骤 2:准备 docker-compose.yml

# docker-compose.yml
version: "3.8"

services:
  mailserver:
    image: ghcr.io/docker-mailserver/docker-mailserver:latest
    container_name: mailserver
    # Provide the FQDN of your mail server here (Your DNS MX record should point to this value)
    hostname: mail.qladgk.com # 修改成你的域名
    env_file: mailserver.env
    # More information about the mail-server ports:
    # https://docker-mailserver.github.io/docker-mailserver/latest/config/security/understanding-the-ports/
    ports:
      - "25:25" # SMTP  (explicit TLS => STARTTLS, Authentication is DISABLED => use port 465/587 instead)
      - "143:143" # IMAP4 (explicit TLS => STARTTLS)
      - "465:465" # ESMTP (implicit TLS)
      - "587:587" # ESMTP (explicit TLS => STARTTLS)
      - "993:993" # IMAP4 (implicit TLS)
    volumes:
      - ./docker-data/dms/mail-data/:/var/mail/
      - ./docker-data/dms/mail-state/:/var/mail-state/
      - ./docker-data/dms/mail-logs/:/var/log/mail/
      - ./docker-data/dms/config/:/tmp/docker-mailserver/
      - ./docker-data/certs/:/tmp/certs/ # 修改成你的证书目录
      - /etc/localtime:/etc/localtime:ro
    environment:
      - SSL_TYPE=manual # 如果要手动设置路径证书类型必须是手动
      - SSL_CERT_PATH=/tmp/certs/nginx.crt # 改成你自己的证书地址
      - SSL_KEY_PATH=/tmp/certs/nginx.key # 改成你自己的证书地址
      - DEFAULT_RELAY_HOST=[服务商获取]:端口 # 中继服务主机
      - RELAY_USER=服务商获取 # 中继服务用户名
      - RELAY_PASSWORD=服务商获取 # 中继服务密码
    restart: always
    stop_grace_period: 1m
    # Uncomment if using `ENABLE_FAIL2BAN=1`:
    # cap_add:
    #   - NET_ADMIN
    healthcheck:
      test: "ss --listening --tcp | grep -P 'LISTEN.+:smtp' || exit 1"
      timeout: 3s
      retries: 0

官网的 compose 对比只修改了这些部分:

hostname: mail.qladgk.com # 修改为你的域名
volumes:
  - ./docker-data/certs/:/tmp/certs/ # 准备你的域名证书
environment:
  - SSL_TYPE=manual # 如果要自定路径证书类型必须选手动
  - SSL_CERT_PATH=/tmp/certs/certs.crt # 根据自己的证书名设定
  - SSL_KEY_PATH=/tmp/certs/certs.key # 根据自己的证书名设定
  - DEFAULT_RELAY_HOST=[服务商获取]:端口 # 中继服务主机
  - RELAY_USER=服务商获取 # 中继服务用户名
  - RELAY_PASSWORD=服务商获取 # 中继服务密码

然后还需要将官网的 mailserver.env 下载下来,这个文件尽量不要改动,东西很多容易错,我们就用 Docker 的环境变量就好,而且环境变量优先于 mailserver.env

步骤 3:配置 Postfix 中继主机

注册好 Resend 后添加域名并且使用 DNS 验证

设置 Resend DNS 解析

然后需要等待验证通过,可能需要两三分钟

Resend DNS 验证

然后就可以设置主机、用户名、密码了,修改 docker-compose.yml

- DEFAULT_RELAY_HOST=[smtp.resend.com]:587
- RELAY_USER=resend
- RELAY_PASSWORD=创建一个 api 就是密码

以上配置是根据 Resend 设置,在官网的这个地方

Resend STMP 服务器

默认用户名应该都是 resend,密码就是你创建的 apikey

步骤 4 :初始化邮件服务器

# 首次启动初始化
docker compose up -d

# 在 120 秒内创建管理员邮箱
docker exec mailserver setup email add postmaster@qladgk.com <你的邮箱密码>

# 然后创建一个自己用的邮箱
docker exec mailserver setup email add hi@qladgk.com <你的邮箱密码>

# 生成 DKIM 签名
docker exec -it mailserver setup config dkim

docker-data/dms/config/opendkim/keys/qladgk.com/mail.txt() 中的复制出来,并删掉其中的 ""多余的空格 拼接成一行备用

比如生成的 txt 如下

mail.txt

拼接之后的 txt 如下:

v=DKIM1; h=sha256; k=rsa; p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAybULjMm1Pv2qn8l0SIan+I8NpBTanNQaVFNVLvR5We9QITGAfxJtVUJv9e9e0BV3XVR/hDWRwxfw4KG6szRzUB1VABp4knYgwr1i3UNgKag3pSgTS4v1k5BccwIod/UK/E6+6iRiIzVoTikd3eSuygDAnAf+/FbZcnVF2Y/W4BvC9+aOyyDUYVCsSmPMgK99fm6fj5Q1LGMAvDapZ4XP+A7aFIHOL+AffPquPcsPAymJgC9guOJH4+D+ejqL5T6loTIljcGzcbavd82sRt01BxX3vRWqsqQ4K5I3yNVX5aLm1vrk5EIssGlyKxjjW9c2+6N7TUz6BD78AaKQmlBlfwIDAQAB

步骤 5:配置 DNS 记录

类型名称说明
Amail你的服务器 ip邮件路由
MX@mail.qladgk.com优先级设置成 10
TXT@v=spf1 mx -allSPF 发件人验证
TXT_dmarcv=DMARC1; p=none;DMARC 记录
TXTmail._domainkey刚才准备的那串 txtDKIM 记录

算上开始配置的 Resend 的 DNS ,你的 DNS 解析应该如下

类型名称说明
Amail你的服务器 ip邮件路由
MX@mail.qladgk.com优先级设置成 10
TXT@v=spf1 mx -allSPF 发件人验证
TXT_dmarcv=DMARC1; p=none;DMARC 记录
TXTmail._domainkey刚才准备的那串 txtDKIM 记录
-----------------------------------------------------
MXsendResend 提供的值优先级设置成 10
TXTsendResend 提供的值SPF 发件人验证
MXresend._domainkeyResend 提供的值DKIM 记录

这里同时配置了两个邮箱的 SPF/DKIM ,因为最后邮件是 Resend 用 @send.qladgk.com 这个邮箱地址代发,那么 send.qladgk.com 子域的 SPF/DKIM 记录确实需要按 Resend 要求配置。同时,根域名 @ 的 DMARC 记录对于邮件 From: 是 user@qladgk.com 的情况仍然重要,它需要与 send.qladgk.com 的 SPF/DKIM 对齐(通常是宽松对齐)。

四、验证你的邮箱系统

发送测试邮件

使用雷鸟客户端,添加邮箱账户和密码

雷鸟客户端

这里的收件和发件都是 mail.qladgk.com 是没有问题的

添加账户后给你的 163 或者 qq 尝试发送邮件,可以看到成功收到

发送邮件测试

发件人是 hi@qladgk.com 后面显示的是由 xxxxx@send.qladgk.com 代发

测试 163 直接回复

直接回复测试

可以看到直接回复的是 origin 地址而不是代发地址

https://www.mail-tester.com/ 发送测试邮件,查看邮件评分

邮件评分测试

同时你也能看见 Resend 中帮你转发的邮件

Resend 记录

接收邮件测试

接受邮件测试

发现我们的 hi@qladgk.com 邮箱成功接收到 163 发来的邮件,但是 Resend 中没有接收记录,后面会解释

五、原理解释

涉及的服务器与 DNS 配置

自建服务器配置(mail.qladgk.com)

类型完整主机名值示例作用说明
Amail.qladgk.com11.22.33.44邮件服务器 IP 地址
MX@qladgk.commail.qladgk.com声明主域名的邮件服务器地址(优先级 10)
TXT@qladgk.comv=spf1 mx -all仅允许 mail.qladgk.com 的 IP 发送邮件(防御伪造)
TXTmail._domainkey.qladgk.comv=DKIM1; p=公钥...邮件数字签名公钥(防止邮件被篡改)

Resend 中继配置(send.qladgk.com)

类型完整主机名值示例作用说明
MXsend.qladgk.comfeedback-smtp.us-east-1.amazonses.comResend 要求的特殊 MX 记录(用于建立发送域身份)
TXTsend.qladgk.comv=spf1 include:amazonses.com ~all授权 Resend 的服务器代发邮件
TXTresend._domainkey.qladgk.comk=rsa; p=公钥...Resend 提供的 DKIM 公钥(验证邮件来源合法性)

全局反垃圾邮件策略

类型完整的主机名称值示例作用
TXT_dmarc.qladgk.comv=DMARC1; p=none;邮件验证策略(告知收件方如何处理验证失败的邮件)

也就是说我们一共在解析中设置了两个 MX 方式,所以会出现两个邮箱地址 比如 hi@qladgk.com 和 hi@send.qladgk.com

涉及到的端口和认证信息

为了让主机认证我们,需要提供端口和账户密码

在 IMAP 邮件服务器中常见的端口分别如下

端口协议使用场景加密方式
25SMTP服务器之间的邮件传输
465SMTP over SSL客户端到服务器的加密邮件发送SSL/TLS
587SMTP with STARTTLS客户端到服务器的加密邮件发送STARTTLS
143IMAP客户端从服务器接收邮件(不加密)
993IMAP over SSL客户端从服务器加密接收邮件SSL/TLS

这里容易混淆,需要慢慢理解

  ┏━━━━━━━━━━ Submission ━━━━━━━━━━━━━┓┏━━━━━━━━━━━━━ Transfer/Relay ━━━━━━━━━━━┓

                            ┌─────────────────────┐                    ┌┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┐
MUA ----- STARTTLS -------> ┤(587)   MTA ╮    (25)├ <-- cleartext ---> ┊ Third-party MTA ┊
    ----- implicit TLS ---> ┤(465)       │        |                    └┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┘
    ----- cleartext ------> ┤(25)        │        |
                            |┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄|
MUA <---- STARTTLS -------- ┤(143)   MDA ╯        |
    <---- implicit TLS ---- ┤(993)                |
                            └─────────────────────┘

  ┗━━━━━━━━━━ Retrieval ━━━━━━━━━━━━━━┛

MUA 是客户端、MTA 是服务器

发邮件过程会经理 MUA - MTA - MTA - MUA 这过程,我们所说的加密邮件指的是 MTA 与 MUA 之间的过程,而 MUA 之间的传输我们不能干预

邮件工作流程图

之所以之前只能接受邮件而不能发送,是因为服务器封锁 25 端口的出站流量,而没有封锁入站流量。如下图:

25 端口测试

可以看到用服务器通过 25 去访问别人的 stmp 会失败,但是个人电脑上去访问服务器的 25 则成功

接下来是认证信息

其中邮箱客户端(雷鸟)里:

  • imap 主机是 mail.qladgk.com、端口是 993(SSL/TLS 加密方式)、用户名是邮箱、密码是邮箱密码
  • smtp 主机是 mail.qladgk.com、端口是 587(STARTTLS 加密方式)、用户名是邮箱、密码是邮箱密码

因为接受邮件只有 993 有加密,所以选他。关于 465 和 587 选谁网上说法不一,但是 587 是现在邮箱常见默认端口,所以选他

而我们的 Resend 的 SMTP 的认证信息则直接存放在 docker-mailserver 里

# 配置中继
relayhost = [smtp.resend.com]:587
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = static:resend的用户名:resend的密码
smtp_sasl_security_options = noanonymous

这里的 587 指的是我们的邮件服务器现在作为客户端与 Resend 服务端通过 STARTTLS 加密方式将邮件传到他们的 STMP 上

邮件发送流程(中继模式):

  1. 客户端提交:雷鸟通过加密连接将邮件提交到 mail.qladgk.com(587 端口),使用邮箱账户密码认证
  2. 中继路由决策:Postfix 检测到目标为外部域(如 163.com),根据 relayhost = [smtp.resend.com]:587 启动中继流程
  3. 中继服务器认证:使用 SASL 认证机制,通过 Resend 提供的 API Key 完成身份验证:
  4. 信封发件人重写:Resend 会将信封发件人(Envelope From)改为 xxx@send.qladgk.com,这是邮件显示"代发"的原因
  5. 最终投递:Resend 通过 25 端口将邮件投递到目标服务器,完全绕开本地服务器的出站限制

所以最后收到的邮件的代发人是 xxx@send.qladgk.com

邮件接收流程

  1. MX 记录查询:外部服务器(163)给 hi@qladgk.com 发邮件时通过 MX 记录找到他的邮件服务器(mail.qladgk.com)
  2. 直接投递:发送方通过 25 端口直连你的服务器(云厂商通常允许入站 25 端口)
  3. 本地存储:Postfix 将邮件存入 /var/mail/ 目录下的用户邮箱
  4. 客户端同步:雷鸟通过 IMAPS(993 端口)加密拉取邮件

为什么接收邮件不经过 Resend?

接收流程是标准的邮件服务器间直接通信(Server to Server),仅依赖:

  • 正确的 MX 记录指向
  • 25 端口的入站连接(通常云厂商允许入站 25 端口)
  • 有效的 SSL 证书

而发送时需要出站 25 端口连接(被禁止),因此需要通过中继 "借道" 发送。

Resend 的角色

Resend 在本方案中充当邮件中继服务器,主要负责将你的邮件投递到目标邮箱服务器。

通过配置 Postfix 的 relayhost 参数,将本地邮件服务器的发送任务委托给 Resend 的 SMTP 服务器。

Resend 提供了每月 3000 封免费额度,对于个人用户或小型团队来说,基本可以满足日常需求。

六、常见问题排雷

1. 邮件进入垃圾箱

  • 检查 SPF/DKIM/DMARC 记录
  • 申请反向解析 PTR

其中阿里云的 PTR 很好申请,发个工单就行,三分钟分钟之内添加好

阿里云 PTR 申请

我是这么发的:

主题:

内容:

尊敬的阿里云售后工程师:
您好!我正在搭建邮件服务器,需要为我的服务器添加 PTR 记录,以便提高邮件的送达率。现向您提交申请,以下是相关信息:
ECS 实例所属地域:[具体地域,如北京、深圳等]
ECS 实例的公网 IP 地址:[公网IP地址]
对应的域名:[域名]
请协助我完成 PTR 记录的添加,谢谢!

2. 客户端连接失败

# 检查端口监听状态
docker exec mailserver netstat -tulpn | grep -E '25|587'