diff --git a/includes/mail.inc b/includes/mail.inc index a97c788f..eacaaf69 100644 --- a/includes/mail.inc +++ b/includes/mail.inc @@ -111,7 +111,9 @@ define('MAIL_RFC_2822_SPECIALS', '()<>[]:;@\,."'); * @param $params * Optional parameters to build the e-mail. * @param $from - * Sets From to this value, if given. + * Sets the From header to this value, if the domain of the email provided + * matches the approved sending email address (site_mail). Sets the Reply-To + * header to this value if the domains do not match. * @param $send * If TRUE, drupal_mail() will call drupal_mail_system()->mail() to deliver * the message, and store the result in $message['result']. Modules @@ -162,6 +164,31 @@ function drupal_mail($module, $key, $to, $language, $params = array(), $from = N } if ($from && $from != $default_from) { $headers['From'] = $from; + // Check to see if the domain matches the specified sending email address. + $default_from_parts = explode('@', $default_from); + if (count($default_from_parts) == 2 && isset($default_from_parts[1]) && + stripos($from, '@' . $default_from_parts[1]) === FALSE) { + + // If domain does not match set Reply-To to From, and reformat From. + $headers['Reply-To'] = $from; + // Match e-mails of the form 'My Name ' as follows: + // ^ = beginning of string + // "? = optional quote + // ([^<]*?) = match optional characters that aren't a < (non-greedy) + // "? = optional quote + // SPACE* = optional spaces + // (?:<(.*)>) = < matching stuff > (without the angle brakets) + // $ = end of string + preg_match('/^"?([^<]*?)"? *(?:<(.*)>)?$/', $from, $matches); + if ($matches) { + $display_name = t('"!name via !site_name"', array( + '!name' => empty($matches[1]) ? $matches[2] : $matches[1], + '!site_name' => variable_get('site_name', 'Drupal'), + )); + $headers['From'] = drupal_mail_format_display_name($display_name) . ' <' . $default_from. '>'; + $message['from'] = $default_from; + } + } } $message['headers'] = $headers; diff --git a/modules/contact/contact.test b/modules/contact/contact.test index 6a1674a0..4523cf83 100644 --- a/modules/contact/contact.test +++ b/modules/contact/contact.test @@ -323,6 +323,33 @@ class ContactPersonalTestCase extends DrupalWebTestCase { $this->contact_user = $this->drupalCreateUser(); } + /** + * Tests that mails for contact messages are correctly sent. + */ + public function testSendPersonalContactMessage() { + // Replace the web user's email so we can check the headers. + $from_email = $edit['mail'] = $this->web_user->name . '&escaped@example.net'; + $site_mail = variable_get('site_mail', 'simpletest@example.com'); + $account = user_load($this->web_user->uid); + user_save($account, $edit); + + $this->drupalLogin($this->web_user); + $this->drupalGet('user/' . $this->contact_user->uid . '/contact'); + $this->assertRaw(check_plain($from_email)); + $this->submitPersonalContact($this->contact_user); + + // Assume the most recent email. + $captured_emails = $this->drupalGetMails(); + $email = end($captured_emails); + + $this->assertEqual(1, count($captured_emails)); + $this->assertEqual($email['to'], $this->contact_user->mail); + $this->assertEqual($email['from'], $site_mail); + $this->assertEqual($email['headers']['From'], "\"$from_email via Drupal\" <$site_mail>"); + $this->assertEqual($email['headers']['Reply-To'], $from_email); + $this->assertEqual($email['key'], 'user_mail'); + } + /** * Tests access to the personal contact form. */ diff --git a/modules/simpletest/tests/mail.test b/modules/simpletest/tests/mail.test index 307c77b2..79a29eec 100644 --- a/modules/simpletest/tests/mail.test +++ b/modules/simpletest/tests/mail.test @@ -90,6 +90,34 @@ class MailTestCase extends DrupalWebTestCase implements MailSystemInterface { $this->assertEqual($site_name . ' <' . $default_from . '>', self::$sent_message['headers']['From']); } + /** + * Checks the From: and Reply-to: headers. + */ + function testFromAndReplyToHeader() { + global $language; + + $from_email = 'foo&escaped@example.net'; + $site_mail = variable_get('site_mail', 'simpletest@example.com'); + + // Reset the class variable holding a copy of the last sent message. + self::$sent_message = NULL; + // Use MailTestCase for sending a message. + drupal_mail('simpletest', 'from_test', 'from_test@example.com', $language, [], $from_email); + // Test that the reply-to e-mail is just the e-mail and not the site name and + // default sender e-mail. + $this->assertEqual("\"$from_email via Drupal\" <$site_mail>", self::$sent_message['headers']['From'], 'Message is sent from the site email account.'); + $this->assertEqual($from_email, self::$sent_message['headers']['Reply-To'], 'Message reply-to headers are set.'); + $this->assertFalse(isset(self::$sent_message['headers']['Errors-To']), 'Errors-to header must not be set, it is deprecated.'); + + // Reset the class variable holding a copy of the last sent message. + self::$sent_message = NULL; + // Send an e-mail and check that the From-header contains the site name. + drupal_mail('simpletest', 'from_test', 'from_test@example.com', $language); + $this->assertEqual($site_mail, self::$sent_message['headers']['From'], 'Message is sent from the site email account.'); + $this->assertFalse(isset(self::$sent_message['headers']['Reply-to']), 'Message reply-to is not set if not specified.'); + $this->assertFalse(isset(self::$sent_message['headers']['Errors-To']), 'Errors-to header must not be set, it is deprecated.'); + } + /** * Checks for the site name in an auto-generated From: header. */