You are here

function smtp_drupal_mail_wrapper in SMTP Authentication Support 6

Sends out the e-mail.

Parameters

message: An array with at least the following elements: id, to, subject, body and headers.

See also

drupal_mail_send()

1 call to smtp_drupal_mail_wrapper()
smtp.module in ./smtp.module
Enables Drupal to send e-mail directly to an SMTP server.

File

./smtp.module, line 327
Enables Drupal to send e-mail directly to an SMTP server.

Code

function smtp_drupal_mail_wrapper($message) {
  $id = $message['id'];
  $to = $message['to'];
  $from = $message['from'];
  $language = $message['language'];
  $subject = $message['subject'];
  $body = $message['body'];
  $headers = $message['headers'];
  if (!smtp_load_library()) {
    watchdog('smtp', 'Could not locate PHPMailer library.', array(), WATCHDOG_ERROR);
    return FALSE;
  }

  // Create a new PHPMailer object.
  $mail = new PHPMailer();

  // Set the language PHPMailer is to use.
  if (!$language) {
    global $language;
    if ($language) {
      $mail
        ->SetLanguage($language->language, drupal_get_path('module', 'smtp') . '/phpmailer/language/');
    }
  }
  else {
    $mail
      ->SetLanguage($language->language, drupal_get_path('module', 'smtp') . '/phpmailer/language/');
  }

  // Turn in debugging, if requested.
  if (variable_get('smtp_debugging', 0) == 1 && user_access('administer smtp module')) {
    $mail->SMTPDebug = TRUE;
  }

  // Set the from name and e-mail address.
  $from_name = variable_get('smtp_fromname', '');
  if ($from_name == '') {

    // If value is not defined in settings, use site_name.
    $from_name = variable_get('site_name', '');
  }

  //Hack to fix reply-to issue.
  $properfrom = variable_get('site_mail', '');
  if (!empty($properfrom)) {
    $headers['From'] = $properfrom;
  }
  if (!isset($headers['Reply-To']) || empty($headers['Reply-To'])) {
    if (strpos($from, '<')) {
      $reply = preg_replace('/>.*/', '', preg_replace('/.*</', '', $from));
    }
    else {
      $reply = $from;
    }
    $headers['Reply-To'] = $reply;
  }

  // Blank value will let the e-mail address appear.
  if ($from == NULL || $from == '') {

    // If from e-mail address is blank, use smtp_from config option.
    if (($from = variable_get('smtp_from', '')) == '') {

      // If smtp_from config option is blank, use site_mail.
      if (($from = variable_get('site_mail', '')) == '') {
        drupal_set_message(t('There is no submitted from address.'), 'error');
        watchdog('smtp', 'There is no submitted from address.', array(), WATCHDOG_ERROR);
        return FALSE;
      }
    }
  }

  /*
   if ($from == NULL || $from == '') {
     if (variable_get('smtp_from', '') != '') {
       $from = variable_get('smtp_from', '');
     }
     else {
       // If smtp_from config option is blank, use site_mail.
       $from = variable_get('site_mail', '');
     }
   }
  */
  if (preg_match('/^"?.*"?\\s*<.*>$/', $from)) {

    // . == Matches any single character except line break characters \r and \n.
    // * == Repeats the previous item zero or more times.
    $from_name = preg_replace('/("([^"]*)")|(([^("\\s)]*))\\s*\\<.*\\>$/', '$2$4', $from);

    // It gives: Name
    $from = preg_replace("/(.*)\\<(.*)\\>/i", '$2', $from);

    // It gives: name@domain.tld
  }
  elseif (!valid_email_address($from)) {
    drupal_set_message(t('The submitted from address (@from) is not valid.', array(
      '@from' => $from,
    )), 'error');
    watchdog('smtp', 'The submitted from address (@from) is not valid.', array(
      '@from' => $from,
    ), WATCHDOG_ERROR);
    return FALSE;
  }

  // Defines the From value to what we expect.
  $mail->From = $from;
  $mail->FromName = $from_name;
  $mail->Sender = $from;

  // Create the list of 'To:' recipients.
  $torecipients = explode(',', $to);
  foreach ($torecipients as $torecipient) {
    if (strpos($torecipient, '<') !== FALSE) {
      $toparts = explode(' <', $torecipient);
      $toname = $toparts[0];
      $toaddr = rtrim($toparts[1], '>');
    }
    else {
      $toname = '';
      $toaddr = $torecipient;
    }
    $mail
      ->AddAddress($toaddr, $toname);
  }

  // Parse the headers of the message and set the PHPMailer object's settings
  // accordingly.
  foreach ($headers as $key => $value) {

    //watchdog('error', 'Key: ' . $key . ' Value: ' . $value);
    switch (drupal_strtolower($key)) {
      case 'from':
        if ($from == NULL or $from == '') {

          // If a from value was already given, then set based on header.
          // Should be the most common situation since drupal_mail moves the
          // from to headers.
          $from = $value;
          $mail->From = $value;

          // then from can be out of sync with from_name !
          $mail->FromName = '';
          $mail->Sender = $value;
        }
        break;
      case 'content-type':

        // Parse several values on the Content-type header, storing them in an array like
        // key=value -> $vars['key']='value'
        $vars = preg_split('/;[\\s]*/', $value);
        foreach ($vars as $i => $var) {
          if ($cut = strpos($var, '=')) {
            $new_var = drupal_strtolower(drupal_substr($var, $cut + 1));
            $new_key = drupal_substr($var, 0, $cut);
            unset($vars[$i]);
            $vars[$new_key] = $new_var;
          }
        }

        // Set the charset based on the provided value, otherwise set it to UTF-8 (which is Drupals internal default).
        $mail->CharSet = isset($vars['charset']) ? $vars['charset'] : 'UTF-8';
        switch ($vars[0]) {
          case 'text/plain':

            // The message includes only a plain text part.
            $mail
              ->IsHTML(FALSE);
            $content_type = 'text/plain';
            break;
          case 'text/html':

            // The message includes only an HTML part.
            $mail
              ->IsHTML(TRUE);
            $content_type = 'text/html';
            break;
          case 'multipart/related':

            // Get the boundary ID from the Content-Type header.
            $boundary = _smtp_get_substring($value, 'boundary', '"', '"');

            // The message includes an HTML part w/inline attachments.
            $mail->ContentType = $content_type = 'multipart/related; boundary="' . $boundary . '"';
            break;
          case 'multipart/alternative':

            // The message includes both a plain text and an HTML part.
            $mail->ContentType = $content_type = 'multipart/alternative';

            // Get the boundary ID from the Content-Type header.
            $boundary = _smtp_get_substring($value, 'boundary', '"', '"');
            break;
          case 'multipart/mixed':

            // The message includes one or more attachments.
            $mail->ContentType = $content_type = 'multipart/mixed';

            // Get the boundary ID from the Content-Type header.
            $boundary = _smtp_get_substring($value, 'boundary', '"', '"');
            break;
          default:

            // Everything else is unsuppored by PHPMailer.
            drupal_set_message(t('The Content-Type of your message is not supported by PHPMailer and will be sent as text/plain instead.'), 'error');
            watchdog('smtp', 'The Content-Type of your message is not supported by PHPMailer and will be sent as text/plain instead.', array(), WATCHDOG_ERROR);

            // Force the Content-Type to be text/plain.
            $mail
              ->IsHTML(FALSE);
            $content_type = 'text/plain';
        }
        break;
      case 'reply-to':

        // Only add a "reply-to" if it's not the same as "return-path".
        if ($value != $headers['Return-Path']) {
          if (strpos($value, '<') !== FALSE) {
            $replyToParts = explode('<', $value);
            $replyToName = trim($replyToParts[0]);
            $replyToName = trim($replyToName, '"');
            $replyToAddr = rtrim($replyToParts[1], '>');
            $mail
              ->AddReplyTo($replyToAddr, $replyToName);
          }
          else {
            $mail
              ->AddReplyTo($value);
          }
        }
        break;
      case 'content-transfer-encoding':
        $mail->Encoding = $value;
        break;
      case 'return-path':
      case 'mime-version':
      case 'x-mailer':

        // Let PHPMailer specify these.
        break;
      case 'errors-to':
        $mail
          ->AddCustomHeader('Errors-To: ' . $value);
        break;
      case 'cc':
        $ccrecipients = explode(',', $value);
        foreach ($ccrecipients as $ccrecipient) {
          if (strpos($ccrecipient, '<') !== FALSE) {
            $ccparts = explode(' <', $ccrecipient);
            $ccname = $ccparts[0];
            $ccaddr = rtrim($ccparts[1], '>');
          }
          else {
            $ccname = '';
            $ccaddr = $ccrecipient;
          }
          $mail
            ->AddCC($ccaddr, $ccname);
        }
        break;
      case 'bcc':
        $bccrecipients = explode(',', $value);
        foreach ($bccrecipients as $bccrecipient) {
          if (strpos($bccrecipient, '<') !== FALSE) {
            $bccparts = explode(' <', $bccrecipient);
            $bccname = $bccparts[0];
            $bccaddr = rtrim($bccparts[1], '>');
          }
          else {
            $bccname = '';
            $bccaddr = $bccrecipient;
          }
          $mail
            ->AddBCC($bccaddr, $bccname);
        }
        break;
      default:

        // The header key is not special - add it as is.
        $mail
          ->AddCustomHeader($key . ': ' . $value);
    }
  }

  /**
  * TODO
  * Need to figure out the following.

   // Add one last header item, but not if it has already been added.
   $errors_to = FALSE;
   foreach ($mail->CustomHeader as $custom_header) {
     if ($custom_header[0] = '') {
       $errors_to = TRUE;
     }
   }
   if ($errors_to) {
     $mail->AddCustomHeader('Errors-To: '. $from);
   }
  */

  // Add the message's subject.
  $mail->Subject = $subject;

  // Processes the message's body.
  switch ($content_type) {
    case 'multipart/related':
      $mail->Body = $body;

      /**
       * TODO
       * Firgure out if there is anything more to handling this type.
       */
      break;
    case 'multipart/alternative':

      // Split the body based on the boundary ID.
      $body_parts = _smtp_boundary_split($body, $boundary);
      foreach ($body_parts as $body_part) {

        // If plain/text within the body part, add it to $mail->AltBody.
        if (strpos($body_part, 'text/plain')) {

          // Clean up the text.
          $body_part = trim(_smtp_remove_headers(trim($body_part)));

          // Include it as part of the mail object.
          $mail->AltBody = $body_part;
        }
        elseif (strpos($body_part, 'text/html')) {

          // Clean up the text.
          $body_part = trim(_smtp_remove_headers(trim($body_part)));

          // Include it as part of the mail object.
          $mail->Body = $body_part;
        }
      }
      break;
    case 'multipart/mixed':

      // Split the body based on the boundary ID.
      $body_parts = _smtp_boundary_split($body, $boundary);

      // Determine if there is an HTML part for when adding the plain text part.
      $text_plain = FALSE;
      $text_html = FALSE;
      foreach ($body_parts as $body_part) {
        if (strpos($body_part, 'text/plain')) {
          $text_plain = TRUE;
        }
        if (strpos($body_part, 'text/html')) {
          $text_html = TRUE;
        }
      }
      foreach ($body_parts as $body_part) {

        // If test/plain within the body part, add it to either
        // $mail->AltBody or $mail->Body, depending on whether there is
        // also a text/html part ot not.
        if (strpos($body_part, 'multipart/alternative')) {

          // Get boundary ID from the Content-Type header.
          $boundary2 = _smtp_get_substring($body_part, 'boundary', '"', '"');

          // Clean up the text.
          $body_part = trim(_smtp_remove_headers(trim($body_part)));

          // Split the body based on the boundary ID.
          $body_parts2 = _smtp_boundary_split($body_part, $boundary2);
          foreach ($body_parts2 as $body_part2) {

            // If plain/text within the body part, add it to $mail->AltBody.
            if (strpos($body_part2, 'text/plain')) {

              // Clean up the text.
              $body_part2 = trim(_smtp_remove_headers(trim($body_part2)));

              // Include it as part of the mail object.
              $mail->AltBody = $body_part2;
              $mail->ContentType = 'multipart/mixed';
            }
            elseif (strpos($body_part2, 'text/html')) {

              // Clean up the text.
              $body_part2 = trim(_smtp_remove_headers(trim($body_part2)));

              // Include it as part of the mail object.
              $mail->Body = $body_part2;
              $mail->ContentType = 'multipart/mixed';
            }
          }
        }
        elseif (strpos($body_part, 'text/plain')) {

          // Clean up the text.
          $body_part = trim(_smtp_remove_headers(trim($body_part)));
          if ($text_html) {
            $mail->AltBody = $body_part;
            $mail
              ->IsHTML(TRUE);
            $mail->ContentType = 'multipart/mixed';
          }
          else {
            $mail->Body = $body_part;
            $mail
              ->IsHTML(FALSE);
            $mail->ContentType = 'multipart/mixed';
          }
        }
        elseif (strpos($body_part, 'text/html')) {

          // Clean up the text.
          $body_part = trim(_smtp_remove_headers(trim($body_part)));

          // Include it as part of the mail object.
          $mail->Body = $body_part;
          $mail
            ->IsHTML(TRUE);
          $mail->ContentType = 'multipart/mixed';
        }
        elseif (strpos($body_part, 'Content-Disposition: attachment;')) {
          $file_path = _smtp_get_substring($body_part, 'filename=', '"', '"');
          $file_name = _smtp_get_substring($body_part, ' name=', '"', '"');
          $file_encoding = _smtp_get_substring($body_part, 'Content-Transfer-Encoding', ' ', "\n");
          $file_type = _smtp_get_substring($body_part, 'Content-Type', ' ', ';');
          if (file_exists($file_path)) {
            if (!$mail
              ->AddAttachment($file_path, $file_name, $file_encoding, $filetype)) {
              drupal_set_message(t('Attahment could not be found or accessed.'));
            }
          }
          else {

            // Clean up the text.
            $body_part = trim(_smtp_remove_headers(trim($body_part)));
            if (drupal_strtolower($file_encoding) == 'base64') {
              $attachment = base64_decode($body_part);
            }
            elseif (drupal_strtolower($file_encoding) == 'quoted-printable') {
              $attachment = quoted_printable_decode($body_part);
            }
            else {
              $attachment = $body_part;
            }
            $attachment_new_filename = tempnam(realpath(file_directory_temp()), 'smtp');
            $file_path = file_save_data($attachment, $attachment_new_filename, FILE_EXISTS_RENAME);
            if (!$mail
              ->AddAttachment($file_path, $file_name)) {

              // , $file_encoding, $filetype);
              drupal_set_message(t('Attachment could not be found or accessed.'));
            }
          }
        }
      }
      break;
    default:
      $mail->Body = $body;
      break;
  }

  // Set the authentication settings.
  $username = variable_get('smtp_username', '');
  $password = variable_get('smtp_password', '');

  // If username and password are given, use SMTP authentication.
  if ($username != '' && $password != '') {
    $mail->SMTPAuth = TRUE;
    $mail->Username = $username;
    $mail->Password = $password;
  }

  // Set the protocol prefix for the smtp host.
  switch (variable_get('smtp_protocol', 'standard')) {
    case 'ssl':
      $mail->SMTPSecure = 'ssl';
      break;
    case 'tls':
      $mail->SMTPSecure = 'tls';
      break;
    default:
      $mail->SMTPSecure = '';
  }

  // Set other connection settings.
  $mail->Host = variable_get('smtp_host', '') . ';' . variable_get('smtp_hostbackup', '');
  $mail->Port = variable_get('smtp_port', '25');
  $mail->Mailer = 'smtp';

  // Try to queue e-mail.
  if (function_exists('job_queue_add')) {
    watchdog('smtp', 'Queueing mail to: @to', array(
      '@to' => $to,
    ));
    job_queue_add('smtp_mail_send', t('Queued email'), array(
      $mail,
    ), drupal_get_path('module', 'smtp') . '/phpmailer/class.phpmailer.php');
  }
  else {
    watchdog('smtp', 'Sending mail to: @to', array(
      '@to' => $to,
    ));
    if (!$mail
      ->Send()) {
      watchdog('smtp', 'Error sending e-mail from @from to @to : !error_message', array(
        '@from' => $from,
        '@to' => $to,
        '!error_message' => $mail->ErrorInfo,
      ), WATCHDOG_ERROR);
      return FALSE;
    }
    $mail
      ->SmtpClose();
  }
  return TRUE;
}