Search code examples
phpphpmailer

PHPMailer - Only output server connection in smtpdebug?


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,


Solution

  • 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.