Index: database/updates.inc =================================================================== --- database/updates.inc +++ database/updates.inc @@ -2071,3 +2071,50 @@ return $ret; } +function system_update_186() { + $ret = array(); + switch ($GLOBALS['db_type']) { + case 'mysqli': + case 'mysql': + $ret[] = update_sql("CREATE TABLE mail_queue ( + mid int(11) NOT NULL auto_increment, + timestamp int(11) NOT NULL default '0', + body longtext NOT NULL, + headers longtext NOT NULL, + subject varchar(255) NOT NULL default '', + parameters varchar(255) NOT NULL default '', + PRIMARY KEY (mid) + )"); + $ret[] = update_sql("CREATE TABLE mail_queue_addresses ( + aid int(11) unsigned NOT NULL auto_increment, + mid int(11) unsigned NOT NULL default '0', + address varchar(255) NOT NULL default '', + sent int(1) NOT NULL default '0', + PRIMARY KEY (aid), + KEY (mid) + )"); + break; + case 'pgsql': + $ret[] = update_sql("CREATE TABLE mail_queue ( + mid SERIAL, + timestamp int NOT NULL default '0', + body text NOT NULL default '', + headers text NOT NULL default '', + subject varchar(255) NOT NULL default '', + parameters varchar(255) NOT NULL default '', + PRIMARY KEY (mid) + )"); + $ret[] = update_sql("CREATE TABLE mail_queue_addresses ( + aid SERIAL, + mid int NOT NULL default '0', + address varchar(255) NOT NULL default '', + sent int NOT NULL default '0', + PRIMARY KEY (aid) + )"); + $ret[] = update_sql("CREATE INDEX mail_queue_addresses_mid_idx on mail_queue_addresses(mid)"); + break; + default: + break; + } + return $ret; +} Index: modules/contact.module =================================================================== --- modules/contact.module +++ modules/contact.module @@ -394,11 +394,11 @@ $body = implode("\n\n", $message); // Send the e-mail: - user_mail($to, $subject, $body, "From: $from\nReply-to: $from\nX-Mailer: Drupal\nReturn-path: $from\nErrors-to: $from"); + drupal_mail($to, $subject, $body, array('From' => $from, 'Reply-To' => $from, 'Return-Path' => $from, 'Errors-To' => $from)); // Send a copy if requested: if ($edit['copy']) { - user_mail($from, $subject, $body, "From: $from\nReply-to: $from\nX-Mailer: Drupal\nReturn-path: $from\nErrors-to: $from"); + drupal_mail($from, $subject, $body, array('From' => $from, 'Reply-To' => $from, 'Return-Path' => $from, 'Errors-To' => $from)); } // Log the operation: @@ -535,16 +535,16 @@ $body = implode("\n\n", $message); // Send the e-mail to the recipients: - user_mail($contact->recipients, $subject, $body, "From: $from\nReply-to: $from\nX-Mailer: Drupal\nReturn-path: $from\nErrors-to: $from"); + drupal_mail($contact->recipients, $subject, $body, array('From' => $from, 'Reply-To' => $from, 'Return-Path' => $from, 'Errors-To' => $from)); // If the user requests it, send a copy. if ($edit['copy']) { - user_mail($from, $subject, $body, "From: $from\nReply-to: $from\nX-Mailer: Drupal\nReturn-path: $from\nErrors-to: $from"); + drupal_mail($from, $subject, $body, array('From' => $from, 'Reply-To' => $from, 'Return-Path' => $from, 'Errors-To' => $from)); } // Send an auto-reply if necessary: if ($contact->reply) { - user_mail($from, $subject, wordwrap($contact->reply), "From: $contact->recipients\nReply-to: $contact->recipients\nX-Mailer: Drupal\nReturn-path: $contact->recipients\nErrors-to: $contact->recipients"); + drupal_mail($from, $subject, wordwrap($contact->reply), array('From' => $contact->recipients, 'Reply-To' => $contact->recipients, 'Return-Path' => $contact->recipients, 'Errors-To' => $contact->recipients)); } // Log the operation: Index: modules/user.module =================================================================== --- modules/user.module +++ modules/user.module @@ -377,44 +377,6 @@ return $deny && !$allow; } -/** - * Send an e-mail message. - */ -function user_mail($mail, $subject, $message, $header) { - if (variable_get('smtp_library', '') && file_exists(variable_get('smtp_library', ''))) { - include_once './' . variable_get('smtp_library', ''); - return user_mail_wrapper($mail, $subject, $message, $header); - } - else { - /* - ** Note: if you are having problems with sending mail, or mails look wrong - ** when they are received you may have to modify the str_replace to suit - ** your systems. - ** - \r\n will work under dos and windows. - ** - \n will work for linux, unix and BSDs. - ** - \r will work for macs. - ** - ** According to RFC 2646, it's quite rude to not wrap your e-mails: - ** - ** "The Text/Plain media type is the lowest common denominator of - ** Internet e-mail, with lines of no more than 997 characters (by - ** convention usually no more than 80), and where the CRLF sequence - ** represents a line break [MIME-IMT]." - ** - ** CRLF === \r\n - ** - ** http://www.rfc-editor.org/rfc/rfc2646.txt - ** - */ - return mail( - $mail, - mime_header_encode($subject), - str_replace("\r", '', $message), - "MIME-Version: 1.0\nContent-Type: text/plain; charset=UTF-8; format=flowed\nContent-transfer-encoding: 8Bit\n" . $header - ); - } -} - function user_fields() { static $fields; @@ -1062,8 +1024,7 @@ $variables = array('%username' => $account->name, '%site' => variable_get('site_name', 'drupal'), '%login_url' => user_pass_reset_url($account), '%uri' => $base_url, '%uri_brief' => substr($base_url, strlen('http://')), '%mailto' => $account->mail, '%date' => format_date(time()), '%login_uri' => url('user', NULL, NULL, TRUE), '%edit_uri' => url('user/'. $account->uid .'/edit', NULL, NULL, TRUE)); $subject = _user_mail_text('pass_subject', $variables); $body = _user_mail_text('pass_body', $variables); - $headers = "From: $from\nReply-to: $from\nX-Mailer: Drupal\nReturn-path: $from\nErrors-to: $from"; - $mail_success = user_mail($account->mail, $subject, $body, $headers); + $mail_success = drupal_mail($account->mail, $subject, $body); if ($mail_success) { watchdog('user', t('Password reset instructions mailed to %name at %email.', array('%name' => ''. $account->name .'', '%email' => ''. $account->mail .''))); @@ -1224,7 +1185,6 @@ $name = $form_values['name']; $pass = $admin ? $form_values['pass'] : user_password(); $notify = $form_values['notify']; - $from = variable_get('site_mail', ini_get('sendmail_from')); if (!$admin && array_intersect(array_keys($form_values), array('uid', 'roles', 'init', 'session', 'status'))) { watchdog('security', t('Detected malicious attempt to alter protected user fields.'), WATCHDOG_WARNING); @@ -1238,7 +1198,7 @@ // The first user may login immediately, and receives a customized welcome e-mail. if ($account->uid == 1) { - user_mail($mail, t('Drupal user account details for %s', array('%s' => $name)), strtr(t("%username,\n\nYou may now login to %uri using the following username and password:\n\n username: %username\n password: %password\n\n%edit_uri\n\n--drupal"), $variables), "From: $from\nReply-to: $from\nX-Mailer: Drupal\nReturn-path: $from\nErrors-to: $from"); + drupal_mail($mail, t('Drupal user account details for %s', array('%s' => $name)), strtr(t("%username,\n\nYou may now login to %uri using the following username and password:\n\n username: %username\n password: %password\n\n%edit_uri\n\n--drupal"), $variables)); drupal_set_message(t('

Welcome to Drupal. You are user #1, which gives you full and immediate access. All future registrants will receive their passwords via e-mail, so please make sure your website e-mail address is set properly under the general settings on the settings page.

Your password is %pass. You may change your password below.

', array('%pass' => $pass, '%settings' => url('admin/settings')))); user_authenticate($account->name, trim($pass)); @@ -1257,8 +1217,8 @@ $subject = $notify ? _user_mail_text('admin_subject', $variables) : _user_mail_text('welcome_subject', $variables); $body = $notify ? _user_mail_text('admin_body', $variables) : _user_mail_text('welcome_body', $variables); - user_mail($mail, $subject, $body, "From: $from\nReply-to: $from\nX-Mailer: Drupal\nReturn-path: $from\nErrors-to: $from"); - + drupal_mail($mail, $subject, $body); + if ($notify) { drupal_set_message(t('Password and further instructions have been e-mailed to the new user %user.', array('%user' => theme('placeholder', $name)))); } @@ -1272,8 +1232,8 @@ $subject = _user_mail_text('approval_subject', $variables); $body = _user_mail_text('approval_body', $variables); - user_mail($mail, $subject, $body, "From: $from\nReply-to: $from\nX-Mailer: Drupal\nReturn-path: $from\nErrors-to: $from"); - user_mail(variable_get('site_mail', ini_get('sendmail_from')), $subject, t("%u has applied for an account.\n\n%uri", array('%u' => $account->name, '%uri' => url("user/$account->uid/edit", NULL, NULL, TRUE))), "From: $from\nReply-to: $from\nX-Mailer: Drupal\nReturn-path: $from\nErrors-to: $from"); + drupal_mail($mail, $subject, $body); + drupal_mail(variable_get('site_mail', ini_get('sendmail_from')), $subject, t("%u has applied for an account.\n\n%uri", array('%u' => $account->name, '%uri' => url("user/$account->uid/edit", NULL, NULL, TRUE)))); drupal_set_message(t('Thank you for applying for an account. Your account is currently pending approval by the site administrator.
In the meantime, your password and further instructions have been sent to your e-mail address.')); } Index: modules/system.module =================================================================== --- modules/system.module +++ modules/system.module @@ -234,6 +234,19 @@ return $output; } +/** + * Implementation of hook_cron(). + */ +function system_cron() { + if (variable_get('mailengine', 'system') == 'system') { + include_once './includes/mail.inc'; + //send queued mail + mail_queue_send(); + //remove completed messages. + mail_queue_clean(); + } +} + function _system_zonelist() { $timestamp = time(); $zonelist = array(-11, -10, -9.5, -9, -8, -7, -6, -5, -4, -3.5, -3, -2, -1, 0, 1, 2, 3, 3.5, 4, 5, 5.5, 5.75, 6, 6.5, 7, 8, 9, 9.5, 10, 10.5, 11, 11.5, 12, 12.75, 13, 14); @@ -255,10 +268,6 @@ '#type' => 'textfield', '#title' => t('Name'), '#default_value' => variable_get('site_name', 'drupal'), '#description' => t('The name of this web site.'), '#required' => TRUE ); - $form['general']['site_mail'] = array( - '#type' => 'textfield', '#title' => t('E-mail address'), '#default_value' => variable_get('site_mail', ini_get('sendmail_from')), - '#description' => t('A valid e-mail address for this website, used by the auto-mailer during registration, new password requests, notifications, etc.') - ); $form['general']['site_slogan'] = array( '#type' => 'textfield', '#title' => t('Slogan'), '#default_value' => variable_get('site_slogan', ''), '#description' => t('The slogan of this website. Some themes display a slogan when available.') @@ -301,6 +310,24 @@ } } + // Mail sending + include_once './includes/mail.inc'; + $form['mail'] = array( '#type' => 'fieldset', '#title' => t('Mail handling'), '#collapsible' => TRUE, '#collapsed' => TRUE ); + $form['mail']['site_mail'] = array( + '#type' => 'textfield', '#title' => t('E-mail address'), '#default_value' => variable_get('site_mail', ini_get('sendmail_from')), '#maxlength' => 128, + '#description' => t('A valid e-mail address for this website, used by the auto-mailer during registration, new password requests, notifications, etc.') + ); + $choices = mail_get_engines(); + $form['mail']['mail_engine'] = array('#type' => 'select', '#title' => t('E-mail engine'), '#default_value' => variable_get('mail_engine', 'mail'), '#options' => $choices, '#description' => t('Choose an e-mail engine for sending mails from your site.')); + + if (variable_get('mail_engine', 0)) { + $form['mail']['mail_engine_settings'] = array('#type' => 'fieldset', '#title' => t('Engine specific settings')); + $form['mail']['mail_engine_settings'] = array_merge($form['mail_engine_settings'], module_invoke(variable_get('mail_engine', 'mail'), 'mailengine', 'settings')); + } + else { + drupal_set_message(t('Please choose a mail engine.'), 'error'); + } + // Error handling: $form['errors'] = array( '#type' => 'fieldset', '#title' =>t('Error handling'), '#collapsible' => TRUE, '#collapsed' => TRUE ); @@ -1270,3 +1297,112 @@ $form['actions']['cancel'] = array('#value' => l($no ? $no : t('Cancel'), $path)); return drupal_get_form($form_id, $form, 'confirm_form'); } + +/** + * PHP mail function wrapper. + * + * @param $address + * Envelope address. For multiple mails use an array. + * @param $subject + * Mail subject + * @param $body + * Mail body. + * @param $additional_headers + * Additional mail headers, an optional array + * @param $additional_parameters + * Additional mail parameters, passed to MTA, optional array + * @return + * result of mail() + */ +function drupal_mail($address, $subject, $body, $additional_headers = array(), $additional_parameters = NULL) { + include_once './includes/mail.inc'; + $message = array(); + $message['address'] = $address; + $message['subject'] = $subject; + $message['body'] = $body; + $message['headers'] = $additional_headers; + $message['parameters'] = $additional_parameters; + + $engine = variable_get('mailengine', 'system') .'_mailengine'; + if (!function_exists($engine)) { + return FALSE; + } + if (is_string($address)) { + $status = $engine('single', $message); + } + elseif (is_array($address)) { + $status = $engine('multiple', $message); + } + + return $status; +} + +function system_mailengine($op, $message = array()) { + include_once './includes/mail.inc'; + switch ($op) { + case 'name': + return 'Drupal'; + break; + case 'description': + return t("Lightweight mailing engine with a simple queue. Uses PHP's mail()."); + break; + case 'settings': + $unsent_mails = db_result(db_query('SELECT COUNT(mid) FROM {mail_queue_addresses} WHERE sent = 0')); + + $form['name'] = array('#type' => 'item', '#title' => t('Mail engine'), '#value' => 'Drupal'); + $form['queue_status'] = array('#type' => 'item', '#title' => t('Queue status'), '#value' => format_plural($unsent_mails, 'There is one unsent e-mail in the queue.', 'There are %count unsent e-mails in the queue.')); + $form['last_sent'] = array('#type' => 'item', '#title' => t('Last sent'), '#value' => variable_get('mail_queue_last_sent', 0) ? format_date(variable_get('mail_queue_last_sent', 0), 'medium') : t('Never'), '#description' => t('Date when e-mail from the e-mail queue was last sent.')); + $throttle = array(0, 50, 100, 200, 500, 1000, 2000, 5000, 10000); + $throttle[0] = t('none'); + $throttle['1000000000'] = t('No limit'); // Well, technically it is a limit. + $form['mail_queue_throttle'] = array('#type' => 'select', '#title' => t('E-mail queue throttle'), '#default_value' => variable_get('mail_queue_throttle', 100), '#options' => $throttle, '#description' => t('How many e-mails do you want to send per hour? Requires crontab. Note that Drupal can not guarantee that the chosen number of e-mails gets sent.')); + return $form; + break; + case 'single': // send a single mail with some formatting of headers and body. + /* + ** Note: if you are having problems with sending mail, or mails look wrong + ** when they are received you may have to modify the str_replace to suit + ** your systems. + ** - \r\n will work under dos and windows. + ** - \n will work for linux, unix and BSDs. + ** - \r will work for macs. + ** + ** According to RFC 2646, it's quite rude to not wrap your e-mails: + ** + ** "The Text/Plain media type is the lowest common denominator of + ** Internet email, with lines of no more than 997 characters (by + ** convention usually no more than 80), and where the CRLF sequence + ** represents a line break [MIME-IMT]." + ** + ** CRLF === \r\n + ** + ** http://www.rfc-editor.org/rfc/rfc2646.txt + ** + */ + $message['headers'] = mail_prepare_headers($message['headers']); + // We strip newlines to prevent spam attacks + $message['address'] = mime_header_encode(strtr($message['address'], "\r\n", ' ')); + $message['subject'] = mime_header_encode(strtr($message['subject'], "\r\n", ' ')); + // We make sure the body contains the correct CRLF sequence + $message['body'] = str_replace("\r\r\n", "\r\n", str_replace("\n", "\r\n", $message['body'])); + case 'send as is': // no formatting whatsoever + $status = mail( + $message['address'], + $message['subject'], + $message['body'], + $message['headers'], + $message['parameters'] + ); + if (!$status) { + watchdog('mail', t('Mail %subject to %address failed.', array('%subject' => theme('placeholder', $subject), '%address' => theme('placeholder', $address))), WATCHDOG_ERROR); + } + return $status; + break; + case 'multiple': // send multiple mails + mail_queue($message['address'], $message['subject'], $message['body'], $message['headers'], $message['parameters']); + break; + default: // method not implemented. + return FALSE; + break; + } +} \ No newline at end of file