Index: includes/common.inc
===================================================================
RCS file: /cvs/drupal/drupal/includes/common.inc,v
retrieving revision 1.542
diff -u -F^f -r1.542 common.inc
--- includes/common.inc	8 Jun 2006 21:23:40 -0000	1.542
+++ includes/common.inc	2 Jul 2006 01:35:24 -0000
@@ -1391,3 +1391,64 @@ function page_set_cache() {
     }
   }
 }
+
+/**
+ * Send an e-mail message.
+ *
+ * @param $mail
+ *   Associative array: to, subject and body (string); headers (associative array)
+ */
+function drupal_mail($mail) {
+  $headers = array(
+    'MIME-Version' => '1.0',
+    'Content-Type' => 'text/plain; charset=UTF-8; format=flowed',
+    'Content-Transfer-Encoding' => '8Bit',
+    'X-Mailer' => 'Drupal'
+  );
+  if (isset($mail['from'])) {
+    $headers = array_merge($headers, array('From' => $mail['from'], 'Reply-To' => $mail['from'], 'Return-Path' => $mail['from'], 'Errors-To' => $mail['from']));
+  }
+  $mail['headers'] = array_merge($headers, isset($mail['headers']) ? $mail['headers'] : array());
+  // Custom hook traversal to allow pass by reference
+  foreach (module_implements('mail_alter') AS $module) {
+    $function = $module .'_mail_alter';
+    $function($mail);
+  }
+  // Allow for custom mail backend
+  if (variable_get('smtp_library', '') && file_exists(variable_get('smtp_library', ''))) {
+    include_once './' . variable_get('smtp_library', '');
+    return drupal_mail_wrapper($mail);
+  }
+  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
+    **
+    */
+    $headers = array();
+    foreach ($mail['headers'] as $name => $value) {
+      $headers[] = $name .': '. mime_header_encode($value);
+    }
+    return mail(
+      $mail['to'],
+      mime_header_encode($mail['subject']),
+      str_replace("\r", '', $mail['body']),
+      join("\n", $headers)
+    );
+  }
+}
Index: modules/contact.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/contact.module,v
retrieving revision 1.55
diff -u -F^f -r1.55 contact.module
--- modules/contact.module	28 Jun 2006 21:47:03 -0000	1.55
+++ modules/contact.module	2 Jul 2006 01:35:29 -0000
@@ -396,11 +396,23 @@ function contact_mail_user_submit($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(array(
+    'mail-id' => 'contact-user-mail',
+    'to' => $to,
+    'subject' => $subject,
+    'body' => $body,
+    'from' => $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(array(
+      'mail-id' => 'contact-user-copy',
+      'to' => $from,
+      'subject' => $subject,
+      'body' => $body,
+      'from' => $from,
+    ));
   }
 
   // Log the operation:
@@ -537,16 +549,34 @@ function contact_mail_page_submit($form_
   $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(array(
+    'mail-id' => 'contact-page-mail',
+    'to' => $contact->recipients,
+    'subject' => $subject,
+    'body' => $body,
+    'from' => $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(array(
+      'mail-id' => 'contact-page-copy',
+      'to' => $from,
+      'subject' => $subject,
+      'body' => $body,
+      'from' => $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(array(
+      'mail-id' => 'contact-page-autoreply',
+      'to' => $from,
+      'subject' => $subject,
+      'body' => wordwrap($contact->reply),
+      'from' => $contact->recipients,
+    ));
   }
 
   // Log the operation:
Index: modules/user.module
===================================================================
RCS file: /cvs/drupal/drupal/modules/user.module,v
retrieving revision 1.632
diff -u -F^f -r1.632 user.module
--- modules/user.module	23 Jun 2006 07:06:17 -0000	1.632
+++ modules/user.module	2 Jul 2006 01:35:54 -0000
@@ -381,44 +381,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 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;
 
@@ -1066,8 +1028,13 @@ function user_pass_submit($form_id, $for
   $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(array(
+    'mail-id' => 'user-pass',
+    'to' => $account->mail,
+    'subject' => $subject,
+    'body' => $body,
+    'from' => $from,
+  ));
 
   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>')));
@@ -1256,8 +1223,15 @@ function user_register_submit($form_id, 
 
   // 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_set_message(t('<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 make sure your website e-mail address is set properly under the general settings on the <a href="%settings">settings page</a>.</p><p> Your password is <strong>%pass</strong>. You may change your password below.</p>', array('%pass' => $pass, '%settings' => url('admin/settings'))));
+    drupal_mail(array(
+      'mail-id' => 'user-register-admin',
+      'to' => $mail,
+      'subject' => t('Drupal user account details for %s', array('%s' => $name)),
+      'body' => 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,
+    ));
+    drupal_set_message(t('<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 make sure your website e-mail address is set properly under the general settings on the <a href="%settings">settings page</a>.</p><p> Your password is <strong>%pass</strong>. You may change your password below.</p>', array('%pass' => $pass, '%settings' => url('admin/settings'))
+    ));
     user_authenticate($account->name, trim($pass));
 
     // Set the installed schema version of the system module to the most recent version.
@@ -1275,7 +1249,13 @@ function user_register_submit($form_id, 
       $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(array(
+        'mail-id' => ($notify ? 'user-register-notify' : 'user-register-welcome'),
+        'to' => $mail,
+        'subject' => $subject,
+        'body' => $body,
+        'from' => $from,
+      ));
 
       if ($notify) {
         drupal_set_message(t('Password and further instructions have been e-mailed to the new user %user.', array('%user' => theme('placeholder', $name))));
@@ -1290,8 +1270,20 @@ function user_register_submit($form_id, 
       $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(array(
+        'mail-id' => 'user-register-approval-user',
+        'to' => $mail,
+        'subject' => $subject,
+        'body' => $body,
+        'from' => $from,
+      ));
+      drupal_mail(array(
+        'mail-id' => 'user-register-approval-admin',
+        'to' => $from,
+        'subject' => $subject,
+        'body' => 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,
+      ));
       drupal_set_message(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.'));
 
     }
