You are here

class SmtpMailSystem in SMTP Authentication Support 7

Same name and namespace in other branches
  1. 7.2 smtp.mail.inc \SmtpMailSystem

Modify the drupal mail system to use smtp when sending emails. Include the option to choose between plain text or HTML

Hierarchy

Expanded class hierarchy of SmtpMailSystem

5 string references to 'SmtpMailSystem'
SmtpUnitTest::setUp in tests/smtp.unit.test
Sets up a Drupal site for running functional and integration tests.
SmtpUnitTest::testSetup in tests/smtp.unit.test
Confirm that SMTP has taken over the 'mail_system' variable.
smtp_admin_settings_form_submit in ./smtp.admin.inc
Submit handler().
smtp_update_7000 in ./smtp.install
Upgrade to Drupal 7.x
smtp_update_7100 in ./smtp.install
Back to default mail system if the status flag is off.

File

./smtp.mail.inc, line 12
The code processing mail in the smtp module.

View source
class SmtpMailSystem implements MailSystemInterface {
  protected $AllowHtml;

  /**
   * Concatenate and wrap the e-mail body for either
   * plain-text or HTML emails.
   *
   * @param $message
   *   A message array, as described in hook_mail_alter().
   *
   * @return
   *   The formatted $message.
   */
  public function format(array $message) {
    $this->AllowHtml = variable_get('smtp_allowhtml', 0);

    // Join the body array into one string.
    $message['body'] = implode("\n\n", $message['body']);
    if ($this->AllowHtml == 0) {

      // Convert any HTML to plain-text.
      $message['body'] = drupal_html_to_text($message['body']);

      // Wrap the mail body for sending.
      $message['body'] = drupal_wrap_mail($message['body']);
    }
    return $message;
  }

  /**
   * Send the e-mail message.
   *
   * @see drupal_mail()
   *
   * @param $message
   *   A message array, as described in hook_mail_alter().
   * @return
   *   TRUE if the mail was successfully accepted, otherwise FALSE.
   */
  public function mail(array $message) {
    if (variable_get('smtp_queue', FALSE) && (!isset($message['params']['skip_queue']) || !$message['params']['skip_queue'])) {
      smtp_send_queue($message);
      if (variable_get('smtp_debugging', SMTP_LOGGING_ERRORS) == SMTP_LOGGING_ALL) {
        watchdog('smtp', 'Queue sending mail to: @to', array(
          '@to' => $message['to'],
        ));
      }
      return TRUE;
    }
    else {
      return $this
        ->mailWithoutQueue($message);
    }
  }
  public function mailWithoutQueue(array $message) {
    $to = $message['to'];
    $from = $message['from'];
    $from_name = isset($message['from_name']) ? $message['from_name'] : FALSE;
    $body = $message['body'];
    $headers = $message['headers'];
    $subject = $message['subject'];

    // Optionally reroute all emails to a single address.
    $reroute_address = variable_get('smtp_reroute_address', '');
    if (!empty($reroute_address)) {
      $to = $reroute_address;

      // Remove any CC and BCC headers that might have been set.
      unset($headers['cc']);
      unset($headers['bcc']);
    }

    // Create a new PHPMailer object - autoloaded from registry.
    $mailer = new PHPMailer();
    $logging = variable_get('smtp_debugging', SMTP_LOGGING_ERRORS);

    // Turn on debugging, if requested.
    if ($logging == SMTP_LOGGING_ALL && user_access('administer smtp module')) {
      $mailer->SMTPDebug = TRUE;
    }

    // Set the from name. First we try to get the name from i18n, in the case
    // that it has been translated. The name is set according to the language
    // of the email being sent.
    if (empty($from_name)) {
      if (function_exists('i18n_variable_get')) {

        // The 'language' value may be stored as an object.
        $langcode = $message['language'];
        if (is_object($langcode)) {
          $langcode = $langcode->language;
        }
        if (i18n_variable_get('smtp_fromname', $langcode, '') != '') {
          $from_name = i18n_variable_get('smtp_fromname', $langcode, '');
        }
        else {
          $from_name = i18n_variable_get('site_name', $langcode, '');
        }
      }
      else {
        if (variable_get('smtp_fromname', '') != '') {
          $from_name = variable_get('smtp_fromname', '');
        }
        else {
          $from_name = variable_get('site_name', '');
        }
      }
    }
    if (variable_get('smtp_client_hostname', '') != '') {
      $mailer->Hostname = variable_get('smtp_client_hostname', '');
    }
    if (variable_get('smtp_client_helo', '') != '') {
      $mailer->Helo = variable_get('smtp_client_helo', '');
    }

    //Hack to fix reply-to issue.
    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;
    }
    $properfrom = variable_get('smtp_from', '');
    if (!empty($properfrom)) {
      $headers['From'] = $properfrom;
      $from = $properfrom;
    }
    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_email.
        if (($from = variable_get('site_mail', '')) == '') {
          drupal_set_message(t('There is no submitted from address.'), 'error');
          if ($logging) {
            watchdog('smtp', 'There is no submitted from address.', array(), WATCHDOG_ERROR);
          }
          return FALSE;
        }
      }
    }
    $from_comp = $this
      ->_get_components($from);
    if (!valid_email_address($from_comp['email'])) {
      drupal_set_message(t('The submitted from address (@from) is not valid.', array(
        '@from' => $from_comp['email'],
      )), 'error');
      if ($logging) {
        watchdog('smtp', 'The submitted from address (@from) is not valid.', array(
          '@from' => $from_comp['email'],
        ), WATCHDOG_ERROR);
      }
      return FALSE;
    }

    // Defines the From value to what we expect.
    $mailer->From = $from_comp['email'];
    $mailer->FromName = empty($from_comp['name']) ? $from_name : $from_comp['name'];
    $mailer->Sender = $from_comp['email'];

    // Create the list of 'To:' recipients.
    $torecipients = explode(',', $to);
    foreach ($torecipients as $torecipient) {
      $to_comp = $this
        ->_get_components($torecipient);
      $mailer
        ->AddAddress($to_comp['email'], $to_comp['name']);
    }

    // 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;
            $mailer->From = $value;

            // then from can be out of sync with from_name !
            $mailer->FromName = '';
            $mailer->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 = explode(';', $value);
          foreach ($vars as $i => $var) {
            if ($cut = strpos($var, '=')) {
              $new_var = trim(drupal_strtolower(drupal_substr($var, $cut + 1)));
              $new_key = trim(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).
          $mailer->CharSet = isset($vars['charset']) ? $vars['charset'] : 'UTF-8';

          // If $vars is empty then set an empty value at index 0 to avoid a PHP warning in the next statement
          $vars[0] = isset($vars[0]) ? $vars[0] : '';
          switch ($vars[0]) {
            case 'text/plain':

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

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

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

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

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

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

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

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

              // Everything else is unsuppored by PHPMailer.
              drupal_set_message(t('The %header of your message is not supported by PHPMailer and will be sent as text/plain instead.', array(
                '%header' => "Content-Type: {$value}",
              )), 'error');
              if ($logging) {
                watchdog('smtp', 'The %header of your message is not supported by PHPMailer and will be sent as text/plain instead.', array(
                  '%header' => "Content-Type: {$value}",
                ), WATCHDOG_ERROR);
              }

              // Force the Content-Type to be text/plain.
              $mailer
                ->IsHTML(FALSE);
              $content_type = 'text/plain';
          }
          break;
        case 'reply-to':
          $replyto_comp = $this
            ->_get_components($value);
          $mailer
            ->AddReplyTo($replyto_comp['email'], $replyto_comp['name']);
          break;
        case 'content-transfer-encoding':
          $mailer->Encoding = $value;
          break;
        case 'return-path':
          $returnpath_comp = $this
            ->_get_components($value);
          $mailer->Sender = $returnpath_comp['email'];
          break;
        case 'mime-version':
        case 'x-mailer':

          // Let PHPMailer specify these.
          break;
        case 'errors-to':
          $mailer
            ->AddCustomHeader('Errors-To: ' . $value);
          break;
        case 'cc':
          $ccrecipients = explode(',', $value);
          foreach ($ccrecipients as $ccrecipient) {
            $cc_comp = $this
              ->_get_components($ccrecipient);
            $mailer
              ->AddCC($cc_comp['email'], $cc_comp['name']);
          }
          break;
        case 'bcc':
          $bccrecipients = explode(',', $value);
          foreach ($bccrecipients as $bccrecipient) {
            $bcc_comp = $this
              ->_get_components($bccrecipient);
            $mailer
              ->AddBCC($bcc_comp['email'], $bcc_comp['name']);
          }
          break;
        case 'message-id':
          $mailer->MessageID = $value;
          break;
        default:

          // The header key is not special - add it as is.
          $mailer
            ->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 ($mailer->CustomHeader as $custom_header) {
     *   if ($custom_header[0] = '') {
     *     $errors_to = TRUE;
     *   }
     * }
     * if ($errors_to) {
     *   $mailer->AddCustomHeader('Errors-To: '. $from);
     * }
     */

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

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

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

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

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

            // Clean up the text.
            $body_part = trim($this
              ->_remove_headers(trim($body_part)));

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

            // Clean up the text.
            $body_part = trim($this
              ->_remove_headers(trim($body_part)));

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

        // Split the body based on the boundary ID.
        $body_parts = $this
          ->_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
          // $mailer->AltBody or $mailer->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 = $this
              ->_get_substring($body_part, 'boundary', '"', '"');

            // Clean up the text.
            $body_part = trim($this
              ->_remove_headers(trim($body_part)));

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

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

                // Clean up the text.
                $body_part2 = trim($this
                  ->_remove_headers(trim($body_part2)));

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

                // Get the encoding.
                $body_part2_encoding = trim($this
                  ->_get_substring($body_part2, 'Content-Transfer-Encoding', ':', "\n"));

                // Clean up the text.
                $body_part2 = trim($this
                  ->_remove_headers(trim($body_part2)));

                // Check whether the encoding is base64, and if so, decode it.
                if (drupal_strtolower($body_part2_encoding) == 'base64') {

                  // Include it as part of the mail object.
                  $mailer->Body = base64_decode($body_part2);

                  // Ensure the whole message is recoded in the base64 format.
                  $mailer->Encoding = 'base64';
                }
                else {

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

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

            // Clean up the text.
            $body_part = trim($this
              ->_remove_headers(trim($body_part)));

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

              // Clean up the text.
              $body_part = trim($this
                ->_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 = drupal_tempnam('temporary://', 'smtp');
              $file_path = file_save_data($attachment, $attachment_new_filename, FILE_EXISTS_REPLACE);
              $real_path = drupal_realpath($file_path->uri);
              if (!$mailer
                ->AddAttachment($real_path, $file_name)) {
                drupal_set_message(t('Attachment could not be found or accessed.'));
              }
            }
          }
        }
        break;
      default:
        $mailer->Body = $body;
        break;
    }

    // Process mimemail attachments, which are prepared in mimemail_mail().
    if (isset($message['params']['attachments'])) {
      foreach ($message['params']['attachments'] as $attachment) {
        if (isset($attachment['filecontent'])) {
          $mailer
            ->AddStringAttachment($attachment['filecontent'], $attachment['filename'], 'base64', $attachment['filemime']);
        }
        if (!isset($attachment['filepath']) && isset($attachment['uri'])) {
          $attachment['filepath'] = $attachment['uri'];
        }
        if (isset($attachment['filepath'])) {
          $filename = isset($attachment['filename']) ? $attachment['filename'] : basename($attachment['filepath']);
          $filemime = isset($attachment['filemime']) ? $attachment['filemime'] : file_get_mimetype($attachment['filepath']);
          $mailer
            ->AddAttachment($attachment['filepath'], $filename, 'base64', $filemime);
        }
      }
    }

    // Process inline images.
    if (!empty($message['params']['images'])) {
      foreach ($message['params']['images'] as $image) {
        if (!empty($image['filepath']) && !empty($image['cid'])) {
          if (file_exists($image['filepath'])) {
            $image_extension = pathinfo($image['filepath'], PATHINFO_EXTENSION);
            $image_mime_type = PHPMailer::_mime_types($image_extension);
            if (empty($image['name'])) {
              $image_name = pathinfo($image['filepath'], PATHINFO_FILENAME);
            }
            else {
              $image_name = $image['name'];
            }
            $mailer
              ->AddEmbeddedImage($image['filepath'], $image['cid'], $image_name, 'base64', $image_mime_type);
          }
        }
      }
    }

    // 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 != '') {
      $mailer->SMTPAuth = TRUE;
      $mailer->Username = $username;
      $mailer->Password = $password;
    }

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

    // Set SSL stream context options
    if (variable_get('smtp_protocol', 'standard') != 'standard') {
      $smtp_allow_self_signed = array(
        'allow_self_signed' => variable_get('smtp_allow_self_signed', FALSE),
      );
      if (version_compare(phpversion(), '5.6.0', '>=')) {
        $smtp_verify_peer = array(
          'verify_peer' => variable_get('smtp_verify_peer', TRUE),
        );
        $smtp_verify_peer_name = array(
          'verify_peer_name' => variable_get('smtp_verify_peer_name', TRUE),
        );
        $mailer->SMTPOptions = array(
          'ssl' => array_merge($smtp_verify_peer, $smtp_verify_peer_name, $smtp_allow_self_signed),
        );
      }
      else {
        $smtp_verify_peer = array(
          'verify_peer' => variable_get('smtp_verify_peer', FALSE),
        );
        $mailer->SMTPOptions = array(
          'ssl' => array_merge($smtp_verify_peer, $smtp_allow_self_signed),
        );
      }
    }

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

    // Integration with the Maillog module.
    if (module_exists('maillog')) {
      if (variable_get('maillog_log', TRUE)) {
        $record = new stdClass();

        // In case the subject/from/to is already encoded, decode with
        // mime_header_decode.
        $record->header_message_id = isset($mailer->MessageID) ? $mailer->MessageID : NULL;
        $record->subject = drupal_substr(mime_header_decode($mailer->Subject), 0, 255);
        $record->header_from = $from;
        $record->header_to = $to;
        $record->header_reply_to = isset($headers['Reply-To']) ? $headers['Reply-To'] : '';
        $record->header_all = serialize($headers);
        $record->sent_date = REQUEST_TIME;

        // Used to separate different portions of the body string.
        $divider = str_repeat('-', 60) . "\n";

        // Load the attachments.
        $attachments = $mailer
          ->GetAttachments();
        $record->body = '';

        // If there's more than one item to display, add a divider.
        if (!empty($mailer->AltBody) || !empty($attachments)) {
          $record->body .= t('Body') . ":\n";
          $record->body .= $divider;
        }

        // Add the body field.
        if (isset($mailer->Body)) {
          $record->body .= $mailer->Body;
        }
        else {
          $record->body .= t('*No message body*') . ":\n";
        }

        // The AltBody value is optional.
        if (!empty($mailer->AltBody)) {
          $record->body .= "\n";
          $record->body .= $divider;
          $record->body .= t('Alternative body') . ":\n";
          $record->body .= $divider;
          $record->body .= $mailer->AltBody;
        }

        // List the attachments.
        if (!empty($attachments)) {
          $record->body .= "\n";
          $record->body .= $divider;
          $record->body .= t('Attachments') . ":\n";
          $record->body .= $divider;
          foreach ($attachments as $file) {
            $record->body .= t('Filename') . ':' . $file[1] . "\n";
            $record->body .= t('Name') . ':' . $file[2] . "\n";
            $record->body .= t('Encoding') . ':' . $file[3] . "\n";
            $record->body .= t('Type') . ':' . $file[4] . "\n";
            $record->body .= "\n";
          }
        }
        drupal_write_record('maillog', $record);
      }

      // Display the e-mail using Devel module.
      if (variable_get('maillog_devel', TRUE) && function_exists('dpm')) {
        $devel_msg = array();
        $devel_msg[t('Subject')] = $mailer->Subject;
        $devel_msg[t('From')] = $from;
        $devel_msg[t('To')] = $to;
        $devel_msg[t('Reply-To')] = isset($headers['Reply-To']) ? $headers['Reply-To'] : NULL;
        $devel_msg[t('Headers')] = $headers;
        $devel_msg[t('Body')] = $mailer->Body;
        $devel_msg[t('Alternative body')] = $mailer->AltBody;
        $devel_msg[t('Attachments')] = $mailer
          ->GetAttachments();
        dpm($devel_msg, 'maillog');
      }
    }
    $error = FALSE;

    // Email delivery was disabled.
    if (!variable_get('smtp_deliver', TRUE)) {
      if ($logging) {
        $params = array(
          '@from' => $from,
          '@to' => $to,
        );
        watchdog('smtp', 'Email delivery is disabled, did not send email from @from to @to.', $params);
      }
    }
    else {
      if (!$mailer
        ->send()) {
        $params = array(
          '@from' => $from,
          '@to' => $to,
          '!error_message' => $mailer->ErrorInfo,
        );
        if (variable_get('smtp_queue_fail', FALSE)) {
          if ($logging) {
            watchdog('smtp', 'Error sending e-mail from @from to @to, will retry on cron run : !error_message.', $params, WATCHDOG_ERROR);
          }
          smtp_failed_messages($message);
        }
        elseif ($logging) {
          $error = TRUE;
          watchdog('smtp', 'Error sending e-mail from @from to @to : !error_message', $params, WATCHDOG_ERROR);
        }
      }
      elseif (variable_get('smtp_debugging', SMTP_LOGGING_ERRORS) == SMTP_LOGGING_ALL) {
        watchdog('smtp', 'Sent mail to: @to', array(
          '@to' => $to,
        ));
      }
    }
    $mailer
      ->SmtpClose();
    return !$error;
  }

  /**
   * Splits the input into parts based on the given boundary.
   *
   * Swiped from Mail::MimeDecode, with modifications based on Drupal's coding
   * standards and this bug report: http://pear.php.net/bugs/bug.php?id=6495
   *
   * @param input
   *   A string containing the body text to parse.
   * @param boundary
   *   A string with the boundary string to parse on.
   * @return
   *   An array containing the resulting mime parts
   */
  protected function _boundary_split($input, $boundary) {
    $parts = array();
    $bs_possible = drupal_substr($boundary, 2, -2);
    $bs_check = '\\"' . $bs_possible . '\\"';
    if ($boundary == $bs_check) {
      $boundary = $bs_possible;
    }
    $tmp = explode('--' . $boundary, $input);
    for ($i = 1; $i < count($tmp); $i++) {
      if (trim($tmp[$i])) {
        $parts[] = $tmp[$i];
      }
    }
    return $parts;
  }

  //  End of _smtp_boundary_split().

  /**
   * Strips the headers from the body part.
   *
   * @param input
   *   A string containing the body part to strip.
   * @return
   *   A string with the stripped body part.
   */
  protected function _remove_headers($input) {
    $part_array = explode("\n", $input);

    // will strip these headers according to RFC2045
    $headers_to_strip = array(
      'Content-Type',
      'Content-Transfer-Encoding',
      'Content-ID',
      'Content-Disposition',
    );
    $pattern = '/^(' . implode('|', $headers_to_strip) . '):/';
    while (count($part_array) > 0) {

      // ignore trailing spaces/newlines
      $line = rtrim($part_array[0]);

      // if the line starts with a known header string
      if (preg_match($pattern, $line)) {
        $line = rtrim(array_shift($part_array));

        // remove line containing matched header.
        // if line ends in a ';' and the next line starts with four spaces, it's a continuation
        // of the header split onto the next line. Continue removing lines while we have this condition.
        while (substr($line, -1) == ';' && count($part_array) > 0 && substr($part_array[0], 0, 4) == '    ') {
          $line = rtrim(array_shift($part_array));
        }
      }
      else {

        // no match header, must be past headers; stop searching.
        break;
      }
    }
    $output = implode("\n", $part_array);
    return $output;
  }

  //  End of _smtp_remove_headers().

  /**
   * Returns a string that is contained within another string.
   *
   * Returns the string from within $source that is some where after $target
   * and is between $beginning_character and $ending_character.
   *
   * @param $source
   *   A string containing the text to look through.
   * @param $target
   *   A string containing the text in $source to start looking from.
   * @param $beginning_character
   *   A string containing the character just before the sought after text.
   * @param $ending_character
   *   A string containing the character just after the sought after text.
   * @return
   *   A string with the text found between the $beginning_character and the
   *   $ending_character.
   */
  protected function _get_substring($source, $target, $beginning_character, $ending_character) {
    $search_start = strpos($source, $target) + 1;
    $first_character = strpos($source, $beginning_character, $search_start) + 1;
    $second_character = strpos($source, $ending_character, $first_character) + 1;
    $substring = drupal_substr($source, $first_character, $second_character - $first_character);
    $string_length = drupal_strlen($substring) - 1;
    if ($substring[$string_length] == $ending_character) {
      $substring = drupal_substr($substring, 0, $string_length);
    }
    return trim($substring);
  }

  //  End of _smtp_get_substring().

  /**
   * Returns an array of name and email address from a string.
   *
   * @param $input
   *  A string that contains different possible combinations of names and
   *  email address.
   * @return
   *  An array containing a name and an email address.
   */
  protected function _get_components($input) {
    $input = trim($input);
    $components = array(
      'input' => $input,
      'name' => '',
      'email' => '',
    );

    // If the input is a valid email address in its entirety, then there is
    // nothing to do, just return that.
    if (valid_email_address($input)) {
      $components['email'] = $input;
      return $components;
    }

    // Check if $input has one of the following formats, extract what we can:
    //  some name <address@example.com>
    //  "another name" <address@example.com>
    //  <address@example.com>
    if (preg_match('/^"?([^"\\t\\n]*)"?\\s*<([^>\\t\\n]*)>$/', $input, $matches)) {
      $components['name'] = trim($matches[1]);
      $components['email'] = trim($matches[2]);
    }
    return $components;
  }

}

Members

Namesort descending Modifiers Type Description Overrides
SmtpMailSystem::$AllowHtml protected property
SmtpMailSystem::format public function Concatenate and wrap the e-mail body for either plain-text or HTML emails. Overrides MailSystemInterface::format
SmtpMailSystem::mail public function Send the e-mail message. Overrides MailSystemInterface::mail
SmtpMailSystem::mailWithoutQueue public function
SmtpMailSystem::_boundary_split protected function Splits the input into parts based on the given boundary.
SmtpMailSystem::_get_components protected function Returns an array of name and email address from a string.
SmtpMailSystem::_get_substring protected function Returns a string that is contained within another string.
SmtpMailSystem::_remove_headers protected function Strips the headers from the body part.