PHP 通过 OpenSMTPD 的邮件中继 returns 错误消息不符合 RFC 2822

PHP's mail relay via OpenSMTPD returns error Message is not RFC 2822 compliant

我的 php.ini

中有以下设置
[mail function]
sendmail_path = /usr/sbin/sendmail -t -i

二进制文件 /usr/sbin/sendmail 来自 Alpine Linux 上安装的 ssmtp 包。我想将所有电子邮件从专用网络转发到 opensmtpd 容器,所以我的 /etc/ssmtp.conf 看起来像这样:

mailhub=opensmtpd

这是我发送电子邮件的方式:

$ php -r 'mail("valid@address.com", "Test subject", "This is our test message", "From: my@email.com");'

我收到以下错误:

sendmail: 550 5.7.1 Delivery not authorized, message refused: Message is not RFC 2822 compliant


更新

sendmail 命令添加了更多冗长内容,并对 /etc/ssmtp.conf 进行了一些调整,如下所示:

mailhub=opensmtpd:25
FromLineOverride=Yes
UseTLS=No

我是这样称呼它的

$ php -r '$headers = ["Date" => date("r", time()), "From" => "my@email.com", "Reply-To" => "my@email.com", "X-Mailer" => "PHP/" .
 phpversion()]; mail("valid@email.com", "Test subject", "This is our test masdlkfjaslkdfjaslkdfjaskldjfeproiqweessage\r\n", $headers);'

这是输出:

[<-] 220 opensmtpd-2298774033-mq2hl ESMTP OpenSMTPD
[->] HELO php-3107772150-7jj96
[<-] 250 opensmtpd-2298774033-mq2hl Hello php-3107772150-7jj96 [172.17.0.60], pleased to meet you
[->] MAIL FROM:<my@email.com>
[<-] 250 2.0.0: Ok
[->] RCPT TO:<opensmtpd:25@php-3107772150-7jj96>
[<-] 250 2.1.5 Destination address valid: Recipient ok
[->] DATA
[<-] 354 Enter mail, end with "." on a line by itself
[->] Received: by php-3107772150-7jj96 (sSMTP sendmail emulation); Fri, 01 Apr 2022 14:13:35 +0000
[->] To: valid@email.com
[->] Subject: Test subject
[->] Date: Fri, 01 Apr 2022 14:13:35 +0000
[->] From: my@email.com
[->] Reply-To: my@email.com
[->] X-Mailer: PHP/8.0.17
[->]
[->] This is our test masdlkfjaslkdfjaslkdfjaskldjfeproiqweessage
[->]
[->]
[->] .
[<-] 550 5.7.1 Delivery not authorized, message refused: Message is not RFC 2822 compliant

我不明白


更新 2

正如您从上面的输出中看到的,收件人是不正确的,那是因为来自 Alpine 包的 ssmtp 的 sendmail 不支持 -t 标志。您当然可以将 php 配置中的 sendmail_path 更改为 /usr/sbin/ssmtp -t -f,这将设置正确的收件人,但不幸的是 ssmtp 不支持对我来说至关重要的 -v 标志调试。

我实际上让它工作了很短的时间。我已经删除了 ssmtp 包,所以 /usr/sbin/sendmail 现在可以从 busybox 中使用。这就是我首先使用的,问题是它不能从消息中覆盖 FROM 电子邮件,所以你必须对发件人进行硬编码:

sendmail_path = /usr/sbin/sendmail -t -i -f my@email.com -v -S opensmtpd:25

一旦我这样做并在我的正文消息前加上 Body: 它开始工作,我实际上收到了电子邮件。但是,它还在我觉得很奇怪的实际电子邮件消息中包含“正文:”。我想这可能是 OpenSMTPD 中的一个错误,所以我将它从 6.0.3 更新到 6.7.1。之后它又停止工作了:

sendmail: recv:'220 opensmtpd-839025387-f4d7n ESMTP OpenSMTPD'
sendmail: send:'EHLO php-4163283461-9fd2b'
sendmail: recv:'250-opensmtpd-839025387-f4d7n Hello php-4163283461-9fd2b [172.17.0.50], pleased to meet you'
sendmail: recv:'250-8BITMIME'
sendmail: recv:'250-ENHANCEDSTATUSCODES'
sendmail: recv:'250-SIZE 36700160'
sendmail: recv:'250-DSN'
sendmail: recv:'250 HELP'
sendmail: send:'MAIL FROM:<my@email.com>'
sendmail: recv:'250 2.0.0 Ok'
sendmail: send:'RCPT TO:<valid@email.com>'
sendmail: recv:'250 2.1.5 Destination address valid: Recipient ok'
sendmail: send:'DATA'
sendmail: recv:'354 Enter mail, end with "." on a line by itself'
'endmail: send:'To: valid@email.com
'endmail: send:'Subject: Test subject
'endmail: send:'From: my@email.com
'endmail: send:'
'endmail: send:'Body: This is our test message
sendmail: send:''
sendmail: send:'.'
sendmail: recv:'550 5.7.1 Delivery not authorized, message refused: Message is not RFC 2822 compliant'
sendmail: . failed

这是 opensmtpd 配置:

listen on 0.0.0.0

table aliases file:/etc/smtpd/aliases

queue ttl 4d

bounce warn-interval 1h, 6h, 2d

smtp max-message-size 35M

table authinfo db:/etc/smtpd/authinfo.db
action act01 relay host "smtp+tls://user@host:587" auth <authinfo>
match from any for any action act01

直接从 OpenSMTPD 发送电子邮件非常有效。

RFC2822 表示日期:和发件人:headers 是必需的(第 3.6 节)

正如@tripleee 在 OpenSMTPD 的 it seems this is a known bug 中指出的那样。我尝试在正文前添加一个 CR (\r):

$ php -r 'mail("<valid@email.com>", "Test subject", "\rThis is our test message", "From: my@email.com");'

它有效,但仅适用于 OpenSMTPD 6.0,不适用于 6.7:

sendmail: recv:'220 opensmtpd-401834694-0hz0r ESMTP OpenSMTPD'
sendmail: send:'EHLO php-4163283461-9fd2b'
sendmail: recv:'250-opensmtpd-401834694-0hz0r Hello php-4163283461-9fd2b [172.17.0.50], pleased to meet you'
sendmail: recv:'250-8BITMIME'
sendmail: recv:'250-ENHANCEDSTATUSCODES'
sendmail: recv:'250-SIZE 36700160'
sendmail: recv:'250-DSN'
sendmail: recv:'250 HELP'
sendmail: send:'MAIL FROM:<my@email.com>'
sendmail: recv:'250 2.0.0: Ok'
sendmail: send:'RCPT TO:<valid@email.com>'
sendmail: recv:'250 2.1.5 Destination address valid: Recipient ok'
sendmail: send:'DATA'
sendmail: recv:'354 Enter mail, end with "." on a line by itself'
'endmail: send:'To: <valid@email.com>
'endmail: send:'Subject: Test subject
'endmail: send:'From: my@email.com
'endmail: send:'
'his is our test message
sendmail: send:''
sendmail: send:'.'
sendmail: recv:'250 2.0.0: 9b837971 Message accepted for delivery'
sendmail: send:'QUIT'
sendmail: recv:'221 2.0.0: Bye'

已更新

我在 php 存储库中发现 this issue 讨论了与 CRLF 相同的问题,以及如何修复它的建议适用于所有版本的 OpenSMTPD:

sendmail_path = '/usr/bin/dos2unix -u | /usr/sbin/sendmail -t -i -f my@email.com -v -S opensmtpd:25'

我仍然不确定不遵循 RFC 导致问题的确切原因是什么,它是 php、sendmail(busybox 和 ssmtp)或 OpenSMTPD。但现在我认为 dos2unix 的解决方法是我的问题的解决方案。


加法

the issue reported in php repository saying that headers are not delimited with CRLF as it should according to the RFC. And this is the commit 修复了它(据我所知,自 8.1.3 和 8.0.16 以来)。因此,PHP 现在使用正确的分隔符 \r\n 但 sendmail 需要 \n 所以看起来它毕竟是一个 sendmail 错误。