Problem/Motivation
PhpMailerSmtp is used as a singleton across multiple \Drupal::service('plugin.manager.mail')->mail() calls within the same PHP process (e.g., during a cron run). After each successful SMTP send, PhpMailerSmtp::reset() is called to prepare the object for the next message. However, reset() does not clear $this->Body or $this->AltBody.
When phpmailer_smtp is used as the formatter for a message, format() calls $this->msgHTML(), which sets both $this->Body and $this->AltBody. After that message is sent and reset() runs, $this->AltBody retains the plain-text content from the previous message.
When the next message is then sent — particularly one using a different formatter such as MimeMail, which sets $message['body'] to a complete MIME string and does not touch $this->AltBody — PhpMailerSmtp::mail() sets $this->Body = $message['body'] but leaves $this->AltBody populated with stale content from the previous send. PHPMailer detects a non-empty $this->AltBody and wraps the message in its own multipart/alternative structure, producing a malformed email: the stale plain-text appears as the text/plain part, and the complete MIME body (e.g., a MimeMail-generated MIME document with its own boundaries) appears raw as the text/html part.
Steps to reproduce
- Configure two mail keys: one using
phpmailer_smtpas both formatter and sender (e.g., an internal notification), and one usingmime_mailas formatter andphpmailer_smtpas sender (e.g., a branded notification). - Send both emails in the same PHP process in that order — for example, from two consecutive
hook_cron()implementations. - Inspect the second email (the MimeMail-formatted one). It will contain a PHPMailer-generated
multipart/alternativewrapper whosetext/plainpart contains the body of the first email, and whosetext/htmlpart contains a raw MIME document string rather than rendered HTML.
Proposed resolution
Add $this->Body = ''; and $this->AltBody = ''; to PhpMailerSmtp::reset(), ensuring both properties are cleared between sends alongside the existing recipient, header, and attachment resets.
public function reset() { $this->clearAllRecipients(); $this->clearReplyTos(); $this->clearAttachments(); $this->clearCustomHeaders(); $this->Priority = 3; $this->CharSet = 'utf-8'; $this->ContentType = 'text/plain'; $this->Encoding = '8bit'; $this->Body = ''; $this->AltBody = ''; $from_name = $this->config->get('smtp_fromname'); if ($from_name == '') { $from_name = $this->configFactory->get('system.site')->get('name'); } $this->FromName = $from_name; $this->Sender = ''; $this->MessageID = ''; }
Remaining tasks
- Review patch
- Commit to 2.x
Issue fork phpmailer_smtp-3593584
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #3
imclean commentedThanks for the detailed report. This makes sense and shouldn't cause any problems.
Comment #4
imclean commented