Index: modules/contact.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/contact.module,v
retrieving revision 1.26
diff -u -p -r1.26 contact.module
--- modules/contact.module	11 Oct 2005 19:44:34 -0000	1.26
+++ modules/contact.module	31 Oct 2005 09:52:25 -0000
@@ -146,11 +146,11 @@ function contact_user_mail_execute($form
   $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:
@@ -301,16 +301,16 @@ function contact_mail_page_execute($form
   $contact = db_fetch_object(db_query("SELECT * FROM {contact} WHERE category = '%s'", $edit['category']));
 
   // 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/system.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/system.module,v
retrieving revision 1.247
diff -u -p -r1.247 system.module
--- modules/system.module	26 Oct 2005 01:24:09 -0000	1.247
+++ modules/system.module	31 Oct 2005 09:52:25 -0000
@@ -211,6 +211,19 @@ function theme_system_user($form) {
   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);
@@ -232,10 +245,6 @@ function system_view_general() {
     '#type' => 'textfield', '#title' => t('Name'), '#default_value' => variable_get('site_name', 'drupal'),
     '#description' => t('The name of this web site.')
   );
-  $form['general']['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.')
-  );
   $form['general']['site_slogan'] = array(
     '#type' => 'textfield', '#title' => t('Slogan'), '#default_value' => variable_get('site_slogan', ''),
     '#maxlength' => 128, '#description' => t('The slogan of this website. Some themes display a slogan when available.')
@@ -269,6 +278,24 @@ function system_view_general() {
   // We will use a random URL so there is no way a proxy or a browser could cache the "no such image" answer.
   $form['general']['clean_url_test'] = array('#type' => 'markup', '#value' => '<img style="position: relative; left: -1000em;" src="'. $base_url. '/system/test/'. user_password(20) .'.png" alt="" />');
 
+  // 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 );
@@ -1231,3 +1258,112 @@ function confirm_form($form_id, $form, $
   $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 './include/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;
+  }
+}
Index: modules/user.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/user.module,v
retrieving revision 1.524
diff -u -p -r1.524 user.module
--- modules/user.module	28 Oct 2005 00:37:06 -0000	1.524
+++ modules/user.module	31 Oct 2005 09:52:25 -0000
@@ -365,44 +365,6 @@ function user_is_blocked($name) {
   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 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
-    **
-    */
-    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;
 
@@ -978,8 +940,7 @@ function user_pass() {
     $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' => '<em>'. $account->name .'</em>', '%email' => '<em>'. $account->mail .'</em>')));
@@ -1067,7 +1028,6 @@ function user_register($edit = array()) 
     user_module_invoke('validate', $edit, $edit, 'account');
 
     if (!form_get_errors()) {
-      $from = variable_get('site_mail', ini_get('sendmail_from'));
       $pass = $admin ? $edit['pass'] : user_password();
 
       // TODO: Is this necessary? Won't session_write() replicate this?
@@ -1083,7 +1043,7 @@ function user_register($edit = array()) 
 
       // The first user may login immediately, and receives a customized welcome e-mail.
       if ($account->uid == 1) {
-        user_mail($edit['mail'], t('drupal user account details for %s', array('%s' => $edit['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($edit['mail'], t('drupal user account details for %s', array('%s' => $edit['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));
         // This should not be t()'ed. No point as its only shown once in the sites lifetime, and it would be bad to store the password.
         $form['instructions'] = array('#type' => 'markup', '#value' => "<p>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 configure your e-mail settings using the Administration pages.</p><p> Your password is <strong>$pass</strong>. You may change your password on the next page.</p><p>Please login below.</p>");
         $form['#action'] = url('user', 'destination=user/1/edit');
@@ -1102,7 +1062,7 @@ function user_register($edit = array()) 
           // Create new user account, no administrator approval required.
           $subject = _user_mail_text('welcome_subject', $variables);
           $body = _user_mail_text('welcome_body', $variables);
-          user_mail($edit['mail'], $subject, $body, "From: $from\nReply-to: $from\nX-Mailer: Drupal\nReturn-path: $from\nErrors-to: $from");
+          drupal_mail($edit['mail'], $subject, $body);
           return t('Your password and further instructions have been sent to your e-mail address.');
         }
         else {
@@ -1110,8 +1070,8 @@ function user_register($edit = array()) 
           $subject = _user_mail_text('approval_subject', $variables);
           $body = _user_mail_text('approval_body', $variables);
 
-          user_mail($edit['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($edit['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))));
           return t('Thank you for applying for an account. Your account is currently pending approval by the site administrator.<br />In the meantime, your password and further instructions have been sent to your e-mail address.');
         }
       }
