diff --git a/includes/phpmailer.class.inc b/includes/phpmailer.class.inc index 63fab4c..d482d31 100644 --- a/includes/phpmailer.class.inc +++ b/includes/phpmailer.class.inc @@ -9,7 +9,7 @@ * Base PHPMailer for Drupal implementation with support for SMTP keep-alive * and setting a custom Return-Path. */ -class DrupalPHPMailer extends PHPMailer { +class DrupalPHPMailer extends PHPMailer implements MailSystemInterface { /** * Stores the Return-Path, which may be different from Sender. */ @@ -43,7 +43,7 @@ class DrupalPHPMailer extends PHPMailer { $this->SMTPDebug = variable_get('smtp_debug', 0); // Adjust path to SMTP class. - $this->PluginDir = './'. phpmailer_get_path() .'/'; + $this->PluginDir = DRUPAL_ROOT . '/' . libraries_get_path('phpmailer') . '/'; } /** @@ -180,5 +180,150 @@ class DrupalPHPMailer extends PHPMailer { return $result; } + + /** + * Format a message composed by drupal_mail() prior sending. + * + * @param $message + * A message array, as described in hook_mail_alter(). + * + * @return + * The formatted $message. + */ + public function format(array $message) { + $body = $message['body']; + $message['body'] = ''; + foreach ($body as $b) { + $message['body'] .= $b . "\n"; + } + return $message; + } + + /** + * Send a message composed by drupal_mail(). + * + * @param $message + * Message array with at least the following elements: + * - id: A unique identifier of the e-mail type. Examples: 'contact_user_copy', + * 'user_password_reset'. + * - to: The mail address or addresses where the message will be sent to. + * The formatting of this string must comply with RFC 2822. Some examples: + * - user@example.com + * - user@example.com, anotheruser@example.com + * - User + * - User , Another User + * - subject: Subject of the e-mail to be sent. This must not contain any + * newline characters, or the mail may not be sent properly. + * - body: Message to be sent. Accepts both CRLF and LF line-endings. + * E-mail bodies must be wrapped. You can use drupal_wrap_mail() for + * smart plain text wrapping. + * - headers: Associative array containing all additional mail headers not + * defined by one of the other parameters. PHP's mail() looks for Cc + * and Bcc headers and sends the mail to addresses in these headers too. + * @return + * TRUE if the mail was successfully accepted for delivery, otherwise FALSE. + */ + public function mail(array $message) { + try { + // Parse 'From' e-mail address. + $from = reset(phpmailer_parse_address($message['from'])); + $this->From = $from['mail']; + if ($from['name'] != '') { + $this->FromName = $from['name']; + } + unset($message['headers']['From']); + + if (variable_get('phpmailer_debug_email', '') === '') { + // Set recipients. + foreach (phpmailer_parse_address($message['to']) as $address) { + $this->AddAddress($address['mail'], $address['name']); + } + // Extract CCs and BCCs from headers. + if (isset($message['headers']['CC'])) { + foreach (phpmailer_parse_address($message['headers']['CC']) as $address) { + $this->AddCC($address['mail'], $address['name']); + } + } + if (isset($message['headers']['BCC'])) { + foreach (phpmailer_parse_address($message['headers']['BCC']) as $address) { + $this->AddBCC($address['mail'], $address['name']); + } + } + } + else { + // Reroute to debug e-mail address. + $this->AddAddress(variable_get('phpmailer_debug_email', '')); + } + unset($message['headers']['CC'], $message['headers']['BCC']); + + // Extract Reply-To from headers. + if (isset($message['headers']['Reply-To'])) { + foreach (phpmailer_parse_address($message['headers']['Reply-To']) as $address) { + $this->AddReplyTo($address['mail'], $address['name']); + } + unset($message['headers']['Reply-To']); + } + elseif (variable_get('smtp_always_replyto', FALSE)) { + // If no Reply-To header has been explicitly set, use the From address to + // be able to respond to e-mails sent via Google Mail. + $this->AddReplyTo($from['mail'], $from['name']); + } + + // Extract Content-Type and charset. + if (isset($message['headers']['Content-Type'])) { + $content_type = explode(';', $message['headers']['Content-Type']); + $this->ContentType = trim(array_shift($content_type)); + foreach ($content_type as $param) { + $param = explode('=', $param, 2); + $key = trim($param[0]); + if ($key == 'charset') { + $this->CharSet = trim($param[1]); + } + else { + $this->ContentType .= '; ' . $key . '=' . trim($param[1]); + } + } + unset($message['headers']['Content-Type']); + } + + // Set additional properties. + $properties = array( + 'X-Priority' => 'Priority', + 'Content-Transfer-Encoding' => 'Encoding', + 'Sender' => 'Sender', + 'Message-ID' => 'MessageID', + // Custom property. + // @see DrupalPHPMailer::CreateHeader() + 'Return-Path' => 'ReturnPath', + ); + foreach ($properties as $source => $property) { + if (isset($message['headers'][$source])) { + $this->$property = $message['headers'][$source]; + unset($message['headers'][$source]); + } + } + + // This one is always set by PHPMailer. + unset($message['headers']['MIME-Version']); + + // Add remaining header lines. + // Note: Any header lines MUST already be checked by the caller for unwanted + // newline characters to avoid header injection. + // @see PHPMailer::SecureHeader() + foreach ($message['headers'] as $key => $value) { + $this->AddCustomHeader("$key:$value"); + } + + $this->Subject = $message['subject']; + $this->Body = $message['body']; + + return $this->send(); + } + catch (phpmailerException $e) { + drupal_set_message(t('Sending of at least one e-mail failed. The error returned was:
@error.', array('@error' => $e->getMessage())), 'error'); + watchdog('phpmailer', $e->getMessage(), NULL, WATCHDOG_ERROR); + return FALSE; + } + } } diff --git a/includes/phpmailer.drupal.inc b/includes/phpmailer.drupal.inc index 0b91d5b..db16f4f 100644 --- a/includes/phpmailer.drupal.inc +++ b/includes/phpmailer.drupal.inc @@ -15,9 +15,6 @@ function phpmailer_send($message) { static $mail; if (!isset($mail)) { - if (!phpmailer_load_library()) { - return FALSE; - } $mail = new DrupalPHPMailer(); } diff --git a/includes/phpmailer.mimemail.inc b/includes/phpmailer.mimemail.inc index f52ad98..fa059ba 100644 --- a/includes/phpmailer.mimemail.inc +++ b/includes/phpmailer.mimemail.inc @@ -15,9 +15,6 @@ function mimemail_phpmailer_send($message) { static $mail; if (!isset($mail)) { - if (!phpmailer_load_library()) { - return FALSE; - } $mail = new DrupalPHPMailer(); // Keep linefeed style in sync. $mail->LE = variable_get('mimemail_crlf', "\n"); diff --git a/phpmailer.admin.inc b/phpmailer.admin.inc index 903330a..861f795 100644 --- a/phpmailer.admin.inc +++ b/phpmailer.admin.inc @@ -24,7 +24,7 @@ function phpmailer_settings_form($form_state) { if (module_exists('mimemail') && variable_get('mimemail_alter', 0)) { $form['smtp_on']['#disabled'] = TRUE; $form['smtp_on']['#default_value'] = 0; - $form['smtp_on']['#description'] = t('MimeMail has been detected. To enable PHPMailer for mail transport, go to the MimeMail settings page and select PHPMailer from the available e-mail engines.', array('@url' => url('admin/settings/mimemail'))); + $form['smtp_on']['#description'] = t('MimeMail has been detected. To enable PHPMailer for mail transport, go to the MimeMail settings page and select PHPMailer from the available e-mail engines.', array('@url' => url('admin/config/system/mimemail'))); } elseif (!variable_get('smtp_on', 0) && empty($form_state['post']['smtp_on'])) { drupal_set_message(t('PHPMailer is currently disabled.'), 'warning'); @@ -181,12 +181,20 @@ function phpmailer_settings_form_submit($form, &$form_state) { // Enable/disable mail sending subsystem. if ($form_state['values']['smtp_on']) { if (!phpmailer_enabled()) { + $mail_system = variable_get('mail_system', array('default-system' => 'DefaultMailSystem')); + $mail_system['default-system'] = 'DrupalPHPMailer'; + variable_set('mail_system', $mail_system); + variable_set('smtp_library', drupal_get_filename('module', 'phpmailer')); drupal_set_message(t('PHPMailer will be used to deliver all site e-mails.')); watchdog('phpmailer', 'PHPMailer has been enabled.'); } } else if (phpmailer_enabled()) { + $mail_system = variable_get('mail_system', array('default-system' => 'DefaultMailSystem')); + $mail_system['default-system'] = 'DefaultMailSystem'; + variable_set('mail_system', $mail_system); + variable_del('smtp_library'); drupal_set_message(t('PHPMailer has been disabled.')); watchdog('phpmailer', 'PHPMailer has been disabled.'); diff --git a/phpmailer.info b/phpmailer.info index 79fd48d..0027892 100644 --- a/phpmailer.info +++ b/phpmailer.info @@ -2,4 +2,12 @@ name = PHPMailer description = Integrates the PHPMailer library for SMTP e-mail delivery. dependencies[] = libraries package = Mail -core = 6.x \ No newline at end of file +core = 7.x +configure = admin/config/system/phpmailer +files[] = includes/phpmailer.class.inc +files[] = includes/phpmailer.drupal.inc +files[] = includes/phpmailer.mimemail.inc +files[] = tests/phpmailer.test +; Libraries +;files[] = class.phpmailer.php +;files[] = class.smtp.php diff --git a/phpmailer.install b/phpmailer.install index b1e1806..7d9cca5 100644 --- a/phpmailer.install +++ b/phpmailer.install @@ -13,7 +13,7 @@ function phpmailer_requirements($phase) { // Ensure translations don't break at install time. $t = get_t(); - if ($phase == 'runtime' && phpmailer_load_library()) { + if ($phase == 'runtime' && phpmailer_library_exists()) { $mail = new PHPMailer(); $requirements['phpmailer'] = array( 'title' => $t('PHPMailer library'), @@ -24,7 +24,7 @@ function phpmailer_requirements($phase) { else { drupal_load('module', 'libraries'); $path = libraries_get_path('phpmailer'); - if (!file_exists('./' . $path . '/class.phpmailer.php') || !file_exists('./' . $path . '/class.smtp.php')) { + if (!file_exists(DRUPAL_ROOT . '/' . $path . '/class.phpmailer.php') || !file_exists(DRUPAL_ROOT . '/' . $path . '/class.smtp.php')) { $requirements['phpmailer'] = array( 'title' => $t('PHPMailer library'), 'value' => $t('Missing'), @@ -45,6 +45,10 @@ function phpmailer_requirements($phase) { * Implementation of hook_uninstall(). */ function phpmailer_uninstall() { + $mail_system = variable_get('mail_system', array('default-system' => 'DefaultMailSystem')); + $mail_system['default-system'] = 'DefaultMailSystem'; + variable_set('mail_system', $mail_system); + variable_del('smtp_on'); variable_del('smtp_host'); variable_del('smtp_hostbackup'); diff --git a/phpmailer.module b/phpmailer.module index 8ad2f2c..828b178 100644 --- a/phpmailer.module +++ b/phpmailer.module @@ -8,15 +8,20 @@ /** * Implementation of hook_perm(). */ -function phpmailer_perm() { - return array('administer phpmailer settings'); +function phpmailer_permission() { + return array( + 'administer phpmailer settings' => array( + 'title' => t('Administer PHPMailer settings'), + 'restrict access' => TRUE, + ), + ); } /** * Implementation of hook_menu(). */ function phpmailer_menu() { - $items['admin/settings/phpmailer'] = array( + $items['admin/config/system/phpmailer'] = array( 'title' => 'PHPMailer', 'description' => 'Configure PHPMailer settings.', 'page callback' => 'drupal_get_form', @@ -45,7 +50,7 @@ function phpmailer_form_mimemail_admin_settings_alter(&$form, &$form_state) { $mimemail_alter = &$form['mimemail']['mimemail_alter']; $mimemail_alter['#disabled'] = TRUE; $mimemail_alter['#default_value'] = 0; - $mimemail_alter['#description'] = t('PHPMailer has been set to deliver all site messages. To let Mime Mail apply styles and formatting to system e-mails but still use PHPMailer for mail transport, uncheck Use PHPMailer to send e-mails first on the PHPMailer settings page. Then activate this setting and choose PHPMailer from the list of e-mail engines below.', array('@url' => url('admin/settings/phpmailer'))); + $mimemail_alter['#description'] = t('PHPMailer has been set to deliver all site messages. To let Mime Mail apply styles and formatting to system e-mails but still use PHPMailer for mail transport, uncheck Use PHPMailer to send e-mails first on the PHPMailer settings page. Then activate this setting and choose PHPMailer from the list of e-mail engines below.', array('@url' => url('admin/config/system/phpmailer'))); } // @todo Move to MimeMail project. $form['preview'] = array( @@ -60,19 +65,10 @@ function phpmailer_form_mimemail_admin_settings_alter(&$form, &$form_state) { * Determine if PHPMailer is used to deliver e-mails. */ function phpmailer_enabled() { + // @todo return strpos(variable_get('smtp_library', ''), 'phpmailer'); } -if (phpmailer_enabled() && !function_exists('drupal_mail_wrapper')) { - /** - * Implementation of drupal_mail_wrapper(). - */ - function drupal_mail_wrapper($message) { - module_load_include('inc', 'phpmailer', 'includes/phpmailer.drupal'); - return phpmailer_send($message); - } -} - /** * Implementation of hook_mailengine(). */ @@ -85,7 +81,7 @@ function phpmailer_mailengine($op, $message = array()) { return t('Mailing engine using the PHPMailer library.'); case 'settings': - $form['info']['#value'] = t('To configure your mail server settings, visit the PHPMailer settings page.', array('@url' => url('admin/settings/phpmailer'))); + $form['info']['#value'] = t('To configure your mail server settings, visit the PHPMailer settings page.', array('@url' => url('admin/config/system/phpmailer'))); return $form; case 'multiple': @@ -174,7 +170,7 @@ function phpmailer_preview_access() { function phpmailer_enable() { if (!phpmailer_enabled() && !(module_exists('mimemail') && variable_get('mimemail_engine', 'mimemail') == 'phpmailer')) { $t = get_t(); - drupal_set_message($t('PHPMailer has been installed, but is currently disabled. Configure it now.', array('@settings-url' => url('admin/settings/phpmailer')))); + drupal_set_message($t('PHPMailer has been installed, but is currently disabled. Configure it now.', array('@settings-url' => url('admin/config/system/phpmailer')))); } } @@ -183,6 +179,10 @@ function phpmailer_enable() { */ function phpmailer_disable() { if (phpmailer_enabled()) { + $mail_system = variable_get('mail_system', array('default-system' => 'DefaultMailSystem')); + $mail_system['default-system'] = 'DefaultMailSystem'; + variable_set('mail_system', $mail_system); + variable_del('smtp_library'); variable_del('smtp_on'); drupal_set_message(t('PHPMailer has been disabled.')); @@ -194,34 +194,32 @@ function phpmailer_disable() { } /** - * Load PHPMailer class from libraries path. + * Implements hook_registry_files_alter(). + * + * @todo Consider to move this into Libraries API. */ -function phpmailer_load_library() { - if (!class_exists('PHPMailer')) { - if (!($library_path = phpmailer_get_path())) { - watchdog('phpmailer', 'Could not load PHPMailer library.', array(), WATCHDOG_ERROR); - return FALSE; - } - require_once './'. $library_path .'/class.phpmailer.php'; - } - if (!class_exists('DrupalPHPMailer')) { - module_load_include('inc', 'phpmailer', 'includes/phpmailer.class'); +function phpmailer_registry_files_alter(&$files, $modules) { + // @todo Not sure whether the registry breaks upon non-existing files. Ideally, + // the files should be registered, even if they do not exist (yet). + $library_path = libraries_get_path('phpmailer'); + foreach (array('class.phpmailer.php', 'class.pop3.php', 'class.smtp.php') as $filename) { + $files[$library_path . '/' . $filename] = array( + 'module' => 'phpmailer', + 'weight' => 0, + ); } - return TRUE; } /** - * Get path to PHPMailer library. + * Returns whether PHPMailer library files exist. */ -function phpmailer_get_path() { +function phpmailer_library_exists() { + $exists = FALSE; $library_path = libraries_get_path('phpmailer'); - if (!file_exists('./'. $library_path .'/class.phpmailer.php')) { - // Provide backwards compatibility for existing installations of - // PHPMailer module. - $library_path = drupal_get_path('module', 'phpmailer') .'/phpmailer'; - if (!file_exists('./'. $library_path .'/class.phpmailer.php')) { - return FALSE; + if ($library_path) { + foreach (array('class.phpmailer.php', 'class.pop3.php', 'class.smtp.php') as $filename) { + $exists = ($exists && file_exists(DRUPAL_ROOT . '/' . $library_path . '/' . $filename)); } } - return $library_path; + return $exists; }