Procházet zdrojové kódy

security update for smtp module

Bachir Soussi Chiadmi před 7 roky
rodič
revize
ed483507e5

+ 3 - 1
sites/all/modules/contrib/mail/smtp/README.txt

@@ -1,4 +1,3 @@
-
 SMTP Authentication Support module for Drupal 7.x.
 This module adds SMTP functionality to Drupal.
 
@@ -41,3 +40,6 @@ extension is working.  If the SMTP module detects openssl is available it
 will display the options in the modules settings page.
 
 Sending mail to Gmail requires SSL or TLS.
+
+If the Maillog module (https://www.drupal.org/project/maillog) is installed, it
+can be used to keep copies of all messages sent through the site.

+ 127 - 66
sites/all/modules/contrib/mail/smtp/smtp.admin.inc

@@ -3,41 +3,21 @@
 /**
  * @file
  * Administrative page code for the smtp module.
- *
  */
 
-
 /**
  * Administrative settings.
- *
- * @return
- *   An array containing form items to place on the module settings page.
  */
 function smtp_admin_settings() {
-  // Override the smtp_library variable.
-  if (module_exists('mimemail') &&
-      strpos(variable_get('smtp_library', ''), 'mimemail')) {
-    // don't touch smtp_library
+  if (variable_get('smtp_on', 0)) {
+    drupal_set_message(t('SMTP.module is active.'));
   }
   else {
-    if (variable_get('smtp_on', 0)) {
-      $smtp_path = drupal_get_filename('module', 'smtp');
-      if ($smtp_path) {
-        variable_set('smtp_library', $smtp_path);
-        drupal_set_message(t('SMTP.module is active.'));
-      }
-      // If drupal can't find the path to the module, display an error.
-      else {
-        drupal_set_message(t("SMTP.module error: Can't find file."), 'error');
-      }
-    }
-    // If this module is turned off, delete the variable.
-    else {
-      variable_del('smtp_library');
-      drupal_set_message(t('SMTP.module is INACTIVE.'));
-    }
+    drupal_set_message(t('SMTP.module is INACTIVE.'));
   }
 
+  $logging = variable_get('smtp_debugging', SMTP_LOGGING_ERRORS);
+
   $form['onoff'] = array(
     '#type'  => 'fieldset',
     '#title' => t('Install options'),
@@ -45,16 +25,29 @@ function smtp_admin_settings() {
   $form['onoff']['smtp_on'] = array(
     '#type'          => 'radios',
     '#title'         => t('Turn this module on or off'),
-    '#default_value' => variable_get('smtp_on', 0),
+    '#default_value' => variable_get('smtp_on', FALSE),
     '#options'       => array(1 => t('On'), 0 => t('Off')),
     '#description'   => t('To uninstall this module you must turn it off here first.'),
   );
+  $form['onoff']['smtp_deliver'] = array(
+    '#type'          => 'radios',
+    '#title'         => t('Turn on delivery of emails'),
+    '#default_value' => variable_get('smtp_deliver', TRUE),
+    '#options'       => array(1 => t('On'), 0 => t('Off')),
+    '#description'   => t('With this option turned off, email messages will be queued up and processed as normal, but not actually delivered. This option should only be used for testing purposes.'),
+  );
   $form['onoff']['smtp_queue'] = array(
     '#type'  => 'checkbox',
     '#title' => t('Send mail by queue'),
     '#default_value' => variable_get('smtp_queue', FALSE),
     '#description'   => t('Mails will be sent by drupal queue api.'),
   );
+  $form['onoff']['smtp_queue_fail'] = array(
+    '#type'  => 'checkbox',
+    '#title' => t('Retry sending mail on error.'),
+    '#default_value' => variable_get('smtp_queue_fail', FALSE),
+    '#description'   => t('Mails will be added to the queue and sent by drupal queue api.'),
+  );
 
   $form['server'] = array(
     '#type'  => 'fieldset',
@@ -80,6 +73,7 @@ function smtp_admin_settings() {
     '#default_value' => variable_get('smtp_port', '25'),
     '#description'   => t('The default SMTP port is 25, if that is being blocked try 80. Gmail uses 465. See !url for more information on configuring for use with Gmail.', array('!url' => l(t('this page'), 'http://gmail.google.com/support/bin/answer.py?answer=13287'))),
   );
+
   // Only display the option if openssl is installed.
   if (function_exists('openssl_open')) {
     $encryption_options = array(
@@ -87,7 +81,7 @@ function smtp_admin_settings() {
       'ssl'      => t('Use SSL'),
       'tls'      => t('Use TLS'),
     );
-    $encryption_description = t('This allows connection to an SMTP server that requires SSL encryption such as Gmail.');
+    $encryption_description = t('This allows connection to a SMTP server that requires SSL encryption such as Gmail.');
   }
   // If openssl is not installed, use normal protocol.
   else {
@@ -119,6 +113,9 @@ function smtp_admin_settings() {
     '#title'         => t('Password'),
     '#default_value' => variable_get('smtp_password', ''),
     '#description'   => t('SMTP password. If you have already entered your password before, you should leave this field blank, unless you want to change the stored password.'),
+    '#attributes'    => array(
+      'autocomplete' => 'off',
+    ),
   );
 
   $form['email_options'] = array(
@@ -139,22 +136,28 @@ function smtp_admin_settings() {
   );
   $form['email_options']['smtp_allowhtml'] = array(
     '#type'          => 'checkbox',
-    '#title'         => t('Allow to send e-mails formated as Html'),
+    '#title'         => t('Allow to send e-mails formatted as Html'),
     '#default_value' => variable_get('smtp_allowhtml', 0),
-    '#description'   => t('Checking this box will allow Html formated e-mails to be sent with the SMTP protocol.'),
+    '#description'   => t('Checking this box will allow Html formatted e-mails to be sent with the SMTP protocol.'),
+  );
+
+  $form['client'] = array(
+    '#type'  => 'fieldset',
+    '#title' => t('SMTP client settings'),
+  );
+  $form['client']['smtp_client_hostname'] = array(
+    '#type' => 'textfield',
+    '#title' => t('Hostname'),
+    '#default_value' => variable_get('smtp_client_hostname', ''),
+    '#description' => t('The hostname to use in the Message-Id and Received headers, and as the default HELO string. Leave blank for using %server_name.', array('%server_name' => isset($_SERVER['SERVER_NAME']) ? $_SERVER['SERVER_NAME'] : 'localhost.localdomain')),
+  );
+  $form['client']['smtp_client_helo'] = array(
+    '#type' => 'textfield',
+    '#title' => t('HELO'),
+    '#default_value' => variable_get('smtp_client_helo', ''),
+    '#description' => t('The SMTP HELO/EHLO of the message. Defaults to hostname (see above).'),
   );
 
-  // If an address was given, send a test e-mail message.
-  $test_address = variable_get('smtp_test_address', '');
-  if ($test_address != '') {
-    // Clear the variable so only one message is sent.
-    variable_del('smtp_test_address');
-    global $language;
-    $params['subject'] = t('Drupal SMTP test e-mail');
-    $params['body']    = array(t('If you receive this message it means your site is capable of using SMTP to send e-mail.'));
-    drupal_mail('smtp', 'smtp-test', $test_address, $language, $params);
-    drupal_set_message(t('A test e-mail has been sent to @email. You may want to !check for any error messages.', array('@email' => $test_address, '!check' => l(t('check the logs'), 'admin/reports/dblog'))));
-  }
   $form['email_test'] = array(
     '#type'  => 'fieldset',
     '#title' => t('Send test e-mail'),
@@ -166,51 +169,76 @@ function smtp_admin_settings() {
     '#description'   => t('Type in an address to have a test e-mail sent there.'),
   );
 
-  $form['smtp_debugging'] = array(
-    '#type'          => 'checkbox',
-    '#title'         => t('Enable debugging'),
-    '#default_value' => variable_get('smtp_debugging', 0),
-    '#description'   => t('Checking this box will print SMTP messages from the server for every e-mail that is sent.'),
+  $form['debugging'] = array(
+    '#type'        => 'fieldset',
+    '#title'       => t('Debugging and logging'),
   );
 
-  $form['#submit'][] = 'smtp_admin_settings_form_submit';
+  $logging_options = array(
+    SMTP_LOGGING_ALL => t('Log everything'),
+    SMTP_LOGGING_ERRORS => t('Errors only'),
+    SMTP_LOGGING_NONE => t('No logging'),
+  );
+  $form['debugging']['smtp_debugging'] = array(
+    '#type'          => 'select',
+    '#title'         => t('Logging'),
+    '#options'       => $logging_options,
+    '#default_value' => $logging,
+    '#description'   => t('Choose the appropriate log level. "Log everything" will log errors and informational messages when an email is sent. "Errors only" will only create a log entry when sending failed. "No logging" will disable all logging for this module.'),
+  );
+  $form['email_test']['smtp_reroute_address'] = array(
+    '#type'          => 'textfield',
+    '#title'         => t('E-mail address to reroute all emails to'),
+    '#default_value' => variable_get('smtp_reroute_address', ''),
+    '#description'   => t('All emails sent by the site will be rerouted to this email address; use with caution.'),
+  );
 
-  return system_settings_form($form);
-}  //  End of smtp_admin_settings().
+  $form['debugging']['maillog'] = array(
+    '#type' => 'fieldset',
+    '#title' => t('Maillog integration'),
+  );
 
+  if (!module_exists('maillog')) {
+    $form['debugging']['maillog']['#description'] = t('Installing the <a href="@url">Maillog module</a> also allows keeping copies of all emails sent through the site.', array('@url' => 'https://www.drupal.org/project/maillog'));
+  }
+  else {
+    $form['debugging']['maillog']['#description'] = t('The <a href="@url">Maillog module</a> is installed, it can also be used to keep copies of all emails sent through the site.', array('@url' => url('admin/config/development/maillog')));
 
+    $form['debugging']['maillog']['maillog_log'] = array(
+      '#type' => 'checkbox',
+      '#title' => t("Create table entries in maillog table for each e-mail."),
+      '#default_value' => variable_get('maillog_log', TRUE),
+    );
+
+    $form['debugging']['maillog']['maillog_devel'] = array(
+      '#type' => 'checkbox',
+      '#title' => t("Display the e-mails on page using devel module (if enabled)."),
+      '#default_value' => variable_get('maillog_devel', TRUE),
+      '#disabled' => !module_exists('devel'),
+    );
+  }
+
+  $form['#submit'][] = 'smtp_admin_settings_form_submit';
+  $form = system_settings_form($form);
+  $form['#submit'][] = 'smtp_admin_settings_submit_post_system_settings';
+  return $form;
+}
 
 /**
  * Validation for the administrative settings form.
- *
- * @param form
- *   An associative array containing the structure of the form.
- * @param form_state
- *   A keyed array containing the current state of the form.
  */
 function smtp_admin_settings_validate($form, &$form_state) {
   if ($form_state['values']['smtp_on'] == 1 && $form_state['values']['smtp_host'] == '') {
-    form_set_error('smtp_host', t('You must enter an SMTP server address.'));
+    form_set_error('smtp_host', t('You must enter a SMTP server address.'));
   }
 
   if ($form_state['values']['smtp_on'] == 1 && $form_state['values']['smtp_port'] == '') {
-    form_set_error('smtp_port', t('You must enter an SMTP port number.'));
+    form_set_error('smtp_port', t('You must enter a SMTP port number.'));
   }
 
   if ($form_state['values']['smtp_from'] && !valid_email_address($form_state['values']['smtp_from'])) {
     form_set_error('smtp_from', t('The provided from e-mail address is not valid.'));
   }
-
-  // If username is set empty, we must set both username/password empty as well.
-  if (empty($form_state['values']['smtp_username'])) {
-    $form_state['values']['smtp_password'] = '';
-  }
-
-  // A little hack. When form is presentend, the password is not shown (Drupal way of doing).
-  // So, if user submits the form without changing the password, we must prevent it from being reset.
-  elseif (empty($form_state['values']['smtp_password'])) {
-    unset($form_state['values']['smtp_password']);
-  }
 }  //  End of smtp_admin_settings_validate().
 
 /**
@@ -236,4 +264,37 @@ function smtp_admin_settings_form_submit($form, &$form_state) {
 
     variable_set('mail_system', $mail_modes);
   }
+
+  // If username is set empty, we must set both username/password empty as well.
+  if (empty($form_state['values']['smtp_username'])) {
+    $form_state['values']['smtp_password'] = '';
+  }
+
+  // A little hack. When form is presentend, the password is not shown (Drupal
+  // way of doing). So, if user submits the form without changing the password,
+  // we must prevent it from being reset.
+  elseif (empty($form_state['values']['smtp_password'])) {
+    unset($form_state['values']['smtp_password']);
+  }
+
+  // Save the test address to send an email after all the settings have been
+  // updated.
+  $form_state['storage']['smtp']['smtp_test_address'] = $form_state['values']['smtp_test_address'];
+  unset($form_state['values']['smtp_test_address']);
+}
+
+/**
+ * Submit handler for the administrative settings form containing all
+ * functionality to be run after system_settings_form_submit.
+ */
+function smtp_admin_settings_submit_post_system_settings($form, &$form_state) {
+  // If an address was given, send a test e-mail message.
+  $test_address = $form_state['storage']['smtp']['smtp_test_address'];
+  if ($test_address != '') {
+    $language = language_default();
+    $params['subject'] = t('Drupal SMTP test e-mail');
+    $params['body'] = array(t('If you receive this message it means your site is capable of using SMTP to send e-mail.'));
+    drupal_mail('smtp', 'smtp-test', $test_address, $language, $params);
+    drupal_set_message(t('A test e-mail has been sent to @email. You may want to !check for any error messages.', array('@email' => $test_address, '!check' => l(t('check the logs'), 'admin/reports/dblog'))));
+  }
 }

+ 9 - 3
sites/all/modules/contrib/mail/smtp/smtp.info

@@ -7,9 +7,15 @@ files[] = smtp.mail.inc
 files[] = smtp.phpmailer.inc
 files[] = smtp.transport.inc
 
-; Information added by Drupal.org packaging script on 2015-01-07
-version = "7.x-1.2"
+; Test suite.
+files[] = tests/smtp.unit.test
+
+; For the tests the Maillog module is also required.
+test_dependencies[] = maillog
+
+; Information added by Drupal.org packaging script on 2017-06-27
+version = "7.x-1.7"
 core = "7.x"
 project = "smtp"
-datestamp = "1420662781"
+datestamp = "1498593247"
 

+ 74 - 8
sites/all/modules/contrib/mail/smtp/smtp.install

@@ -5,6 +5,34 @@
  * The installation instructions for the SMTP Authentication Support.
  */
 
+/**
+ * Implements hook_requirements().
+ */
+function smtp_requirements($phase) {
+  $requirements = array();
+
+  if ($phase == 'runtime') {
+    if (variable_get('smtp_queue', FALSE) || variable_get('smtp_queue_fail', FALSE)) {
+      $count = db_query("SELECT count('name') FROM {queue} WHERE name='smtp_send_queue'")->fetchField();
+      $requirements['smtp_queue'] = array(
+        'title' => t('SMTP Queue'),
+        'value' => '',
+        'severity' => REQUIREMENT_INFO,
+      );
+      if ($count > 0) {
+        $requirements['smtp_queue']['value'] = format_plural($count, 'There is 1 message queued for delivery.', 'There are @count messages queued for delivery.', array('@count' => $count))
+          . ' '
+          . t('Delivery of the message(s) will be attempted the next time cron runs.');
+      }
+      else {
+        $requirements['smtp_queue']['value'] = t('There are no messages queued for delivery.');
+      }
+    }
+  }
+
+  return $requirements;
+}
+
 /**
  * Implements hook_install().
  */
@@ -16,6 +44,7 @@
  * Implements hook_uninstall().
  */
 function smtp_uninstall() {
+  variable_del('smtp_allowhtml');
   variable_del('smtp_from');
   variable_del('smtp_fromname');
   variable_del('smtp_host');
@@ -24,12 +53,14 @@ function smtp_uninstall() {
   variable_del('smtp_password');
   variable_del('smtp_port');
   variable_del('smtp_protocol');
-  variable_del('smtp_test_address');
+  variable_del('smtp_queue');
+  variable_del('smtp_queue_fail');
   variable_del('smtp_username');
-
-  if (variable_get('smtp_library', '') == drupal_get_path('module', 'smtp') . '/smtp.module') {
-    variable_del('smtp_library');
-  }
+  variable_del('smtp_debugging');
+  variable_del('smtp_client_hostname');
+  variable_del('smtp_client_helo');
+  variable_del('smtp_deliver');
+  variable_del('smtp_reroute_address');
 }
 
 /**
@@ -42,18 +73,21 @@ function smtp_disable() {
 }
 
 /**
- * Implements hook_update_N().
+ * Implementations of hook_update_N().
+ */
+
+/**
  * Upgrade to Drupal 7.x
  */
 function smtp_update_7000() {
   if (variable_get('smtp_on', 0) != 0) {
     variable_set('mail_system', array('default-system' => 'SmtpMailSystem'));
   }
+  // Not used any more in D7.
+  variable_del('smtp_library');
 }
 
 /**
- * Implements hook_update_N().
- *
  * Back to default mail system if the status flag is off.
  */
 function smtp_update_7100() {
@@ -63,3 +97,35 @@ function smtp_update_7100() {
     variable_set('mail_system', $mail_modes);
   }
 }
+
+/**
+ * Updating variable value now that new SMTP logging behavior has been
+ * implemented.
+ */
+function smtp_update_7101() {
+  $old_debugging_value = variable_get('smtp_debugging', 0);
+
+  $logging = SMTP_LOGGING_NONE;
+
+  if ($old_debugging_value == 1) {
+    $logging = SMTP_LOGGING_ERRORS;
+  }
+
+  variable_set('smtp_debugging', $logging);
+}
+
+/**
+ * Remove the unused 'smtp_library' variable.
+ */
+function smtp_update_7102() {
+  variable_del('smtp_library');
+}
+
+/**
+ * Delete the variable "smtp_test_address". It is unlikely that this would
+ * actually be set in the normal course of events, and it's no longer needed as
+ * it was replaced with a form submit handler.
+ */
+function smtp_update_7103() {
+  variable_del('smtp_test_address');
+}

+ 243 - 87
sites/all/modules/contrib/mail/smtp/smtp.mail.inc

@@ -46,35 +46,84 @@ class SmtpMailSystem implements MailSystemInterface {
    *   TRUE if the mail was successfully accepted, otherwise FALSE.
    */
   public function mail(array $message) {
-    $id = $message['id'];
+    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'];
     $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 (variable_get('smtp_debugging', 0) == 1) {
+    if ($logging == SMTP_LOGGING_ALL && user_access('administer smtp module')) {
       $mailer->SMTPDebug = TRUE;
     }
 
-    // Set the from name.
-    if (variable_get('smtp_fromname', '') != '') {
-      $from_name = variable_get('smtp_fromname', '');
+    // 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.
+    $from_name = FALSE;
+    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 {
+        // If value is not defined in settings, use site_name.
+        $from_name = i18n_variable_get('site_name', $langcode, '');
+      }
     }
-    else {
-      // If value is not defined in settings, use site_name.
-      $from_name = variable_get('site_name', '');
+
+    if (variable_get('smtp_client_hostname', '') != '') {
+      $mailer->Hostname = variable_get('smtp_client_hostname', '');
     }
 
-    //Hack to fix reply-to issue.
-    $properfrom = variable_get('site_mail', '');
-    if (!empty($properfrom)) {
-      $headers['From'] = $properfrom;
+    if (variable_get('smtp_client_helo', '') != '') {
+      $mailer->Helo = variable_get('smtp_client_helo', '');
+    }
+
+    // If i18n is not enabled, we get the From Name through normal variables
+    if (!$from_name) {
+      if (variable_get('smtp_fromname', '') != '') {
+        $from_name = variable_get('smtp_fromname', '');
+      }
+      else {
+        // If value is not defined in settings, use site_name.
+        $from_name = variable_get('site_name', '');
+      }
     }
+
+    //Hack to fix reply-to issue.
     if (!isset($headers['Reply-To']) || empty($headers['Reply-To'])) {
       if (strpos($from, '<')) {
         $reply = preg_replace('/>.*/', '', preg_replace('/.*</', '', $from));
@@ -84,6 +133,11 @@ class SmtpMailSystem implements MailSystemInterface {
       }
       $headers['Reply-To'] = $reply;
     }
+    $properfrom = variable_get('smtp_from', '');
+    if (!empty($properfrom)) {
+      $headers['From'] = $properfrom;
+      $from = $properfrom;
+    }
 
     // Blank value will let the e-mail address appear.
 
@@ -93,42 +147,34 @@ class SmtpMailSystem implements MailSystemInterface {
         // 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');
-          watchdog('smtp', 'There is no submitted from address.', array(), WATCHDOG_ERROR);
+          if ($logging) {
+            watchdog('smtp', 'There is no submitted from address.', array(), WATCHDOG_ERROR);
+          }
           return FALSE;
         }
       }
     }
-    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('/"?([^("\t\n)]*)"?.*$/', '$1', $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);
+    $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;
-    $mailer->FromName = $from_name;
-    $mailer->Sender   = $from;
+    $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) {
-      if (strpos($torecipient, '<') !== FALSE) {
-        $toparts = explode(' <', $torecipient);
-        $toname = $toparts[0];
-        $toaddr = rtrim($toparts[1], '>');
-      }
-      else {
-        $toname = '';
-        $toaddr = $torecipient;
-      }
-      $mailer->AddAddress($toaddr, $toname);
+      $to_comp = $this->_get_components($torecipient);
+      $mailer->AddAddress($to_comp['email'], $to_comp['name']);
     }
 
 
@@ -201,8 +247,9 @@ class SmtpMailSystem implements MailSystemInterface {
             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');
-              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);
-
+              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';
@@ -212,16 +259,8 @@ class SmtpMailSystem implements MailSystemInterface {
         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], '>');
-              $mailer->AddReplyTo($replyToAddr, $replyToName);
-            }
-            else {
-              $mailer->AddReplyTo($value);
-            }
+            $replyto_comp = $this->_get_components($value);
+            $mailer->AddReplyTo($replyto_comp['email'], $replyto_comp['name']);
           }
           break;
 
@@ -230,14 +269,8 @@ class SmtpMailSystem implements MailSystemInterface {
           break;
 
         case 'return-path':
-          if (strpos($value, '<') !== FALSE) {
-            $returnPathParts = explode('<', $value);
-            $returnPathAddr = rtrim($returnPathParts[1], '>');
-            $mailer->Sender = $returnPathAddr;
-          }
-          else {
-            $mailer->Sender = $value;
-          }
+          $returnpath_comp = $this->_get_components($value);
+          $mailer->Sender = $returnpath_comp['email'];
           break;
 
         case 'mime-version':
@@ -252,32 +285,16 @@ class SmtpMailSystem implements MailSystemInterface {
         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;
-            }
-            $mailer->AddCC($ccaddr, $ccname);
+            $cc_comp = $this->_get_components($ccrecipient);
+            $mailer->AddCC($cc_comp['email'], $cc_comp['name']);
           }
           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;
-            }
-            $mailer->AddBCC($bccaddr, $bccname);
+            $bcc_comp = $this->_get_components($bccrecipient);
+            $mailer->AddBCC($bcc_comp['email'], $bcc_comp['name']);
           }
           break;
 
@@ -377,7 +394,7 @@ class SmtpMailSystem implements MailSystemInterface {
               // If plain/html within the body part, add it to $mailer->Body.
               elseif (strpos($body_part2, 'text/html')) {
                 // Get the encoding.
-                $body_part2_encoding = $this->_get_substring($body_part2, 'Content-Transfer-Encoding', ':', "\n");
+                $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.
@@ -509,20 +526,124 @@ class SmtpMailSystem implements MailSystemInterface {
     $mailer->Port = variable_get('smtp_port', '25');
     $mailer->Mailer = 'smtp';
 
-    $mailerArr = array(
-      'mailer' => $mailer,
-      'to' => $to,
-      'from' => $from,
-    );
-    if (variable_get('smtp_queue', FALSE)) {
-      watchdog('smtp', 'Queue sending mail to: @to', array('@to' => $to));
-      smtp_send_queue($mailerArr);
+    // 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 {
-      return _smtp_mailer_send($mailerArr);
+      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));
+      }
     }
 
-    return TRUE;
+    $mailer->SmtpClose();
+    return !$error;
   }
 
   /**
@@ -628,6 +749,41 @@ class SmtpMailSystem implements MailSystemInterface {
       $substring = drupal_substr($substring, 0, $string_length);
     }
 
-    return $substring;
+    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) {
+    $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'] = trim($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;
+  }
 }

+ 70 - 17
sites/all/modules/contrib/mail/smtp/smtp.module

@@ -15,6 +15,22 @@
  * This module uses array('default-system' => 'SmtpMailSystem').
  */
 
+/**
+ * SMTP logging -- logging is disabled
+ */
+define('SMTP_LOGGING_NONE', 0);
+
+/**
+ * SMTP logging -- all messages are logged
+ */
+define('SMTP_LOGGING_ALL', 1);
+
+/**
+ * SMTP logging -- only errors are logged
+ */
+define('SMTP_LOGGING_ERRORS', 2);
+
+
 /**
  * Implements hook_help().
  */
@@ -68,8 +84,14 @@ function smtp_mail($key, &$message, $params) {
 function smtp_cron_queue_info() {
   $queues['smtp_send_queue'] = array(
     'worker callback' => 'smtp_send_queue_runner',
-    'time' => 60, // This is the max run time per cron run in seconds.
+    'time' => 60,
+  );
+
+  $queues['smtp_failure_queue'] = array(
+    'worker callback' => 'smtp_failure_queue_runner',
+    'time' => 30,
   );
+
   return $queues;
 }
 
@@ -81,24 +103,55 @@ function smtp_send_queue($mailerObj) {
   $queue->createItem($mailerObj);
 }
 
-function smtp_send_queue_runner($variables) {
-  _smtp_mailer_send($variables);
-}
+function smtp_send_queue_runner($message) {
+  $logging = variable_get('smtp_debugging', SMTP_LOGGING_ERRORS);
 
-function _smtp_mailer_send($variables) {
-  $mailer = $variables['mailer'];
-  $to = $variables['to'];
-  $from = $variables['from'];
+  // Legacy for mails queued before 7.x-v1.3
+  // What was passed to the runner used to be a PHPMailer object, not a message array.
+  if (!empty($message['mailer']) && is_object($message['mailer'])) {
+    if (!$message['mailer']->Send()) {
+      if ($logging == SMTP_LOGGING_ALL || $logging == SMTP_LOGGING_ERRORS) {
+        watchdog('smtp', 'Error sending e-mail from @from to @to, will retry on cron run : !error_message.',
+          array(
+            '@from' => $message['from'],
+            '@to' => $message['to'],
+            '!error_message' => $message['mailer']->ErrorInfo,
+          ), WATCHDOG_ERROR);
+      }
+    }
+    return;
+  }
 
   // Let the people know what is going on.
-  watchdog('smtp', 'Sending mail to: @to', array('@to' => $to));
-
-  // Try to send e-mail. If it fails, set watchdog entry.
-  if (!$mailer->Send()) {
-    watchdog('smtp', 'Error sending e-mail from @from to @to : !error_message', array('@from' => $from, '@to' => $to, '!error_message' => $mailer->ErrorInfo), WATCHDOG_ERROR);
-    return FALSE;
+  if ($logging == SMTP_LOGGING_ALL) {
+    watchdog('smtp', 'Sending mail to: @to', array('@to' => $message['to']));
   }
 
-  $mailer->SmtpClose();
-  return TRUE;
-}
+  // Send the message.
+  $mail_system = new SmtpMailSystem();
+  $mail_system->mailWithoutQueue($message);
+}
+
+/**
+ * Store failed messages for later.
+ *
+ * @param array $new_message
+ *
+ * @return array
+ *   All messages that have been saved.
+ */
+function smtp_failed_messages($message) {
+  $queue = DrupalQueue::get('smtp_failure_queue');
+  $queue->createItem($message);
+}
+
+/**
+ * Queue runner for smtp_failure_queue.
+ *
+ * @param $message
+ *   A drupal_mail-formatted message.
+ */
+function smtp_failure_queue_runner($message) {
+  $queue = DrupalQueue::get('smtp_send_queue');
+  $queue->createItem($message);
+}

+ 40 - 68
sites/all/modules/contrib/mail/smtp/smtp.phpmailer.inc

@@ -7,7 +7,7 @@
  */
 
 /*~ class.phpmailer.php
-Orginal release information:
+Original release information:
 .---------------------------------------------------------------------------.
 |  Software: PHPMailer - PHP email class                                    |
 |   Version: 5.1                                                            |
@@ -325,6 +325,7 @@ class PHPMailer {
   private   $sign_key_file  = "";
   private   $sign_key_pass  = "";
   private   $exceptions     = FALSE;
+  private   $logging;
 
   /////////////////////////////////////////////////
   // CONSTANTS
@@ -343,6 +344,7 @@ class PHPMailer {
    * @param boolean $exceptions Should we throw external exceptions?
    */
   public function __construct($exceptions = FALSE) {
+    $this->logging = variable_get('smtp_debugging', SMTP_LOGGING_ERRORS);
     $this->exceptions = ($exceptions == TRUE);
   }
 
@@ -455,7 +457,9 @@ class PHPMailer {
    */
   private function AddAnAddress($kind, $address, $name = '') {
     if (!preg_match('/^(to|cc|bcc|ReplyTo)$/', $kind)) {
-      echo 'Invalid recipient array: ' . kind;
+      if ($this->logging) {
+        watchdog('smtp', 'Invalid recipient array: %kind', array('%kind' => $kind), WATCHDOG_ERROR);
+      }
       return FALSE;
     }
     $address = trim($address);
@@ -465,7 +469,9 @@ class PHPMailer {
       if ($this->exceptions) {
         throw new phpmailerException(t('Invalid address') . ': ' . $address);
       }
-      echo t('Invalid address') . ': ' . $address;
+      if ($this->logging) {
+        watchdog('smtp', 'Invalid address: %address', array('%address' => $address), WATCHDOG_ERROR);
+      }
       return FALSE;
     }
     if ($kind != 'ReplyTo') {
@@ -498,7 +504,9 @@ class PHPMailer {
       if ($this->exceptions) {
         throw new phpmailerException(t('Invalid address') . ': ' . $address);
       }
-      echo t('Invalid address') . ': ' . $address;
+      if ($this->logging) {
+        watchdog('smtp', 'Invalid address: %address', array('%address' => $address), WATCHDOG_ERROR);
+      }
       return FALSE;
     }
     $this->From = $address;
@@ -577,8 +585,6 @@ class PHPMailer {
 
       // Choose the mailer and send through it
       switch ($this->Mailer) {
-        case 'sendmail':
-          return $this->SendmailSend($header, $body);
         case 'smtp':
           return $this->SmtpSend($header, $body);
         default:
@@ -590,57 +596,11 @@ class PHPMailer {
       if ($this->exceptions) {
         throw $e;
       }
-      echo $e->getMessage() . "\n";
-      return FALSE;
-    }
-  }
-
-  /**
-   * Sends mail using the $Sendmail program.
-   * @param string $header The message headers
-   * @param string $body The message body
-   * @access protected
-   * @return bool
-   */
-  protected function SendmailSend($header, $body) {
-    if ($this->Sender != '') {
-      $sendmail = sprintf("%s -oi -f %s -t", escapeshellcmd($this->Sendmail), escapeshellarg($this->Sender));
-    }
-    else {
-      $sendmail = sprintf("%s -oi -t", escapeshellcmd($this->Sendmail));
-    }
-    if ($this->SingleTo === TRUE) {
-      foreach ($this->SingleToArray as $key => $val) {
-        if (!@$mail = popen($sendmail, 'w')) {
-          throw new phpmailerException(t('Could not execute: !smail', array('!smail' => $this->Sendmail)), self::STOP_CRITICAL);
-        }
-        fputs($mail, "To: " . $val . "\n");
-        fputs($mail, $header);
-        fputs($mail, $body);
-        $result = pclose($mail);
-        // implement call back function if it exists
-        $isSent = ($result == 0) ? 1 : 0;
-        $this->doCallback($isSent, $val, $this->cc, $this->bcc, $this->Subject, $body);
-        if ($result != 0) {
-          throw new phpmailerException(t('Could not execute: !smail', array('!smail' => $this->Sendmail)), self::STOP_CRITICAL);
-        }
-      }
-    }
-    else {
-      if (!@$mail = popen($sendmail, 'w')) {
-        throw new phpmailerException(t('Could not execute: !smail', array('!smail' => $this->Sendmail)), self::STOP_CRITICAL);
-      }
-      fputs($mail, $header);
-      fputs($mail, $body);
-      $result = pclose($mail);
-      // implement call back function if it exists
-      $isSent = ($result == 0) ? 1 : 0;
-      $this->doCallback($isSent, $this->to, $this->cc, $this->bcc, $this->Subject, $body);
-      if ($result != 0) {
-        throw new phpmailerException(t('Could not execute: !smail', array('!smail' => $this->Sendmail)), self::STOP_CRITICAL);
+      if ($this->logging) {
+        watchdog_exception('smtp', $e);
       }
+      return FALSE;
     }
-    return TRUE;
   }
 
   /**
@@ -662,7 +622,7 @@ class PHPMailer {
       $old_from = ini_get('sendmail_from');
       ini_set('sendmail_from', $this->Sender);
       if ($this->SingleTo === TRUE && count($toArr) > 1) {
-        foreach ($toArr as $key => $val) {
+        foreach ($toArr as $val) {
           $rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
           // implement call back function if it exists
           $isSent = ($rt == 1) ? 1 : 0;
@@ -678,7 +638,7 @@ class PHPMailer {
     }
     else {
       if ($this->SingleTo === TRUE && count($toArr) > 1) {
-        foreach ($toArr as $key => $val) {
+        foreach ($toArr as $val) {
           $rt = @mail($val, $this->EncodeHeader($this->SecureHeader($this->Subject)), $body, $header, $params);
           // implement call back function if it exists
           $isSent = ($rt == 1) ? 1 : 0;
@@ -792,10 +752,11 @@ class PHPMailer {
     $hosts = explode(';', $this->Host);
     $index = 0;
     $connection = $this->smtp->Connected();
+    $lastexception = NULL;
 
     // Retry while there is no connection
-    try {
-      while ($index < count($hosts) && !$connection) {
+    while ($index < count($hosts) && !$connection) {
+      try {
         $hostinfo = array();
         if (preg_match('/^(.+):([0-9]+)$/', $hosts[$index], $hostinfo)) {
           $host = $hostinfo[1];
@@ -830,14 +791,24 @@ class PHPMailer {
             }
           }
         }
-        $index++;
-        if (!$connection) {
-          throw new phpmailerException(t('SMTP Error: Could not connect to SMTP host.'));
+      } catch (phpmailerException $e) {
+        if ($connection) {
+          $this->SmtpClose();
+          $connection = FALSE;
         }
+
+        $lastexception = $e;
+      }
+
+      $index++;
+    }
+    if (!$connection) {
+      if ($lastexception != NULL) {
+        throw $lastexception;
+      }
+      else {
+        throw new phpmailerException(t('SMTP Error: Could not connect to SMTP host.'));
       }
-    } catch (phpmailerException $e) {
-      $this->smtp->Reset();
-      throw $e;
     }
     return TRUE;
   }
@@ -1361,7 +1332,9 @@ class PHPMailer {
       if ($this->exceptions) {
         throw $e;
       }
-      echo $e->getMessage() . "\n";
+      if ($this->logging) {
+        watchdog_exception('smtp', $e);
+      }
       if ( $e->getCode() == self::STOP_CRITICAL ) {
         return FALSE;
       }
@@ -2217,7 +2190,6 @@ class PHPMailer {
    * @param string $key_pass Password for private key
    */
   public function DKIM_QP($txt) {
-    $tmp="";
     $line="";
     for ($i=0;$i<strlen($txt);$i++) {
       $ord=ord($txt[$i]);
@@ -2344,4 +2316,4 @@ class phpmailerException extends Exception {
     $errorMsg = '<strong>' . $this->getMessage() . "</strong><br />\n";
     return $errorMsg;
   }
-}
+}

+ 32 - 32
sites/all/modules/contrib/mail/smtp/smtp.transport.inc

@@ -6,7 +6,7 @@
  *
  */
 /*~ class.smtp.php
-Orginal release information:
+Original release information:
 .---------------------------------------------------------------------------.
 |  Software: PHPMailer - PHP email class                                    |
 |   Version: 5.1                                                            |
@@ -141,7 +141,7 @@ class SMTP {
                            "errno" => $errno,
                            "errstr" => $errstr);
       if ($this->do_debug >= 1) {
-        echo "SMTP -> ERROR: " . $this->error["error"] . ": $errstr ($errno)" . $this->CRLF . '<br />';
+        drupal_set_message(t("SMTP -> ERROR: @error: @errstr (@errno)", array("@error" => $this->error["error"], "@errstr" => $errstr, "@errno" => $errno)));
       }
       return FALSE;
     }
@@ -155,7 +155,7 @@ class SMTP {
     $announce = $this->get_lines();
 
     if ($this->do_debug >= 2) {
-      echo "SMTP -> FROM SERVER:" . $announce . $this->CRLF . '<br />';
+      drupal_set_message(t("SMTP -> FROM SERVER: @announce", array("@announce" => $announce)));
     }
 
     return TRUE;
@@ -184,7 +184,7 @@ class SMTP {
     $code = substr($rply, 0, 3);
 
     if ($this->do_debug >= 2) {
-      echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
+      drupal_set_message(t("SMTP -> FROM SERVER: @rply", array("@rply" => $rply)));
     }
 
     if ($code != 220) {
@@ -193,7 +193,7 @@ class SMTP {
                "smtp_code" => $code,
                "smtp_msg"  => substr($rply, 4));
       if ($this->do_debug >= 1) {
-        echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
+        drupal_set_message(t("SMTP -> ERROR: @error: @rply", array("@error" => $this->error["error"], "@rply" => $rply)));
       }
       return FALSE;
     }
@@ -225,7 +225,7 @@ class SMTP {
               "smtp_code" => $code,
               "smtp_msg" => substr($rply, 4));
       if ($this->do_debug >= 1) {
-        echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
+        drupal_set_message(t("SMTP -> ERROR: @error: @rply", array("@error" => $this->error["error"], "@rply" => $rply)));
       }
       return FALSE;
     }
@@ -242,7 +242,7 @@ class SMTP {
               "smtp_code" => $code,
               "smtp_msg" => substr($rply, 4));
       if ($this->do_debug >= 1) {
-        echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
+        drupal_set_message(t("SMTP -> ERROR: @error: @rply", array("@error" => $this->error["error"], "@rply" => $rply)));
       }
       return FALSE;
     }
@@ -259,7 +259,7 @@ class SMTP {
               "smtp_code" => $code,
               "smtp_msg" => substr($rply, 4));
       if ($this->do_debug >= 1) {
-        echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
+        drupal_set_message(t("SMTP -> ERROR: @error: @rply", array("@error" => $this->error["error"], "@rply" => $rply)));
       }
       return FALSE;
     }
@@ -278,7 +278,7 @@ class SMTP {
       if ($sock_status["eof"]) {
         // the socket is valid but we are not connected
         if ($this->do_debug >= 1) {
-            echo "SMTP -> NOTICE:" . $this->CRLF . "EOF caught while checking if connected";
+          drupal_set_message(t("SMTP -> NOTICE: EOF caught while checking if connected"));
         }
         $this->Close();
         return FALSE;
@@ -314,7 +314,7 @@ class SMTP {
    * finializing the mail transaction. $msg_data is the message
    * that is to be send with the headers. Each header needs to be
    * on a single line followed by a <CRLF> with the message headers
-   * and the message body being seperated by and additional <CRLF>.
+   * and the message body being separated by and additional <CRLF>.
    *
    * Implements rfc 821: DATA <CRLF>
    *
@@ -343,7 +343,7 @@ class SMTP {
     $code = substr($rply, 0, 3);
 
     if ($this->do_debug >= 2) {
-      echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
+      drupal_set_message(t("SMTP -> FROM SERVER: @rply", array("@rply" => $rply)));
     }
 
     if ($code != 354) {
@@ -352,7 +352,7 @@ class SMTP {
               "smtp_code" => $code,
               "smtp_msg" => substr($rply, 4));
       if ($this->do_debug >= 1) {
-        echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
+        drupal_set_message(t("SMTP -> ERROR: @error: @rply", array("@error" => $this->error["error"], "@rply" => $rply)));
       }
       return FALSE;
     }
@@ -437,7 +437,7 @@ class SMTP {
     $code = substr($rply, 0, 3);
 
     if ($this->do_debug >= 2) {
-      echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
+      drupal_set_message(t("SMTP -> FROM SERVER: @rply", array("@rply" => $rply)));
     }
 
     if ($code != 250) {
@@ -446,7 +446,7 @@ class SMTP {
               "smtp_code" => $code,
               "smtp_msg" => substr($rply, 4));
       if ($this->do_debug >= 1) {
-        echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
+        drupal_set_message(t("SMTP -> ERROR: @error: @rply", array("@error" => $this->error["error"], "@rply" => $rply)));
       }
       return FALSE;
     }
@@ -502,7 +502,7 @@ class SMTP {
     $code = substr($rply, 0, 3);
 
     if ($this->do_debug >= 2) {
-      echo "SMTP -> FROM SERVER: " . $rply . $this->CRLF . '<br />';
+      drupal_set_message(t("SMTP -> FROM SERVER: @rply", array("@rply" => $rply)));
     }
 
     if ($code != 250) {
@@ -511,7 +511,7 @@ class SMTP {
               "smtp_code" => $code,
               "smtp_msg" => substr($rply, 4));
       if ($this->do_debug >= 1) {
-        echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
+        drupal_set_message(t("SMTP -> ERROR: @error: @rply", array("@error" => $this->error["error"], "@rply" => $rply)));
       }
       return FALSE;
     }
@@ -551,7 +551,7 @@ class SMTP {
     $code = substr($rply, 0, 3);
 
     if ($this->do_debug >= 2) {
-      echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
+      drupal_set_message(t("SMTP -> FROM SERVER: @rply", array("@rply" => $rply)));
     }
 
     if ($code != 250) {
@@ -560,7 +560,7 @@ class SMTP {
               "smtp_code" => $code,
               "smtp_msg" => substr($rply, 4));
       if ($this->do_debug >= 1) {
-        echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
+        drupal_set_message(t("SMTP -> ERROR: @error: @rply", array("@error" => $this->error["error"], "@rply" => $rply)));
       }
       return FALSE;
     }
@@ -594,7 +594,7 @@ class SMTP {
     $byemsg = $this->get_lines();
 
     if ($this->do_debug >= 2) {
-      echo "SMTP -> FROM SERVER:" . $byemsg . $this->CRLF . '<br />';
+      drupal_set_message(t("SMTP -> FROM SERVER: @byemsg", array("@rply" => $byemsg)));
     }
 
     $rval = TRUE;
@@ -608,7 +608,7 @@ class SMTP {
                  "smtp_rply" => substr($byemsg, 4));
       $rval = FALSE;
       if ($this->do_debug >= 1) {
-        echo "SMTP -> ERROR: " . $e["error"] . ": " . $byemsg . $this->CRLF . '<br />';
+        drupal_set_message(t("SMTP -> ERROR: @error: @rply", array("@error" => $this->error["error"], "@rply" => $rply)));
       }
     }
 
@@ -646,7 +646,7 @@ class SMTP {
     $code = substr($rply, 0, 3);
 
     if ($this->do_debug >= 2) {
-      echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
+      drupal_set_message(t("SMTP -> FROM SERVER: @rply", array("@rply" => $rply)));
     }
 
     if ($code != 250 && $code != 251) {
@@ -655,7 +655,7 @@ class SMTP {
               "smtp_code" => $code,
               "smtp_msg" => substr($rply, 4));
       if ($this->do_debug >= 1) {
-        echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
+        drupal_set_message(t("SMTP -> ERROR: @error: @rply", array("@error" => $this->error["error"], "@rply" => $rply)));
       }
       return FALSE;
     }
@@ -689,7 +689,7 @@ class SMTP {
     $code = substr($rply, 0, 3);
 
     if ($this->do_debug >= 2) {
-      echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
+      drupal_set_message(t("SMTP -> FROM SERVER: @rply", array("@rply" => $rply)));
     }
 
     if ($code != 250) {
@@ -698,7 +698,7 @@ class SMTP {
               "smtp_code" => $code,
               "smtp_msg" => substr($rply, 4));
       if ($this->do_debug >= 1) {
-        echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
+        drupal_set_message(t("SMTP -> ERROR: @error: @rply", array("@error" => $this->error["error"], "@rply" => $rply)));
       }
       return FALSE;
     }
@@ -736,7 +736,7 @@ class SMTP {
     $code = substr($rply, 0, 3);
 
     if ($this->do_debug >= 2) {
-      echo "SMTP -> FROM SERVER:" . $rply . $this->CRLF . '<br />';
+      drupal_set_message(t("SMTP -> FROM SERVER: @rply", array("@rply" => $rply)));
     }
 
     if ($code != 250) {
@@ -745,7 +745,7 @@ class SMTP {
               "smtp_code" => $code,
               "smtp_msg" => substr($rply, 4));
       if ($this->do_debug >= 1) {
-        echo "SMTP -> ERROR: " . $this->error["error"] . ": " . $rply . $this->CRLF . '<br />';
+        drupal_set_message(t("SMTP -> ERROR: @error: @rply", array("@error" => $this->error["error"], "@rply" => $rply)));
       }
       return FALSE;
     }
@@ -755,7 +755,7 @@ class SMTP {
   /**
    * This is an optional command for SMTP that this class does not
    * support. This method is here to make the RFC821 Definition
-   * complete for this class and __may__ be implimented in the future
+   * complete for this class and __may__ be implemented in the future
    *
    * Implements from rfc 821: TURN <CRLF>
    *
@@ -768,7 +768,7 @@ class SMTP {
   public function Turn() {
     $this->error = array("error" => "This method, TURN, of the SMTP is not implemented");
     if ($this->do_debug >= 1) {
-      echo "SMTP -> NOTICE: " . $this->error["error"] . $this->CRLF . '<br />';
+      drupal_set_message(t("SMTP -> NOTICE: @error", array("@error" => $this->error["error"])));
     }
     return FALSE;
   }
@@ -799,12 +799,12 @@ class SMTP {
     $data = "";
     while ($str = @fgets($this->smtp_conn, 515)) {
       if ($this->do_debug >= 4) {
-        echo "SMTP -> get_lines(): \$data was \"$data\"" . $this->CRLF . '<br />';
-        echo "SMTP -> get_lines(): \$str is \"$str\"" . $this->CRLF . '<br />';
+        drupal_set_message(t("SMTP -> get_lines(): \$data was \"@data\"", array("@data" => $data)));
+        drupal_set_message(t("SMTP -> get_lines(): \$str is \"@str\"", array("@str" => $str)));
       }
       $data .= $str;
       if ($this->do_debug >= 4) {
-        echo "SMTP -> get_lines(): \$data is \"$data\"" . $this->CRLF . '<br />';
+        drupal_set_message(t("SMTP -> get_lines(): \$data was \"@data\"", array("@data" => $data)));
       }
       // if 4th character is a space, we are done reading, break the loop
       if (substr($str, 3, 1) == " ") {
@@ -813,4 +813,4 @@ class SMTP {
     }
     return $data;
   }
-}
+}

+ 40 - 0
sites/all/modules/contrib/mail/smtp/smtp.variable.inc

@@ -0,0 +1,40 @@
+<?php
+/**
+ * @file
+ * Custom integration with the Variable module.
+ */
+
+/**
+ * Implements hook_variable_group_info().
+ */
+function smtp_variable_group_info() {
+  $groups['smtp'] = array(
+    'title' => t('SMTP Authentication Support'),
+    'access' => 'administer smtp module',
+    'description' => t('Configure SMTP server for site emails to be sent from different names.'),
+  );
+
+  return $groups;
+}
+
+/**
+ * Implements hook_variable_info().
+ *
+ * Allows for the SMTP from name to be translated if/when the Variable module is
+ * enabled.
+ *
+ * @link http://api.drupalhelp.net/api/variable/variable.api.php/function/hook_variable_info/7
+ * @param array $options
+ */
+function smtp_variable_info($options) {
+  $variable['smtp_fromname'] = array (
+    'title' => t('Email from name (SMTP module)'),
+    'type' => 'string',
+    'description' => t('Allow for site emails to be sent from a different name.'),
+    'group' => 'smtp',
+    'multidomain' => TRUE,
+    'localize' => TRUE,
+  );
+
+  return $variable;
+}

+ 200 - 0
sites/all/modules/contrib/mail/smtp/tests/smtp.unit.test

@@ -0,0 +1,200 @@
+<?php
+/**
+ * @file
+ * Some tests for the SMTP module.
+ */
+
+class SmtpUnitTest extends DrupalWebTestCase {
+  /**
+   * {@inheritdoc}
+   */
+  public static function getInfo() {
+    return array(
+      'name' => 'SMTP unit tests',
+      'description' => 'Test the SMTP module.',
+      'group' => 'SMTP',
+    );
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  function setUp(array $modules = array()) {
+    // Requirements.
+    $modules[] = 'smtp';
+
+    // Some extra logic for fully testing the module.
+    $modules[] = 'smtp_tests';
+
+    // This module is used to log all emails so that the delivery can be
+    // confirmed.
+    $modules[] = 'maillog';
+
+    parent::setUp($modules);
+
+    // Take over the email system.
+    variable_set('mail_system', array('default-system' => 'SmtpMailSystem'));
+
+    // Turn on the mail module.
+    variable_set('smtp_on', TRUE);
+
+    // Do not actually deliver the emails.
+    variable_set('smtp_deliver', FALSE);
+
+    // Use Maillog to log all emails.
+    variable_set('maillog_log', TRUE);
+  }
+
+  /**
+   * Confirm that SMTP has taken over the 'mail_system' variable.
+   */
+  function testSetup() {
+    $enabled = variable_get('mail_system', array());
+    $should_be = array(
+      'default-system' => 'SmtpMailSystem',
+    );
+    $this->assertEqual($enabled, $should_be, 'SMTP is controlling mail delivery.');
+
+    $delivery = variable_get('smtp_on', TRUE);
+    $this->assertEqual($delivery, TRUE, 'SMTP is enabled.');
+
+    $delivery = variable_get('smtp_deliver', FALSE);
+    $this->assertEqual($delivery, FALSE, 'Email delivery is disabled.');
+
+    $logging = variable_get('maillog_log', TRUE);
+    $this->assertEqual($logging, TRUE, 'Email delivery is being logged.');
+  }
+
+  /**
+   * Tests logging mail with maillog module.
+   */
+  public function testLogging() {
+    $langcode = language_default('language');
+
+    // This is automatically assigned by Simpletest.
+    $sender = 'simpletest@example.com';
+
+    // Send an email.
+    $to_email = 'to_test@example.com';
+    $reply_email = 'reply_test@example.com';
+    $params = array();
+    drupal_mail('smtp_tests', 'smtp_basic_test', $to_email, $langcode, $params);
+
+    // The SMTP module controls the 'from' address but defaults to using the
+    // site's system email address.
+    $from_email = variable_get('site_mail', '');
+
+    // Compare the maillog db entry with the sent mail.
+    $logged_email = $this->getLatestMaillogEntry();
+    $this->assertTrue(!empty($logged_email), 'The test email was captured.');
+    $this->assertEqual($to_email, $logged_email['header_to']);//, 'Email "to" address is correct.');
+    $this->assertEqual($from_email, $logged_email['header_from']);//, 'Email "from" address is correct.');
+    $this->assertEqual($from_email, $logged_email['header_all']['From']);//, 'Email "from" header is correct.');
+    $this->assertEqual($sender, $logged_email['header_all']['Sender']);//, 'Email "sender" header is correct.');
+    $this->assertEqual($sender, $logged_email['header_all']['Return-Path']);//, 'Email "return-path" header is correct.');
+    $this->assertEqual('Drupal', $logged_email['header_all']['X-Mailer']);//, 'Email "x-mailer" header is correct.');
+    $this->assertEqual(t('Test email subject'), $logged_email['subject']);//, 'Email subject is correct.');
+    $this->assertEqual(t('Test email body.') . "\n", $logged_email['body']);//, 'Email body is correct.');
+  }
+
+  /**
+   * Confirm the queue works.
+   */
+  public function testQueue() {
+    // Turn on the queue.
+    variable_set('smtp_queue', TRUE);
+
+    // Send a test message.
+    $langcode = language_default('language');
+    $sender = 'simpletest@example.com';
+    $to_email = 'to_test@example.com';
+    $reply_email = 'reply_test@example.com';
+    $params = array();
+    drupal_mail('smtp_tests', 'smtp_basic_test', $to_email, $langcode, $params);
+
+    // Check the queue for messages.
+    $queue_count = $this->getQueueCount();
+    $this->assertEqual($queue_count, 1, 'An email was found in the send queue.');
+  }
+
+  /**
+   * Confirm the queue works.
+   */
+  public function testFailQueue() {
+    // Turn on the queue failover.
+    variable_set('smtp_queue_fail', TRUE);
+
+    // Make sure the queue is disabled.
+    variable_set('smtp_queue', FALSE);
+
+    // Turn on email delivery.
+    variable_set('smtp_deliver', TRUE);
+
+    // Set some fake values for the delivery, it should fail and then cause the
+    // email to go in to the queue.
+    variable_set('smtp_from', 'drupal@example.com');
+    variable_set('smtp_fromname', 'Drupal Simpletest');
+    variable_set('smtp_host', 'smtp.gmail.com');
+    variable_set('smtp_hostbackup', '');
+    variable_set('smtp_password', 'THIS WILL NOT WORK!');
+    variable_set('smtp_port', '465');
+    variable_set('smtp_protocol', 'ssl');
+    variable_set('smtp_username', 'hello@example.com');
+
+    // Send a test message.
+    $langcode = language_default('language');
+    $sender = 'simpletest@example.com';
+    $to_email = 'to_test@example.com';
+    $reply_email = 'reply_test@example.com';
+    $params = array();
+    drupal_mail('smtp_tests', 'smtp_basic_test', $to_email, $langcode, $params);
+
+    // Check the queue for messages.
+    $queue_count = $this->getQueueCount('smtp_failure_queue');
+    $this->assertEqual($queue_count, 1, 'An email was found in the failure queue.');
+    $queue_count = $this->getQueueCount();
+    $this->assertEqual($queue_count, 0, 'An email was not found in the regular email queue.');
+
+    // Run the queue so that messages can be moved to the normal email queue.
+    drupal_cron_run();
+
+    // Check the queue for messages.
+    $queue_count = $this->getQueueCount();
+    $this->assertEqual($queue_count, 1, 'An email was found in the regular email queue.');
+    $queue_count = $this->getQueueCount('smtp_failure_queue');
+    $this->assertEqual($queue_count, 0, 'An email was not found in the failure queue.');
+  }
+
+  /**
+   * Gets the latest Maillog entry.
+   *
+   * @return array
+   *   Maillog entry.
+   */
+  protected function getLatestMaillogEntry() {
+    $query = 'SELECT idmaillog, header_from, header_to, header_reply_to, header_all, subject, body FROM {maillog} ORDER BY idmaillog DESC';
+    $result = db_query_range($query, 0, 1);
+
+    if ($maillog = $result->fetchAssoc()) {
+      // Unserialize values.
+      $maillog['header_all'] = unserialize($maillog['header_all']);
+    }
+    return $maillog;
+  }
+
+  /**
+   * Get the number of emails in a specific queue.
+   *
+   * @param string $queue
+   *   The name of the queue to add the emails to.
+   *
+   * @return int
+   *   The number of messages found in the requested queue.
+   */
+  protected function getQueueCount($queue = 'smtp_send_queue') {
+    return db_query("SELECT count('name') FROM {queue} WHERE name = :queue",
+      array(':queue' => $queue))
+      ->fetchField();
+  }
+
+}

+ 12 - 0
sites/all/modules/contrib/mail/smtp/tests/smtp_tests.info

@@ -0,0 +1,12 @@
+name = SMTP tests
+description = Contains helper logic for the SMTP tests.
+package = Mail
+core = 7.x
+hidden = TRUE
+
+; Information added by Drupal.org packaging script on 2017-06-27
+version = "7.x-1.7"
+core = "7.x"
+project = "smtp"
+datestamp = "1498593247"
+

+ 16 - 0
sites/all/modules/contrib/mail/smtp/tests/smtp_tests.module

@@ -0,0 +1,16 @@
+<?php
+/**
+ * @file
+ * Primary hook implementations for the SMTP test helper module.
+ */
+
+/**
+ * Implements hook_mail().
+ */
+function smtp_tests_mail($key, &$message, $params) {
+  // A very rudimentary test.
+  if ($key == 'smtp_basic_test') {
+    $message['subject'] = t('Test email subject');
+    $message['body'][] = t('Test email body.');
+  }
+}