与其他网站的讨论,SMTP问题:到达文件结尾

(致工作人员:这与我的账户所关联的托管订阅无关)

我根据 Run other websites on the same machine as Discourse 上的说明在 VPS 上安装了 Discourse,但有一点不同:我在首次安装前修改了 app.yml

sudo mkdir /var/discourse
sudo git clone https://github.com/discourse/discourse_docker.git /var/discourse
cd /var/discourse
sudo cp samples/standalone.yml containers/app.yml
sudo nano containers/app.yml

在 YAML 文件中,我注释掉了端口部分,添加了 - "templates/web.socketed.template.yml",并设置了主机名和 SMTP:

  ## TODO: 此 Discourse 实例将响应的域名
  ## 必填项。Discourse 无法仅通过 IP 地址运行。
  DISCOURSE_HOSTNAME: 'discuss.mydomain.community'

  ## TODO: 初始注册时将成为管理员和开发人员的逗号分隔邮箱列表
  ## 示例:'user1@example.com,user2@example.com'
  DISCOURSE_DEVELOPER_EMAILS: 'someuser@protonmail.com,anotheruser@otherdomain.io'

  ## TODO: 用于验证新账户和发送通知的 SMTP 邮件服务器
  # 需要 SMTP 地址、用户名和密码
  # 警告:SMTP 密码中的字符 '#' 可能导致问题!
  DISCOURSE_SMTP_ADDRESS: smtp.myprovider.email
  DISCOURSE_SMTP_PORT: 465
  DISCOURSE_SMTP_USER_NAME: mydomain-no-reply@otherdomain.io
  DISCOURSE_SMTP_PASSWORD: pa$$word
  #DISCOURSE_SMTP_ENABLE_START_TLS: true           # (可选,默认为 true)

随后我引导并启动了 Discourse 应用:

sudo ./launcher bootstrap app
sudo ./launcher start app

这步成功了。我停止 Discourse,并按照建议配置了外部 Nginx(位于 /etc/nginx/conf.d/discourse.conf),仅使用 HTTP 配置(仅用于测试)。我可以访问 http://discuss.mydomain.community

我再次停止 Discourse,并使用 Certbot 升级了 discourse.conf,现在配置如下:

server {
	server_name discuss.mydomain.community;  # <-- 修改此项

	location / {
		proxy_pass http://unix:/var/discourse/shared/standalone/nginx.http.sock:;
		proxy_set_header Host $http_host;
		proxy_http_version 1.1;
		proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
		proxy_set_header X-Forwarded-Proto $scheme;
		proxy_set_header X-Real-IP $remote_addr;
	}

    listen [::]:443 ssl ipv6only=on; # 由 Certbot 管理
    listen 443 ssl; # 由 Certbot 管理
    ssl_certificate /etc/letsencrypt/live/discuss.mydomain.community/fullchain.pem; # 由 Certbot 管理
    ssl_certificate_key /etc/letsencrypt/live/discuss.mydomain.community/privkey.pem; # 由 Certbot 管理
    include /etc/letsencrypt/options-ssl-nginx.conf; # 由 Certbot 管理
    ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # 由 Certbot 管理

}
server {
    if ($host = discuss.mydomain.community) {
        return 301 https://$host$request_uri;
    } # 由 Certbot 管理


	listen 80; listen [::]:80;
	server_name discuss.mydomain.community;
    return 404; # 由 Certbot 管理
}

到目前为止一切顺利。我可以通过 HTTPS 访问 Discourse(后来当出现问题时我执行了 ./launcher rebuild app,但这没有任何区别)。

在提交注册表单后的“完成安装”屏幕上,我收到了提示:“我们已向 someuser@protonmail.com 发送了激活邮件”

问题:未收到邮件。

管理员的邮箱收件箱中没有收到任何邮件。检查 mydomain-no-reply@otherdomain.io 邮箱,也没有任何记录。

注意:整个问题可能是由于邮件用户位于 otherdomain.io,而必须位于 mydomain.community 上。但据我所知,这并不是强制要求。

我开始排查,并随后尝试了以下 app.yml 更改(中间进行了 rebuild app):

  DISCOURSE_SMTP_ENABLE_START_TLS: false

没有成功。继续尝试:

## 如果希望设置首次注册的“发件人”邮箱地址,请取消注释并修改:
  - exec: rails r "SiteSetting.notification_email='mydomain-no-reply@otherdomain.io"

于是我按照 Troubleshoot email on a new Discourse install 进行排查:

  • otherdomain.io 的 DNS 中已正确设置 DKIM 和 SPF
  • 从 VPS 使用 telnet 连接到 SMTP 提供商成功
  • 从 Docker 容器(使用 docker exec 并安装 telnet)测试也成功

我运行了 ./discourse-doctor,其中有两部分结果异常(其余结果符合预期):

========================================
Discourse 版本(discuss.mydomain.community):Discourse 2.6.0.beta2 
Discourse 版本(localhost):未找到
==================== DNS 问题 ====================
该服务器报告“未找到”,但 discuss.mydomain.community 报告为 Discourse 2.6.0.beta2。
这表明存在 DNS 问题,或者中间代理配置有误。
如果您使用的是 Cloudflare 或 CDN,可能配置不当。
==================== 邮件测试 ====================
要进行可靠测试,请从 http://www.mail-tester.com/ 获取一个地址
正在向 REDACTED 发送邮件 . . 
使用 smtp.myprovider.email:465 向 test-k86jiyqb9@srv1.mail-tester.com 发送测试邮件。
======================================== 错误 ========================================
                                    意外错误

到达文件末尾

====================================== 解决方案 =======================================
这不是常见错误,暂无推荐解决方案!

请将上述确切错误信息报告至 https://meta.discourse.org/
(如果您找到解决方案,也请一并告知!)

我尝试了两次:一次使用配置的邮箱,一次使用 mail-tester.com 提供的邮箱。结果相同。情况看起来不太妙。

注意:显然 Docker 安装过程也会提供测试版版本。这点值得注意。

查看生产日志,内容如下:

Started GET "/" for REDACTED-IP at 2020-09-03 06:21:57 +0000
Processing by FinishInstallationController#index as HTML
  Rendering finish_installation/index.html.erb within layouts/finish_installation
  Rendered finish_installation/index.html.erb within layouts/finish_installation (Duration: 3.2ms | Allocations: 356)
  Rendered layouts/_head.html.erb (Duration: 15.7ms | Allocations: 2969)
Completed 200 OK in 323ms (Views: 140.3ms | ActiveRecord: 0.0ms | Allocations: 32137)
Started GET "/finish-installation/register" for REDACTED-IP at 2020-09-03 06:22:01 +0000
Processing by FinishInstallationController#register as HTML
  Rendering finish_installation/register.html.erb within layouts/finish_installation
  Rendered finish_installation/register.html.erb within layouts/finish_installation (Duration: 7.1ms | Allocations: 1607)
  Rendered layouts/_head.html.erb (Duration: 22.3ms | Allocations: 3139)
Completed 200 OK in 107ms (Views: 41.3ms | ActiveRecord: 0.0ms | Allocations: 11760)
Started POST "/finish-installation/register" for REDACTED-IP at 2020-09-03 06:22:22 +0000
Processing by FinishInstallationController#register as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"l1hEEsK/gur5yplJdMIHttZAgYcuzLLkESaAI87IMb88nAFqNwi7l3yJ+3EJBw7leFypVGbH4C5hJl7VnJVYBQ==", "email"=>"someuser@protonmail.com", "username"=>"someusername", "password"=>"[FILTERED]", "commit"=>"Register"}
Redirected to https://discuss.mydomain.community/finish-installation/confirm-email
Completed 302 Found in 48ms (ActiveRecord: 0.0ms | Allocations: 4246)
  Rendering layouts/email_template.html.erb
  Rendered layouts/email_template.html.erb (Duration: 0.2ms | Allocations: 31)
Started GET "/finish-installation/confirm-email" for REDACTED-IP at 2020-09-03 06:22:22 +0000
Processing by FinishInstallationController#confirm_email as HTML
  Rendering finish_installation/confirm_email.html.erb within layouts/finish_installation
  Rendered finish_installation/confirm_email.html.erb within layouts/finish_installation (Duration: 2.3ms | Allocations: 418)
  Rendered layouts/_head.html.erb (Duration: 7.9ms | Allocations: 1612)
Completed 200 OK in 25ms (Views: 22.1ms | ActiveRecord: 0.0ms | Allocations: 4611)
Delivered mail ea8af868-4a2c-4312-85dd-f57061a3cd90@discuss.mydomain.community (60015.9ms)
Job exception: Net::ReadTimeout

稍等片刻后,通过浏览器请求“重新发送通知邮件”。生产日志中随后新增了以下内容:

Delivered mail 47ca6f15-cd9e-4c96-a670-6646e2bda585@discuss.mydomain.community (60007.9ms)
Job exception: end of file reached

  Rendering layouts/email_template.html.erb
  Rendered layouts/email_template.html.erb (Duration: 0.2ms | Allocations: 31)
Delivered mail 02367872-af3a-4df4-9a68-4e5e7c5eda60@discuss.mydomain.community (60007.4ms)
Job exception: end of file reached

  Rendering layouts/email_template.html.erb
  Rendered layouts/email_template.html.erb (Duration: 0.2ms | Allocations: 31)
Delivered mail ee9ee1fc-6fd1-4970-89fa-260efe2dd04c@discuss.mydomain.community (60014.1ms)
Job exception: end of file reached

  Rendering layouts/email_template.html.erb
  Rendered layouts/email_template.html.erb (Duration: 0.1ms | Allocations: 31)
Delivered mail 9030f87b-99df-4de2-9a60-2c57f7c752de@discuss.mydomain.community (60007.0ms)
Job exception: end of file reached

  Rendering layouts/email_template.html.erb
  Rendered layouts/email_template.html.erb (Duration: 0.2ms | Allocations: 31)
Started PUT "/finish-installation/resend-email" for REDACTED-IP at 2020-09-03 06:31:22 +0000
Processing by FinishInstallationController#resend_email as HTML
  Parameters: {"authenticity_token"=>"NE21scxxyZz3/DxDkoF8kwi9GXoNKvnstNJdKZjQs7afigDKWcbw4XK/XnvvRHTApqExqUUghybE1oPfyo3aDA=="}
  Rendering finish_installation/resend_email.html.erb within layouts/finish_installation
  Rendered finish_installation/resend_email.html.erb within layouts/finish_installation (Duration: 0.9ms | Allocations: 163)
  Rendered layouts/_head.html.erb (Duration: 2.5ms | Allocations: 269)
Completed 200 OK in 63ms (Views: 6.5ms | ActiveRecord: 0.0ms | Allocations: 6408)
  Rendering layouts/email_template.html.erb
  Rendered layouts/email_template.html.erb (Duration: 0.2ms | Allocations: 31)
Delivered mail 127cc350-3fb0-4ef1-8759-391fb407b1cb@discuss.mydomain.community (60008.0ms)
Job exception: Net::ReadTimeout

Delivered mail d9c70dfd-5a8b-4f4c-bafa-5a540fc8ed4f@discuss.mydomain.community (60010.0ms)
Job exception: end of file reached

  Rendering layouts/email_template.html.erb
  Rendered layouts/email_template.html.erb (Duration: 0.1ms | Allocations: 31)
Delivered mail e9e67ed1-d7b1-4e8a-ba11-30501c6fae89@discuss.mydomain.community (60012.4ms)
Job exception: end of file reached

  Rendering layouts/email_template.html.erb
  Rendered layouts/email_template.html.erb (Duration: 0.2ms | Allocations: 31)
  Rendering layouts/email_template.html.erb
  Rendered layouts/email_template.html.erb (Duration: 0.1ms | Allocations: 31)
Delivered mail 82d0361e-0349-4a1a-928e-dcb16dcffdbc@discuss.mydomain.community (60008.6ms)
Job exception: end of file reached

我已联系主机提供商,确认问题是否出在他们那边。他们表示根据他们的判断,此配置应能正常工作,但 VPS 在 SMTP 服务器上完全没有产生任何活动。

这就是我的现状……现发布到 Meta 论坛求助。

是否出站到邮件服务器的流量被阻断了?你能从容器内部 telnet 到那里吗?

是的,我可以在 Docker 容器内部使用 telnet 成功连接到 SMTP 服务器。不过,我无法使用 telnet 发送测试邮件,因为我的提供商不允许这样做(在发送更多命令时会关闭连接)。

解决方案看起来很简单。虽然我的服务商指出的是上述端口,但我通过 telnet 测试了 587 端口,发现它也能正常工作。于是我修改了 app.yml 并重新构建……一切运行正常 :smiley:

在我看到这一点之前,我本来要推荐这个更改。

端口 465 是 SMTP-over-SSL,已被弃用。
端口 587 是 MSA 端口(邮件提交代理),通常支持 STARTTLS(从明文连接升级到 TLS 连接)。

当您在配置中使用 465 时,Discourse 试图以明文方式与 SSL 端口通信。

谢谢 @supermathie,我已将你的回答设为解决方案。解释得很清楚。

你好 @supermathie

据我所知,根据 RFC 8314,端口 465 已被(或正在)恢复使用。我当前的电子邮件提供商(mailfence.com)似乎遵循了这一建议。

是否有任何方法可以强制在端口 465 的连接上使用 TLS?这应该能解决我的问题,因为我已通过 swaks 验证,使用 STARTTLS(–tls)会失败,而在容器内使用 --tls-on-connect(–tlsc)则能正常工作:

swaks --to user@example.com --from myuser@mailfence.com --server smtp.mailfence.com:465 --auth LOGIN --tlsc --auth-user myuser@mailfence.com

祝好,

啊,它正被重新用作基于 TLS 的提交,这很合理。

目前还不行。看起来当你在 smtp_settings 中设置 :ssl = true 时,ActionMailer 支持该功能,但我们目前没有启用该功能的代码路径。

我们相信,如果有人提交一个添加该支持的 PR,我们会非常欢迎。