diff --git a/core/includes/common.inc b/core/includes/common.inc
index 17f83ad63656ed349250af6f9e98d3a901003d0a..9f50506e945bb98fe688fc9a5806913c25ca958e 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -6934,6 +6934,9 @@ function drupal_common_theme() {
     'tel' => array(
       'render element' => 'element',
     ),
+    'email' => array(
+      'render element' => 'element',
+    ),
     'form' => array(
       'render element' => 'element',
     ),
diff --git a/core/includes/form.inc b/core/includes/form.inc
index d726f5c18563ee0cfe33e68721f63c8fdeac5268..9051eef2a3a99f0871cb74f23049aeeae557373d 100644
--- a/core/includes/form.inc
+++ b/core/includes/form.inc
@@ -3749,6 +3749,56 @@ function theme_textfield($variables) {
   return $output . $extra;
 }
 
+/**
+ * Returns HTML for an email form element.
+ *
+ * @param $variables
+ *   An associative array containing:
+ *   - element: An associative array containing the properties of the element.
+ *     Properties used: #title, #value, #description, #size, #maxlength,
+ *     #placeholder, #required, #attributes, #autocomplete_path.
+ *
+ * @ingroup themeable
+ */
+function theme_email($variables) {
+  $element = $variables['element'];
+  $element['#attributes']['type'] = 'email';
+  element_set_attributes($element, array('id', 'name', 'value', 'size', 'maxlength', 'placeholder'));
+  _form_set_class($element, array('form-email'));
+
+  $extra = '';
+  if ($element['#autocomplete_path'] && drupal_valid_path($element['#autocomplete_path'])) {
+    drupal_add_library('system', 'drupal.autocomplete');
+    $element['#attributes']['class'][] = 'form-autocomplete';
+
+    $attributes = array();
+    $attributes['type'] = 'hidden';
+    $attributes['id'] = $element['#attributes']['id'] . '-autocomplete';
+    $attributes['value'] = url($element['#autocomplete_path'], array('absolute' => TRUE));
+    $attributes['disabled'] = 'disabled';
+    $attributes['class'][] = 'autocomplete';
+    $extra = '<input' . drupal_attributes($attributes) . ' />';
+  }
+
+  $output = '<input' . drupal_attributes($element['#attributes']) . ' />';
+
+  return $output . $extra;
+}
+
+/**
+ * Form element validation handler for #type 'email'.
+ *
+ * Note that #maxlength and #required is validated by _form_validate() already.
+ */
+function form_validate_email(&$element, &$form_state) {
+  $value = trim($element['#value']);
+  form_set_value($element, $value, $form_state);
+
+  if ($value !== '' && !valid_email_address($value)) {
+    form_error($element, t('The e-mail address %mail is not valid.', array('%mail' => $value)));
+  }
+}
+
 /**
  * Returns HTML for a tel form element.
  *
diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc
index f16e094d8e6bf7c57301b82c8c7136a5978ebe84..49147a807826338251dd94f59c65e65446a67f83 100644
--- a/core/includes/install.core.inc
+++ b/core/includes/install.core.inc
@@ -1747,7 +1747,7 @@ function _install_configure_form($form, &$form_state, &$install_state) {
     '#weight' => -20,
   );
   $form['site_information']['site_mail'] = array(
-    '#type' => 'textfield',
+    '#type' => 'email',
     '#title' => st('Site e-mail address'),
     '#default_value' => ini_get('sendmail_from'),
     '#description' => st("Automated e-mails, such as registration information, will be sent from this address. Use an address ending in your site's domain to help prevent these e-mails from being flagged as spam."),
@@ -1770,9 +1770,9 @@ function _install_configure_form($form, &$form_state, &$install_state) {
     '#attributes' => array('class' => array('username')),
   );
 
-  $form['admin_account']['account']['mail'] = array('#type' => 'textfield',
+  $form['admin_account']['account']['mail'] = array(
+    '#type' => 'email',
     '#title' => st('E-mail address'),
-    '#maxlength' => EMAIL_MAX_LENGTH,
     '#required' => TRUE,
     '#weight' => -5,
   );
@@ -1849,12 +1849,6 @@ function install_configure_form_validate($form, &$form_state) {
   if ($error = user_validate_name($form_state['values']['account']['name'])) {
     form_error($form['admin_account']['account']['name'], $error);
   }
-  if ($error = user_validate_mail($form_state['values']['account']['mail'])) {
-    form_error($form['admin_account']['account']['mail'], $error);
-  }
-  if ($error = user_validate_mail($form_state['values']['site_mail'])) {
-    form_error($form['site_information']['site_mail'], $error);
-  }
 }
 
 /**
diff --git a/core/modules/comment/comment.module b/core/modules/comment/comment.module
index 664acf3674220390b7ee2374e05b80defafd1940..946583669cebb3d6542f66db28cb62f9028b9d07 100644
--- a/core/modules/comment/comment.module
+++ b/core/modules/comment/comment.module
@@ -1781,7 +1781,7 @@ function comment_form($form, &$form_state, $comment) {
 
   // Add author e-mail and homepage fields depending on the current user.
   $form['author']['mail'] = array(
-    '#type' => 'textfield',
+    '#type' => 'email',
     '#title' => t('E-mail'),
     '#default_value' => $comment->mail,
     '#required' => (!$user->uid && $anonymous_contact == COMMENT_ANONYMOUS_MUST_CONTACT),
@@ -1982,9 +1982,6 @@ function comment_form_validate($form, &$form_state) {
       }
     }
   }
-  if ($form_state['values']['mail'] && !valid_email_address($form_state['values']['mail'])) {
-    form_set_error('mail', t('The e-mail address you specified is not valid.'));
-  }
   if ($form_state['values']['homepage'] && !valid_url($form_state['values']['homepage'], TRUE)) {
     form_set_error('homepage', t('The URL of your homepage is not valid. Remember that it must be fully qualified, i.e. of the form <code>http://example.com/directory</code>.'));
   }
diff --git a/core/modules/contact/contact.pages.inc b/core/modules/contact/contact.pages.inc
index 289e38b7a2a8b233a3d21c89e245ed49e535bf3e..bf096a7b8ee438b9a171b3b513aaee4e0dd48abb 100644
--- a/core/modules/contact/contact.pages.inc
+++ b/core/modules/contact/contact.pages.inc
@@ -71,9 +71,8 @@ function contact_site_form($form, &$form_state) {
     '#required' => TRUE,
   );
   $form['mail'] = array(
-    '#type' => 'textfield',
+    '#type' => 'email',
     '#title' => t('Your e-mail address'),
-    '#maxlength' => 255,
     '#default_value' => $user->uid ? $user->mail : '',
     '#required' => TRUE,
   );
@@ -121,9 +120,6 @@ function contact_site_form_validate($form, &$form_state) {
   if (!$form_state['values']['cid']) {
     form_set_error('cid', t('You must select a valid category.'));
   }
-  if (!valid_email_address($form_state['values']['mail'])) {
-    form_set_error('mail', t('You must enter a valid e-mail address.'));
-  }
 }
 
 /**
@@ -211,9 +207,8 @@ function contact_personal_form($form, &$form_state, $recipient) {
     '#required' => TRUE,
   );
   $form['mail'] = array(
-    '#type' => 'textfield',
+    '#type' => 'email',
     '#title' => t('Your e-mail address'),
-    '#maxlength' => 255,
     '#default_value' => $user->uid ? $user->mail : '',
     '#required' => TRUE,
   );
@@ -249,17 +244,6 @@ function contact_personal_form($form, &$form_state, $recipient) {
   return $form;
 }
 
-/**
- * Form validation handler for contact_personal_form().
- *
- * @see contact_personal_form_submit()
- */
-function contact_personal_form_validate($form, &$form_state) {
-  if (!valid_email_address($form_state['values']['mail'])) {
-    form_set_error('mail', t('You must enter a valid e-mail address.'));
-  }
-}
-
 /**
  * Form submission handler for contact_personal_form().
  *
diff --git a/core/modules/contact/contact.test b/core/modules/contact/contact.test
index 48c8bb01fd63a0c0172adabf0c368c252ae235d3..d7f26acf17d1ab75f73132f195cce50765d7304d 100644
--- a/core/modules/contact/contact.test
+++ b/core/modules/contact/contact.test
@@ -126,7 +126,7 @@ class ContactSitewideTestCase extends DrupalWebTestCase {
     $this->assertText(t('Your e-mail address field is required.'), t('E-mail required.'));
 
     $this->submitContact($this->randomName(16), $invalid_recipients[0], $this->randomName(16), $categories[0], $this->randomName(64));
-    $this->assertText(t('You must enter a valid e-mail address.'), t('Valid e-mail required.'));
+    $this->assertRaw(t('The e-mail address %mail is not valid.', array('%mail' => 'invalid')), 'Valid e-mail required.');
 
     $this->submitContact($this->randomName(16), $recipients[0], '', $categories[0], $this->randomName(64));
     $this->assertText(t('Subject field is required.'), t('Subject required.'));
diff --git a/core/modules/simpletest/drupal_web_test_case.php b/core/modules/simpletest/drupal_web_test_case.php
index e5d36c338ba7809dbc12e60566402df657aa41fb..940915fde215af011f4e66dd21281fd6b64201ad 100644
--- a/core/modules/simpletest/drupal_web_test_case.php
+++ b/core/modules/simpletest/drupal_web_test_case.php
@@ -2250,6 +2250,7 @@ protected function handleForm(&$post, &$edit, &$upload, $submit, $form) {
           case 'textarea':
           case 'hidden':
           case 'password':
+          case 'email':
             $post[$name] = $edit[$name];
             unset($edit[$name]);
             break;
diff --git a/core/modules/simpletest/tests/form.test b/core/modules/simpletest/tests/form.test
index 6e40f1f9fc6165beaa6a3f3fd706e64ccae8f666..4eefff462c9daaef35fa20910fb01a37ef2e153a 100644
--- a/core/modules/simpletest/tests/form.test
+++ b/core/modules/simpletest/tests/form.test
@@ -1627,3 +1627,47 @@ class FormCheckboxTestCase extends DrupalWebTestCase {
     }
   }
 }
+
+/**
+ * Tests email element.
+ */
+class FormEmailTestCase extends DrupalWebTestCase {
+  protected $profile = 'testing';
+
+  public static function getInfo() {
+    return array(
+      'name' => 'Form API email',
+      'description' => 'Tests the form API email element.',
+      'group' => 'Form API',
+    );
+  }
+
+  function setUp() {
+    parent::setUp('form_test');
+  }
+
+  /**
+   * Tests that #type 'email' fields are properly validated.
+   */
+  function testFormEmail() {
+    $edit = array();
+    $edit['email'] = 'invalid';
+    $edit['email_required'] = ' ';
+    $this->drupalPost('form-test/email', $edit, 'Submit');
+    $this->assertRaw(t('The e-mail address %mail is not valid.', array('%mail' => 'invalid')));
+    $this->assertRaw(t('!name field is required.', array('!name' => 'Address')));
+
+    $edit = array();
+    $edit['email_required'] = '  foo.bar@example.com ';
+    $values = drupal_json_decode($this->drupalPost('form-test/email', $edit, 'Submit'));
+    $this->assertIdentical($values['email'], '');
+    $this->assertEqual($values['email_required'], 'foo.bar@example.com');
+
+    $edit = array();
+    $edit['email'] = 'foo@example.com';
+    $edit['email_required'] = 'example@drupal.org';
+    $values = drupal_json_decode($this->drupalPost('form-test/email', $edit, 'Submit'));
+    $this->assertEqual($values['email'], 'foo@example.com');
+    $this->assertEqual($values['email_required'], 'example@drupal.org');
+  }
+}
diff --git a/core/modules/simpletest/tests/form_test.module b/core/modules/simpletest/tests/form_test.module
index 76e5c260de3d62ce449ff21140cedb44c2c38acf..a64fb62e278638718ce8612db0fe749dfbf9036a 100644
--- a/core/modules/simpletest/tests/form_test.module
+++ b/core/modules/simpletest/tests/form_test.module
@@ -125,6 +125,12 @@ function form_test_menu() {
     'page arguments' => array('form_test_checkboxes_radios'),
     'access callback' => TRUE,
   );
+  $items['form-test/email'] = array(
+    'title' => 'E-Mail fields',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('form_test_email'),
+    'access callback' => TRUE,
+  );
 
   $items['form-test/disabled-elements'] = array(
     'title' => t('Form test'),
@@ -1097,6 +1103,39 @@ function form_test_checkboxes_radios($form, &$form_state, $customize = FALSE) {
   return $form;
 }
 
+/**
+ * Form constructor for testing #type 'email' elements.
+ *
+ * @see form_test_email_submit()
+ * @ingroup forms
+ */
+function form_test_email($form, &$form_state) {
+  $form['email'] = array(
+    '#type' => 'email',
+    '#title' => 'E-Mail address',
+    '#description' => 'An e-mail address.',
+  );
+  $form['email_required'] = array(
+    '#type' => 'email',
+    '#title' => 'Address',
+    '#required' => TRUE,
+    '#description' => 'A required e-mail address field.',
+  );
+  $form['submit'] = array(
+    '#type' => 'submit',
+    '#value' => 'Submit',
+  );
+  return $form;
+}
+
+/**
+ * Form submission handler for form_test_email().
+ */
+function form_test_email_submit($form, &$form_state) {
+  drupal_json_output($form_state['values']);
+  exit();
+}
+
 /**
  * Build a form to test disabled elements.
  */
diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc
index d28ecfbe207b1052351d6c9bb59c0f3c14a465de..1c865a6356f25deee43107fcc37eb92385dcbf0e 100644
--- a/core/modules/system/system.admin.inc
+++ b/core/modules/system/system.admin.inc
@@ -1477,7 +1477,7 @@ function system_site_information_settings() {
     '#description' => t("How this is used depends on your site's theme."),
   );
   $form['site_information']['site_mail'] = array(
-    '#type' => 'textfield',
+    '#type' => 'email',
     '#title' => t('E-mail address'),
     '#default_value' => variable_get('site_mail', ini_get('sendmail_from')),
     '#description' => t("The <em>From</em> address in automated e-mails sent during registration and new password requests, and other notifications. (Use an address ending in your site's domain to help prevent this e-mail being flagged as spam.)"),
@@ -1532,10 +1532,6 @@ function system_site_information_settings() {
  * Validates the submitted site-information form.
  */
 function system_site_information_settings_validate($form, &$form_state) {
-  // Validate the e-mail address.
-  if ($error = user_validate_mail($form_state['values']['site_mail'])) {
-    form_set_error('site_mail', $error);
-  }
   // Check for empty front page path.
   if (empty($form_state['values']['site_frontpage'])) {
     // Set to default "user".
diff --git a/core/modules/system/system.module b/core/modules/system/system.module
index 92092d293d9589222f6ba7274275f580ed0c17ab..1c0543d158c9df0c577cbb29ad8b95728cf79261 100644
--- a/core/modules/system/system.module
+++ b/core/modules/system/system.module
@@ -374,6 +374,16 @@ function system_element_info() {
     '#theme' => 'tel',
     '#theme_wrappers' => array('form_element'),
   );
+  $types['email'] = array(
+    '#input' => TRUE,
+    '#size' => 60,
+    '#maxlength' => EMAIL_MAX_LENGTH,
+    '#autocomplete_path' => FALSE,
+    '#process' => array('ajax_process_form'),
+    '#element_validate' => array('form_validate_email'),
+    '#theme' => 'email',
+    '#theme_wrappers' => array('form_element'),
+  );
   $types['machine_name'] = array(
     '#input' => TRUE,
     '#default_value' => NULL,
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 3ac4cd682313d0f4a76bdaf4ab163dddeb4ded60..7fb442f15d070e64da0f86b758ec19eeb541fad4 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -395,9 +395,6 @@ function user_save($account, $edit = array()) {
       // Avoid overwriting an existing password with a blank password.
       unset($edit['pass']);
     }
-    if (isset($edit['mail'])) {
-      $edit['mail'] = trim($edit['mail']);
-    }
 
     // Load the stored entity, if any.
     if (!empty($account->uid) && !isset($account->original)) {
@@ -608,28 +605,6 @@ function user_validate_name($name) {
   }
 }
 
-/**
- * Validates a user's email address.
- *
- * Checks that a user's email address exists and follows all standard
- * validation rules. Returns error messages when the address is invalid.
- *
- * @param $mail
- *   A user's email address.
- *
- * @return
- *   If the address is invalid, a human-readable error message is returned.
- *   If the address is valid, nothing is returned.
- */
-function user_validate_mail($mail) {
-  if (!$mail) {
-    return t('You must enter an e-mail address.');
-  }
-  if (!valid_email_address($mail)) {
-    return t('The e-mail address %mail is not valid.', array('%mail' => $mail));
-  }
-}
-
 /**
  * Validates an image uploaded by a user.
  *
@@ -965,9 +940,8 @@ function user_account_form(&$form, &$form_state) {
   );
 
   $form['account']['mail'] = array(
-    '#type' => 'textfield',
+    '#type' => 'email',
     '#title' => t('E-mail address'),
-    '#maxlength' => EMAIL_MAX_LENGTH,
     '#description' => t('A valid e-mail address. All e-mails from the system will be sent to this address. The e-mail address is not made public and will only be used if you wish to receive a new password or wish to receive certain news or notifications by e-mail.'),
     '#required' => TRUE,
     '#default_value' => (!$register ? $account->mail : ''),
@@ -1149,22 +1123,15 @@ function user_account_form_validate($form, &$form_state) {
     }
   }
 
-  // Trim whitespace from mail, to prevent confusing 'e-mail not valid'
-  // warnings often caused by cutting and pasting.
-  $mail = trim($form_state['values']['mail']);
-  form_set_value($form['account']['mail'], $mail, $form_state);
+  $mail = $form_state['values']['mail'];
 
-  // Validate the e-mail address, and check if it is taken by an existing user.
-  if ($error = user_validate_mail($form_state['values']['mail'])) {
-    form_set_error('mail', $error);
-  }
-  elseif ((bool) db_select('users')->fields('users', array('uid'))->condition('uid', $account->uid, '<>')->condition('mail', db_like($form_state['values']['mail']), 'LIKE')->range(0, 1)->execute()->fetchField()) {
+  if ((bool) db_select('users')->fields('users', array('uid'))->condition('uid', $account->uid, '<>')->condition('mail', db_like($mail), 'LIKE')->range(0, 1)->execute()->fetchField()) {
     // Format error message dependent on whether the user is logged in or not.
     if ($GLOBALS['user']->uid) {
-      form_set_error('mail', t('The e-mail address %email is already taken.', array('%email' => $form_state['values']['mail'])));
+      form_set_error('mail', t('The e-mail address %email is already taken.', array('%email' => $mail)));
     }
     else {
-      form_set_error('mail', t('The e-mail address %email is already registered. <a href="@password">Have you forgotten your password?</a>', array('%email' => $form_state['values']['mail'], '@password' => url('user/password'))));
+      form_set_error('mail', t('The e-mail address %email is already registered. <a href="@password">Have you forgotten your password?</a>', array('%email' => $mail, '@password' => url('user/password'))));
     }
   }
 
diff --git a/core/modules/user/user.test b/core/modules/user/user.test
index 0c5f90ffc908e54b011049cd138cc0a5a7e1c3ea..5b97e8b3e1ae87f8c83074d1fad29dd0bafbfb5d 100644
--- a/core/modules/user/user.test
+++ b/core/modules/user/user.test
@@ -292,20 +292,6 @@ class UserValidationTestCase extends DrupalWebTestCase {
       $this->$test($result, $description . ' (' . $name . ')');
     }
   }
-
-  // Mail validation. More extensive tests can be found at common.test
-  function testMailAddresses() {
-    $test_cases = array( // '<username>' => array('<description>', 'assert<testName>'),
-      ''                => array('Empty mail address', 'assertNotNull'),
-      'foo'             => array('Invalid mail address', 'assertNotNull'),
-      'foo@example.com' => array('Valid mail address', 'assertNull'),
-    );
-    foreach ($test_cases as $name => $test_case) {
-      list($description, $test) = $test_case;
-      $result = user_validate_mail($name);
-      $this->$test($result, $description . ' (' . $name . ')');
-    }
-  }
 }
 
 /**
diff --git a/core/themes/bartik/css/style.css b/core/themes/bartik/css/style.css
index 7a743b1fb001e8b05cc31fddb66e1525b388b33d..739ae81ae46e2908d1314b571ba5a4a0a7b68689 100644
--- a/core/themes/bartik/css/style.css
+++ b/core/themes/bartik/css/style.css
@@ -1195,6 +1195,7 @@ select.form-select {
 }
 input.form-text,
 input.form-tel,
+input.form-email,
 textarea.form-textarea,
 select.form-select {
   border: 1px solid #ccc;
diff --git a/core/themes/seven/style.css b/core/themes/seven/style.css
index 66914f6fb1036a278006b51eb373ad136c4eabe9..4214453410c0fd7a92c114a3fc413ec084017286 100644
--- a/core/themes/seven/style.css
+++ b/core/themes/seven/style.css
@@ -602,6 +602,7 @@ div.teaser-checkbox .form-item,
 .form-disabled input.form-autocomplete,
 .form-disabled input.form-text,
 .form-disabled input.form-tel,
+.form-disabled input.form-email,
 .form-disabled input.form-file,
 .form-disabled textarea.form-textarea,
 .form-disabled select.form-select {
@@ -689,6 +690,7 @@ input.form-button-disabled:active {
 input.form-autocomplete,
 input.form-text,
 input.form-tel,
+input.form-email,
 input.form-file,
 textarea.form-textarea,
 select.form-select {
@@ -703,6 +705,7 @@ select.form-select {
 }
 input.form-text:focus,
 input.form-tel:focus,
+input.form-email:focus,
 input.form-file:focus,
 textarea.form-textarea:focus,
 select.form-select:focus {