SMTP-CONFIG
Discourse 邮件配置文档
最后更新: 2025-12-29
环境信息
| 项目 | 值 |
|---|---|
| 服务器 | Ubuntu Linux |
| Discourse | Docker 容器部署 |
| 域名 | www.micu.wiki |
| 邮件服务 | QQ 邮箱 (smtp.qq.com) |
| QQ 邮箱账号 | byeserver@qq.com |
| QQ 授权码 | qezavpcenetvdbij |
问题描述
使用 QQ 邮箱直接作为 SMTP 服务器时,存在以下问题:
- QQ 邮箱要求
From地址必须与授权用户一致 - QQ 邮箱在关闭 SMTP 连接时有非标准行为,导致
SSL_read: unexpected eof错误 - 虽然邮件实际发送成功,但 Discourse 将此错误视为发送失败
- Sidekiq 自动重试导致用户收到多封重复邮件
最终解决方案
架构
Discourse 容器 → 宿主机 Postfix (172.17.0.1:25) → QQ 邮箱 (smtp.qq.com:465)
Discourse 发送邮件到本地 Postfix 会立即成功(无错误),Postfix 负责转发到 QQ 邮箱。
配置详情
1. 宿主机 Postfix 配置
安装 Postfix
DEBIAN_FRONTEND=noninteractive apt-get install -y postfix libsasl2-modules
SASL 密码文件
文件: /etc/postfix/sasl_passwd
[smtp.qq.com]:465 byeserver@qq.com:qezavpcenetvdbij
设置权限并生成数据库:
chmod 600 /etc/postfix/sasl_passwd
postmap /etc/postfix/sasl_passwd
主配置文件
文件: /etc/postfix/main.cf
关键配置项:
# 中继设置
relayhost = [smtp.qq.com]:465
# TLS 设置 (SSL wrapper mode for port 465)
smtp_tls_CApath=/etc/ssl/certs
smtp_tls_security_level=encrypt
smtp_tls_wrappermode=yes
smtp_tls_session_cache_database = btree:${data_directory}/smtp_scache
# SASL 认证
smtp_sasl_auth_enable = yes
smtp_sasl_password_maps = hash:/etc/postfix/sasl_passwd
smtp_sasl_security_options = noanonymous
# 发件人地址重写 (QQ 要求 From = 授权用户)
sender_canonical_maps = static:byeserver@qq.com
# 网络设置 (允许 Docker 容器连接)
mynetworks = 127.0.0.0/8 [::ffff:127.0.0.0]/104 [::1]/128 172.17.0.0/16
inet_interfaces = 127.0.0.1, 172.17.0.1
重启 Postfix
postfix check && systemctl restart postfix
验证 Postfix 监听
ss -tlnp | grep :25
# 应显示监听 127.0.0.1:25 和 172.17.0.1:25
2. Discourse 配置
文件: /var/discourse/containers/app.yml
env:
## SMTP 配置 - 使用本地 Postfix 中继
DISCOURSE_SMTP_ADDRESS: 172.17.0.1
DISCOURSE_SMTP_PORT: 25
DISCOURSE_SMTP_ENABLE_START_TLS: false
DISCOURSE_SMTP_FORCE_TLS: false
DISCOURSE_SMTP_DOMAIN: micu.wiki
DISCOURSE_SMTP_AUTHENTICATION: none
DISCOURSE_NOTIFICATION_EMAIL: byeserver@qq.com
重建容器
cd /var/discourse && ./launcher rebuild app
验证方法
测试 Postfix (宿主机)
# 发送测试邮件
(
echo "From: byeserver@qq.com"
echo "To: 3427788907@qq.com"
echo "Subject: Postfix Test"
echo ""
echo "Test email from Postfix"
) | /usr/sbin/sendmail -t
# 检查队列 (应为空表示发送成功)
mailq
# 查看日志
tail -20 /var/log/mail.log
测试 Discourse
docker exec -i app rake emails:test[3427788907@qq.com]
成功输出:
Testing sending to 3427788907@qq.com using 172.17.0.1:25, username:(none) with no auth.
SMTP server connection successful.
Sending to 3427788907@qq.com…
Mail accepted by SMTP server.
相关文件清单
| 文件 | 说明 |
|---|---|
/var/discourse/containers/app.yml | Discourse 主配置 |
/etc/postfix/main.cf | Postfix 主配置 |
/etc/postfix/sasl_passwd | SMTP 认证凭据 (敏感) |
/etc/postfix/sasl_passwd.db | SMTP 认证数据库 |
/var/log/mail.log | Postfix 邮件日志 |
常用命令
Postfix 管理
# 检查配置
postfix check
# 重启服务
systemctl restart postfix
# 查看状态
systemctl status postfix
# 查看队列
mailq
# 清空队列
postsuper -d ALL
# 查看日志
tail -f /var/log/mail.log
Discourse 管理
# 重建容器
cd /var/discourse && ./launcher rebuild app
# 进入容器
docker exec -it app bash
# 测试邮件
docker exec -i app rake emails:test[email@example.com]
# 查看 Sidekiq 队列
docker exec -i app rails runner "puts Sidekiq::Queue.new.size"
故障排查
1. Postfix 无法启动
# 检查配置语法
postfix check
# 查看详细错误
journalctl -u postfix -n 50
2. 邮件发送失败
# 查看邮件日志
tail -50 /var/log/mail.log
# 检查队列中的邮件
mailq
# 查看特定邮件详情
postcat -q <queue_id>
3. Discourse 无法连接 Postfix
# 检查 Postfix 是否监听 Docker 网络
ss -tlnp | grep :25
# 从容器内测试连接
docker exec -i app bash -c "echo 'QUIT' | nc 172.17.0.1 25"
4. QQ 邮箱拒绝
常见原因:
- 授权码过期或错误
- 发件人地址与授权用户不一致
- IP 被 QQ 邮箱封禁
解决方法:
- 登录 QQ 邮箱重新生成授权码
- 更新
/etc/postfix/sasl_passwd并运行postmap - 检查
sender_canonical_maps配置
注意事项
- QQ 邮箱授权码: 使用授权码而非 QQ 密码,授权码在 QQ 邮箱设置中生成
- 发件人限制: QQ 邮箱要求发件人地址必须与授权用户一致
- 防火墙: 确保 Docker 容器可以访问宿主机的 25 端口
- Postfix 服务: 系统重启后 Postfix 会自动启动 (已启用 systemd 服务)
- 敏感信息:
/etc/postfix/sasl_passwd包含授权码,确保权限为 600
更换授权码步骤
如果需要更换 QQ 邮箱授权码:
# 1. 编辑密码文件
vi /etc/postfix/sasl_passwd
# 修改为: [smtp.qq.com]:465 byeserver@qq.com:新授权码
# 2. 重新生成数据库
postmap /etc/postfix/sasl_passwd
# 3. 重启 Postfix
systemctl restart postfix
# 4. 测试
echo "Test" | /usr/sbin/sendmail -t test@example.com