0

I am cross-posting from https://github.com/PHPMailer/PHPMailer/issues/2267 in hopes that someone here can help me resolve this issue.

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,

Joel
  • 135
  • 9

2 Answers2

0

Crossposting my answer, as I figure it may be useful here too!

You can filter the error messages before saving them to your log. Look out for the DATA command being sent, and ignore client output until you see a new server command. Here is a typical message send:

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

The approach would be to stop logging when you see SERVER -> CLIENT: 354, and start again when you see SERVER -> CLIENT. This does mean that your logging is stateful, which isn't ideal (e.g. you can end up in a broken state if the mail server drops the connection while the message data is sending), but it it should work ok.

A different approach might be to rearrange how you're sending. Install a mail server like postfix inside your container and relay your sends through that from PHPMailer, then you can get the mail server to do your logging. This will also take care of many other things relating to sending email that your script will not be doing, such as bounce handling, deferrals, etc, and will also be much faster as far as your sending scripts are concerned.

Something like this (using 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;
    }
};

I do the "turn off" check after the debug output so that the 354 line will appear in the logs.

Synchro
  • 35,538
  • 15
  • 81
  • 104
0

Adding PHP 7 compatible version in case anyone else needs it, see 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;
    }
};
Joel
  • 135
  • 9