Overriding Drupal's mail() function

This article outlines a quick Drupal hack for controlling how mail gets sent. It was originally posted on matthine.com.

After setting a Drupal site recently up I found that the contact form wasn't working. That is, it would report that email was being sent, but no email would arrive at its destination. From past experience I guessed this might be something to do with my ISP's email configuration. It was a bit difficult to tell without a meaningful (or any) error message, and another site with a very similar configuration was sending out emails fine, probably via a different mail server, but it seemed like the best place to start.

I looked briefly into adding an SMTP module, but didn't see the need. Instead, I used the smtp_library variable to force drupal to include and execute a drupal_mail_wrapper() function. If this variable is set, Drupal loads the file in the variable and calls this function, passing $message, which is an array containing the message data.

I have a general purpose module that provides minor bits of additional functionality, so I put this there. It could go anywhere - just put your own mail() function in its own file somewhere, and put the path to that file in smtp_library in your config.

Here's how I did mine:

My module is called 'coherent'. Here is the line in the init function that sets the smtp_library variable.

   1:  function coherent_init() {    
   2:      // snip
   3:      variable_set('smtp_library', drupal_get_path('module','coherent') . '/smtp.inc.php');    
   4:  }

The file smtp.inc.php is actually empty. I put my own mail function in the coherent module. This could potentially cause function name collisions but I am using this in a controlled environment.

The mail function is very similar to Drupal's own. The only difference is that it adds a '-f' additional parameter to the mail() call, this being the extra information required by my ISP's security.

   1:  function drupal_mail_wrapper($message) {
   2:      $mimeheaders = array();
   3:      foreach ($message['headers'] as $name => $value) {
   4:          $mimeheaders[] = $name .': '. mime_header_encode($value);
   5:      }
   6:      return mail(
   7:          $message['to'],
   8:          mime_header_encode($message['subject']),
   9:          // Note: e-mail uses CRLF for line-endings, but PHP's API requires LF.
  10:          // They will appear correctly in the actual e-mail that is sent.
  11:          str_replace("\r", '', $message['body']),
  12:          // For headers, PHP's API suggests that we use CRLF normally,
  13:          // but some MTAs incorrecly replace LF with CRLF. See #234403.
  14:          join("\n", $mimeheaders),
  15:          // Add in an explicit sendmail '-f' from arg
  16:          '-f'.$message['from']
  17:      );
  18:  }

The Drupal mail function, then, looks like this:

   1:  function drupal_mail_send($message) {
   2:    // Allow for a custom mail backend.
   3:    if (variable_get('smtp_library', '') && file_exists(variable_get('smtp_library', ''))) {
   4:      include_once './'. variable_get('smtp_library', '');
   5:      return drupal_mail_wrapper($message);
   6:    }
   7:      // etc...

With the smtp_library function set, and a file present (hence the blank include file described above), the drupal_mail_wrapper() function gets called, and the mail gets sent.

This website and its content is copyright of NMGLC and respective authors - © NMGLC 2008. All rights reserved.