为自托管站点使用 Mail-Receiver 配置直接交付的收件邮箱

你好!我遇到了一个奇怪的问题,我按照指南设置了它,而且效果很好!但是,出站电子邮件出现了一些问题,我原本以为这不会受到任何影响。自从我启用 mail-receiver 后,Sidekiq 就会为每一次尝试发送的电子邮件(所有卡在 Retries 列表中的邮件)报出以下错误:

Jobs::HandledExceptionWrapper: Wrapped OpenSSL::SSL::SSLError: SSL_read: unexpected eof while reading

我的搜索结果表明这与 TLS 有关。我曾取消注释 .yml 文件中与 TLS 相关的行,但重新注释掉它们也没有解决问题。我尝试了指南中关于解决 Postfix 冲突的说明,但似乎我没有 Postfix?(指南中提到的 /etc/postfix 目录在我的实例上不存在,它也不将 postfix 识别为服务。)根据 netstat 的结果,只有 docker-proxy 在使用 25 端口。

我们使用 Gmail 作为出站 SMTP 服务,事实上,在此之前我们已经使用 Gmail 进行入站 POP3 轮询。我确实删除了许多指向 Google 的 MX 记录,但指南说要这样做。

这是我的 mail-receiver.yml,其中一些细节当然被隐藏了:

## 这是入站邮件接收器容器模板
##
## 修改此文件后,您必须重建
## /var/discourse/launcher rebuild mail-receiver
##
## 编辑时请*非常小心*!
## YAML 文件对空格或对齐错误非常非常敏感!
## 如有需要,请访问 http://www.yamllint.com/ 来验证此文件

base_image: discourse/mail-receiver:release
update_pups: false

expose:
  - "25:25"   # SMTP

env:
  LC_ALL: en_US.UTF-8
  LANG: en_US.UTF-8
  LANGUAGE: en_US.UTF-8

  ## 发送电子邮件到您的论坛的地址。通常情况下,使用
  ## 与论坛本身相同的域名是完全可以的。
  MAIL_DOMAIN: discourse.[mydomain].org
# 取消注释这些行(以及下面的 volume!)以支持 TLS
  POSTCONF_smtpd_tls_key_file:  /letsencrypt/discourse.[mydomain].org/discourse.[mydomain].org.key
  POSTCONF_smtpd_tls_cert_file:  /letsencrypt/discourse.[mydomain].org/fullchain.cer
  POSTCONF_smtpd_tls_security_level: may


  ## 此 Discourse 实例的基础 URL。
  ## 这将是您的 Discourse 站点 URL。例如,
  ## https://discourse.example.com。如果您正在运行子文件夹设置,
  ## 请务必考虑进去(例如 https://example.com/forum)。
DISCOURSE_BASE_URL: 'https://discourse.[mydomain].org'

  ## 您 Discourse 论坛的主 API 密钥。您可以在
  ## 管理面板的“API”选项卡中找到它。
  DISCOURSE_API_KEY: [myapikey]

  ## 用于处理入站电子邮件的用户名。除非您
  ## 重命名了 `system` 用户,否则应保持原样。
  DISCOURSE_API_USERNAME: system

volumes:
  - volume:
      host: /var/discourse/shared/mail-receiver/postfix-spool
      guest: /var/spool/postfix
# 取消注释以支持 TLS
  - volume:
      host: /var/discourse/shared/standalone/letsencrypt
      guest: /letsencrypt

电子邮件技术有点超出我的专业范围,所以任何建议我都将感激不尽,即使只是指出我在设置过程中遗漏了什么愚蠢的东西。谢谢!

1 个赞

正如你所想,这与颈部接收器无关。你正在通过其发送邮件的主机具有损坏的 SSL 证书。

好吧,经过一番排查,我终于弄明白了。问题可能出在我们托管 Discourse 实例的域名与我们的 MX 记录所在的域名不同。一旦我弄清楚了这一点,一切就都迎刃而解了。

这绝对是我的愚蠢错误,但指南中的这一点也让我有些困惑:

这里并没有非常清楚地说明,两个 forum.example.com 条目不必完全相同,而在我的情况下,它们需要不同。也许使用此指南的人应该足够有经验来知道这一点,但我不知道。所以,我在这里留下这些信息,以供其他可能遇到类似问题的人参考。我学到了一些关于 DNS 的知识,这对我来说是一次很好的学习经历,现在一切都运行得很顺利。 :slight_smile:

好吧,我话说的太早了。发件电子邮件工作正常,入站回复似乎也工作正常,但发送到类别电子邮件地址却悄无声息地失败了。我直接从设置中将地址复制粘贴到新电子邮件中,所以我知道没有拼写错误。

我的 mail-receiver 的日志主要有三种类型的条目。成功的那个,也就是已发送回复到现有帖子的邮件,看起来是这样的:

Sep 20 16:59:44 discourse-mail-receiver postfix/smtpd[277]: connect from server168-1.web-hosting.com[68.65.122.144]
Sep 20 16:59:45 discourse-mail-receiver postfix/smtpd[277]: NOQUEUE: reject: RCPT from server168-1.web-hosting.com[68.65.122.144]: 454 4.7.1 <[category]@discourse.[domain].org>: Relay access denied; from=<ryan@[redacted].com> to=<[category]@discourse.[domain].org> proto=ESMTP helo=<server168-1.web-hosting.com>
<22>Sep 20 16:59:45 policyd-spf[288]: : prepend Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=[redacted]; helo=server168-1.web-hosting.com; envelope-from=ryan@[redacted].com; receiver=discourse.[domain].org Sep 20 16:59:45 discourse-mail-receiver postfix/cleanup[281]: 4CCED114200: message-id=<20240920165945.4CCED114200@discourse-mail-receiver.localdomain>
Sep 20 16:59:45 discourse-mail-receiver postfix/smtpd[277]: disconnect from server168-1.web-hosting.com[68.65.122.144] ehlo=1 starttls=0/1 mail=1 rcpt=0/1 data=0/1 quit=1 commands=3/6

除此之外,还有两种(我认为是)错误,每种都重复了很多次。第一个看起来像:

Sep 20 17:00:23 discourse-mail-receiver postfix/qmgr[124]: 5D162FC26D: from=<double-bounce@discourse-mail-receiver.localdomain>, size=960, nrcpt=1 (queue active)

另一个:

Sep 20 17:00:23 discourse-mail-receiver postfix/error[293]: 8DC3BFC141: to=<postmaster@discourse-mail-receiver.localdomain>, orig_to=<postmaster>, relay=none, delay=126622, delays=126622/0.05/0/0, dsn=4.4.3, status=deferred (delivery temporarily suspended: Host or domain name not found. Name service error for name=discourse-mail-receiver.localdomain type=MX: Host not found, try again)

这是我的 mailq 的样子,只有这样的条目一遍又一遍地重复:

3D07BFC23D      960 Fri Sep 20 06:42:23  double-bounce@discourse-mail-receiver.localdomain
(delivery temporarily suspended: Host or domain name not found. Name service error for name=discourse-mail-receiver.localdomain type=MX: Host not found, try again)
                                         postmaster@discourse-mail-receiver.localdomain

其中一些看起来与 Discourse 发送的电子邮件有关,然后由于某种原因被退回。mail-receiver 是否有任何处理这些退信的功能,还是它们会永远停留在 mailq 中?

其次,为什么回复有效,但直接通过电子邮件发布到类别却无效?再次感谢您的帮助和耐心。 :slight_smile:

这看起来像是发送到某个分类地址失败的日志条目,而不是成功回复帖子的日志条目。

我不完全确定,但我想 relay access denied(中继访问被拒绝)表明 discourse.[domain].org 可能不是 mail-receiver.yml 中用于 MAIL_DOMAIN 的域名。也许回复地址通过其他方式被允许了。

我知道 MAIL_DOMAIN 的内容至少会出现在 postfix 配置文件的一个地方,所以更改它可能需要重建容器。你是否更改了 MAIL_DOMAIN?如果更改了,之后是否运行了 ./launcher rebuild mail-receiver

2 个赞

[抱歉,在完成上一篇帖子之前意外按下了回车键]

我还在为这个问题苦恼。但我有一个关于问题可能出在哪里的新想法。我正在使用两个域,我们称它们为 [domain1] 和 [domain2]。我的 Gmail SMTP 中继托管在 [domain1] 上。我的 Discourse 实例以及我的 mail-receiver 都托管在 [domain2] 上。

当邮件从 [domain1] 发出时,我该如何在 Discourse 中设置 reply-by-email-address 设置,强制将回复地址设为 [domain2]?当我尝试这样做时,会收到上面提到的 SSL EOF 错误。我假设我遗漏了一些 DNS 认证技巧或别的东西。

看起来我终于弄明白了。为了让“回复地址”位于与 SMTP 中继不同的域中,我需要放宽 Google Workspace 中的一些设置。现在一切似乎都按预期在两个方向上正常工作。

1 个赞

还有一个最终问题。尽管现在一切正常,但我的 mailq 中仍有大量旧条目。这些很可能是使用错误设置生成的电子邮件,因此将永远卡在中间状态。我宁愿删除它们然后继续。那么,如何清除 mailq

这是一个比较旧的帖子,但 SSL EOF 错误最常见的原因可能是 OpenSSL 版本冲突:v1.1.1f 与 v3。升级旧的 1.1.1f 版本将是解决方案。坏消息是,例如 Ubuntu 20.x 不能使用更新的版本,因此整个 Ubuntu 都需要升级。

1 个赞

我对此感到非常沮丧,花了几个小时。我似乎无法绕过这个启动器错误,尽管我的配置文件名都是小写的。

“错误:配置名称不得包含大写字符、空格或特殊字符。请更正配置名称并重新运行 ./launcher。”

在运行

./launcher rebuild mail-receiver

./launcher bootstrap mail-receiver

./launcher start mail-receiver

时。我可以在启动器代码库中看到它。

可恶——请帮忙!

尝试了上面链接帖子中与区域设置相关的所有内容,以及我在其他地方能找到的所有内容。

./launcher rebuild app___ 都可以正常工作!

我确实有一个可能的线索:在我意外地在命名配置文件时按下了大写锁定键(但只大写了两个字母),然后我立即禁用了大写锁定键并在保存之前重新输入了这两个字母之后,这种情况就开始发生了。
很难想象这个短暂的输入错误/更正会引起这个问题,但也许大写字母卡在了某个缓冲区里,或者???

这超出了我的知识范围,但我很惊讶错误消息没有输出 $config 变量 :thinking:
这肯定有助于调试。

1 个赞

感谢 @Canapin!- 这正是我试图设置的:

https://www.perplexity.ai/search/provide-the-code-lJcI4BrFQ2auuD42ehYFwA

您能复制粘贴您命令行中的所有内容吗?

从您的 ./launcher start mail-receiver 到错误消息,以及确切的 .yml 文件名?

如果我将配置文件重命名为 Mail-receiver.yml./launcher start Mail-receiver 将输出

ERROR: Config name 'Mail-receiver' must not contain upper case characters, spaces or special characters. Correct config name and rerun ./launcher.

这里错误消息中包含了文件名。

另外,如果您运行 ./launcher start aaa,它找不到任何相应的文件,并且会列出可用的文件。它只从文件夹中选择,所以这里没有什么神奇之处,但也许它会输出一些有趣的东西 :person_shrugging:

ERROR: containers/aaa.yml does not exist or is not readable.

Available configs ( app, mail-receiver )

太感谢了——我已经解决了并且可以正常工作了。

最终问题是什么?可以帮助其他人 :slight_smile:

没有问题,这只是一个学习曲线,用来理解各种服务器组件如何交互以路由域和电子邮件。我以前从未深入学习过 postfix。这很有趣,我学到了很多东西。

我最终确定的方法是使用一个 mail-receiver.yml(一个 docker 容器)与每个 Discourse 实例配对,所有实例共享端口 25,并使用 postfix 中的传输功能来处理路由。

2 个赞

我在我的专用服务器(运行 Ubuntu 22.04,安装了 Postfix)上,为启用了邮件内发帖功能的每个 Discourse 实例使用了一个单独的 mail-receiver.yml 文件。

此设置会在我的服务器上为每个 Discourse 实例创建一个单独的容器(与典型的 app 容器并列),该容器接收并处理对应 Discourse 实例的电子邮件。

服务器上所有 Discourse 论坛的入站电子邮件都通过标准端口 25 由 Postfix 接收,其中主要的 Postfix 配置文件使用“传输映射”通过解析电子邮件“To:”地址中的域名来将每封电子邮件“中继”到其目标 Discourse 论坛。

因此,除了本主题的说明外,我还…

  1. 修改了现有的 postfix 配置文件:/etc/postfix/main.cf

  2. 然后,我添加了相应的 postfix 传输映射 文件:/etc/postfix/transport

  1. 最后,我添加了相应的文件来为每个论坛创建电子邮件容器:
    /var/discourse/containers/mail-receiver-domain1.yml
    /var/discourse/containers/mail-receiver-domain2.yml
    /var/discourse/containers/mail-receiver-domain3.yml
    /var/discourse/containers/mail-receiver-domain4.yml
    /var/discourse/containers/mail-receiver-domain5.yml

3 个赞

mail-receiver.yml 中没有 DISCOURSE_MAIL_ENDPOINT,还有 DISCOURSE_BASE_URL 需要更改。

2 个赞

我使用了一个邮件转发服务,该服务支持将邮件以 JSON 格式转发到 webhook。\n\n这是否是电子邮件直接投递的一种选项?

1 个赞