PHPMailer - 仅在 smtpdebug 中输出服务器连接?

PHPMailer - Only output server connection in smtpdebug?

我从 https://github.com/PHPMailer/PHPMailer/issues/2267 交叉发帖,希望这里有人可以帮助我解决这个问题。

I apologize in advance for asking a beginner question but I'm not that good with PHP (though I am working on that).

Currently, I am trying to get PHPMailer to output only server related information to to STDERR (we operate in a Docker environment and this is useful to us).

Here is my current code:

  // Enable logging to STDERR
  if(!defined('STDERR')) define('STDERR', fopen('php://stderr', 'wb'));

  // Output SMTP errors to STDERR
  $phpmailer->SMTPDebug = 2;
  $phpmailer->Debugoutput = function($str, $level) {error_log("debug level $level; message: $str");};

This pretty much does exactly what I want it to do, except it also outputs the entire contents of the email message body into the log which I do not want.

I have tried all the different debug levels and none of them seems to prevent the entire message from being outputted.

I would appreciate any assistance you can provide.

Thank you,

交叉发布 my answer,我认为它在这里也很有用!

您可以在将错误消息保存到日志之前对其进行过滤。注意正在发送的 DATA 命令,并忽略客户端输出,直到您看到新的服务器命令。这是一个典型的消息发送:

2021-02-18 08:28:00 Connection: opening to localhost:2500, timeout=300, options=array()
2021-02-18 08:28:00 Connection: opened
2021-02-18 08:28:00 SERVER -> CLIENT: 220 mac-en0.lan ESMTP
2021-02-18 08:28:00 CLIENT -> SERVER: EHLO mac-en0.lan
2021-02-18 08:28:00 SERVER -> CLIENT: 250-mac-en0.lan Nice to meet you, [127.0.0.1]
                                      250-PIPELINING
                                      250-8BITMIME
                                      250-SMTPUTF8
                                      250 AUTH LOGIN PLAIN
2021-02-18 08:28:00 CLIENT -> SERVER: AUTH LOGIN
2021-02-18 08:28:00 SERVER -> CLIENT: 334 VXNlcm5hbWU6
2021-02-18 08:28:00 CLIENT -> SERVER: [credentials hidden]
2021-02-18 08:28:00 SERVER -> CLIENT: 334 UGFzc3dvcmQ6
2021-02-18 08:28:00 CLIENT -> SERVER: [credentials hidden]
2021-02-18 08:28:00 SERVER -> CLIENT: 235 Authentication successful
2021-02-18 08:28:00 CLIENT -> SERVER: MAIL FROM:<my@email.fr>
2021-02-18 08:28:00 SERVER -> CLIENT: 250 Accepted
2021-02-18 08:28:00 CLIENT -> SERVER: RCPT TO:<name_lastname@example.com>
2021-02-18 08:28:00 SERVER -> CLIENT: 250 Accepted
2021-02-18 08:28:00 CLIENT -> SERVER: DATA
2021-02-18 08:28:00 SERVER -> CLIENT: 354 End data with <CR><LF>.<CR><LF>
2021-02-18 08:28:00 CLIENT -> SERVER: Date: Thu, 18 Feb 2021 08:28:00 +0000
2021-02-18 08:28:00 CLIENT -> SERVER: To: "Lastname, Name" <name_lastname@example.com>
2021-02-18 08:28:00 CLIENT -> SERVER: From: Root User <my@email.fr>
2021-02-18 08:28:00 CLIENT -> SERVER: Subject: =?UTF-8?B?2LfZhNioINin2YbYqtiv2KfYqA==?=
2021-02-18 08:28:00 CLIENT -> SERVER: Message-ID: <CdIzpGbLD6Kc99lGGX3wTS0vGRcMNungIzDbEuHDlQ@Octoo-en0.lan>
2021-02-18 08:28:00 CLIENT -> SERVER: X-Mailer: PHPMailer 6.2.0 (https://github.com/PHPMailer/PHPMailer)
2021-02-18 08:28:00 CLIENT -> SERVER: MIME-Version: 1.0
2021-02-18 08:28:00 CLIENT -> SERVER: Content-Type: text/html; charset=UTF-8
2021-02-18 08:28:00 CLIENT -> SERVER:
2021-02-18 08:28:00 CLIENT -> SERVER: some text
2021-02-18 08:28:00 CLIENT -> SERVER:
2021-02-18 08:28:00 CLIENT -> SERVER: .
2021-02-18 08:28:00 SERVER -> CLIENT: 250 OK: message queued
2021-02-18 08:28:00 CLIENT -> SERVER: QUIT
2021-02-18 08:28:00 SERVER -> CLIENT: 221 Bye
2021-02-18 08:28:00 Connection: closed

方法是当您看到 SERVER -> CLIENT: 354 时停止记录,当您看到 SERVER -> CLIENT 时重新开始。这 确实 意味着您的日志记录是有状态的,这并不理想(例如,如果邮件服务器在发送消息数据时断开连接,您最终可能会处于中断状态),但是它应该可以正常工作。

另一种方法可能是重新安排发送方式。在你的容器中安装一个像 postfix 这样的邮件服务器,并通过 PHPMailer 转发你的发送,然后你可以让邮件服务器进行你的日志记录。这还将处理您的脚本不会执行的与发送电子邮件相关的许多其他事情,例如退回处理、延迟等,并且就您的发送脚本而言也会更快。

像这样(使用 PHP 8):

$phpmailer->Debugoutput = function ($str, $level) {
    static $logging = true;
    if ($logging === false && str_contains($str, 'SERVER -> CLIENT')) {
        $logging = true;
    }
    if ($logging) {
        error_log("debug level $level; message: $str");
    }
    if (str_contains($str, 'SERVER -> CLIENT: 354')) {
        $logging = false;
    }
};

我在调试输出之后执行“关闭”检查,这样 354 行就会出现在日志中。

添加 PHP 7 兼容版本以防其他人需要它,请参阅 How do I check if a string contains a specific word?

// Filter out client message body and output debug info to the logs
// NOTE: Log level must be set to '2' or higher in order for the filter to work
$phpmailer->SMTPDebug = 2;

$phpmailer->Debugoutput = function ($str, $level) {
    static $logging = true;
    if ($logging === false && strpos($str, 'SERVER -> CLIENT') !== false) {
        $logging = true;
    }
    if ($logging) {
        error_log("debug level $level; message: $str");
    }
    if (strpos($str, 'SERVER -> CLIENT: 354') !== false) {
        $logging = false;
    }
};