Patching Popular Drupal SMTP Modules for Lack of Return-Path Header Support

April 1st, 2012 Permalink

The situation for outgoing mail via SMTP in Drupal 7 is more of a backwater than it should be. There is little ongoing development, yet some necessary use cases are still not supported by the most widely used modules, SMTP Authentication Support and PHPMailer. This seems odd, given the importance of sending mail in core Drupal. Both of these modules are built on top of the venerable and robust PHPMailer library, and both implement their functionality in a way that is broken for the use case I am presently most interested in.

In recent weeks I have been finishing up the work on Bounce, a full featured email non-delivery report management module for Drupal 7 - which is currently sitting in a sandbox repository and waiting on an upgrade to full project status. When mail servers tell you to stop sending mail to a given address, failing to do so is a great way to look like a spambot. The more you send mail after being told not to, the more you will find the global anti-spam infrastructure start to take an interest in your activities - which means you will start to find it hard to deliver mail to anywhere other than junk folders and /dev/null. Up until now Drupal has lacked a good all-in-one module to handle blocking of outgoing mail based on past non-delivery reports, which was one of the reasons I decided to take the code I've been using for this purpose in some other projects and roll it all up into the Bounce module.

When managing non-delivery reports it is vital to be able to set the Return-Path header in outgoing mail. That header is an email address, and can be different from the From and Reply-To email address headers: it tells the receiving mail server where to send non-delivery reports. If you want to feed all of your non-delivery reports to a processing module, then it is very necessary to be able to specify an account that can be assumed to contain nothing but non-delivery reports - which in turn means that all outgoing mail should be given a suitable Return-Path header. In the course of testing Bounce, it has been somewhat aggravating to find that neither the SMTP Authentication Support nor the PHPMailer module support setting the Return-Path header. This seems like a glaring omission.

Now admittedly the way in which you set the Return-Path header in the PHPMailer library is not exactly intuitive:

$mailer = new PHPMailer();
// This sets the Return-Path header in the outgoing mail to be
// something other than $mailer->From.
$mailer->Sender = 'return-path@example.com';

But still, Drupal modules based on the PHPMailer library should allow the Return-Path header to be set, such as through the standard method for setting headers in the mail message via hook_mail_alter():

/**
 * Implements hook_mail_alter().
 */
function bounce_mail_alter(&$message) {
  $return_path = variable_get('bounce_mail_header_return_path', '');
  if ($return_path) {
    $message['headers']['Return-Path'] = $return_path;
  }
}

The above code does not work if you are using either SMTP Authentication Support or PHPMailer to sent outgoing mail via SMTP, however - and these are the modules that people will be most likely be using or be familiar with when they look at Bounce to consider whether to not to use my module. Such is life. So I wrote patches for these two; the links below are to the issue threads at drupal.org:

These are quite simple patches - as you'll see above, the only thing that needs to be done is to set $mailer->Sender correctly. For example:

diff --git a/smtp.mail.inc b/smtp.mail.inc
index a053187..d8fd2d2 100644
--- a/smtp.mail.inc
+++ b/smtp.mail.inc
@@ -228,6 +228,9 @@ class SmtpMailSystem implements MailSystemInterface {
           break;

         case 'return-path':
+          $mailer->Sender = $value;
+          break;
+
         case 'mime-version':
         case 'x-mailer':
           // Let PHPMailer specify these.