=== modified file 'modules/contact/contact.module'
--- modules/contact/contact.module	
+++ modules/contact/contact.module	
@@ -475,9 +475,11 @@ function contact_mail_page() {
       '#title' => t('Message'),
       '#required' => TRUE,
     );
-    $form['copy'] = array('#type' => 'checkbox',
-      '#title' => t('Send yourself a copy.'),
-    );
+    if ($user->uid) {
+      $form['copy'] = array('#type' => 'checkbox',
+        '#title' => t('Send yourself a copy.'),
+      );
+    }
     $form['submit'] = array('#type' => 'submit',
       '#value' => t('Send e-mail'),
     );
=== modified file 'modules/user/user.module'
--- modules/user/user.module	
+++ modules/user/user.module	
@@ -704,6 +704,8 @@ function user_menu($may_cache) {
       'callback' => 'drupal_get_form', 'callback arguments' => array('user_pass'), 'access' => $user->uid == 0, 'type' => MENU_LOCAL_TASK);
     $items[] = array('path' => 'user/reset', 'title' => t('reset password'),
       'callback' => 'drupal_get_form', 'callback arguments' => array('user_pass_reset'), 'access' => TRUE, 'type' => MENU_CALLBACK);
+    $items[] = array('path' => 'user/change/mail', 'title' => t('change email'),
+      'callback' => 'user_change_mail', 'access' => TRUE, 'type' => MENU_CALLBACK);
     $items[] = array('path' => 'user/help', 'title' => t('help'),
       'callback' => 'user_help_page', 'type' => MENU_CALLBACK);
 
@@ -1125,7 +1127,7 @@ function user_pass_reset($uid, $timestam
 
 function user_pass_reset_url($account) {
   $timestamp = time();
-  return url("user/reset/$account->uid/$timestamp/".user_pass_rehash($account->pass, $timestamp, $account->login), NULL, NULL, TRUE);
+  return url("user/reset/$account->uid/$timestamp/". user_pass_rehash($account->pass, $timestamp, $account->login), NULL, NULL, TRUE);
 }
 
 function user_pass_rehash($password, $timestamp, $login) {
@@ -1372,6 +1374,55 @@ function _user_edit_submit($uid, &$edit)
   if (isset($edit['roles'])) {
     $edit['roles'] = array_filter($edit['roles']);
   }
+  if ($edit['mail']) {
+    $hash = user_email_rehash($user->pass, $edit['mail']);
+    $url = url("user/change/mail/$account->uid/$timestamp/". $edit['mail'] ."/$hash", NULL, NULL, TRUE);
+    $variables = array('%username' => $user->name, '%site' => variable_get('site_name', 'drupal'), '%email_url' => $url, '%uri' => $base_url, '%uri_brief' => substr($base_url, strlen('http://')), '%mailto' => $user->mail, '%date' => format_date(time()), '%login_uri' => url('user', NULL, NULL, TRUE), '%edit_uri' => url('user/'. $user->uid .'/edit', NULL, NULL, TRUE));
+    $subject = _user_mail_text('mail_change_subject', $variables);
+    $body = _user_mail_text('mail_change_body', $variables);
+    $headers = "From: $from\nReply-to: $from\nX-Mailer: Drupal\nReturn-path: $from\nErrors-to: $from";
+    $mail_success = user_mail($user->mail, $subject, $body, $headers);
+    unset($edit['mail']);
+  }
+}
+
+function user_email_rehash($pass, $mail) {
+  return md5($pass . $mail);
+}
+
+function user_change_mail($uid, $timestamp, $new_mail, $hash, $action = '') {
+  global $user;
+
+  // Time out, in seconds, until login URL expires. 24 hours = 86400 seconds.
+  $timeout = 86400;
+  $current = time();
+  // Some redundant checks for extra security ?
+  if ($timestamp < $current && $account = user_load(array('uid' => $uid, 'status' => 1)) ) {
+    if ($current - $timestamp > $timeout) {
+      drupal_set_message(t('You have tried to use a one-time edit link that has expired. Please request a new one using the form below.'));
+      drupal_goto('user/password');
+    }
+    else if ($account->uid && $timestamp > $account->login && $timestamp < $current && $hashed_pass == user_email_rehash($account->pass, $new_mail)) {
+      watchdog('user', t('User %name used one-time edit link at time %timestamp.', array('%name' => "<em>$account->name</em>", '%timestamp' => $timestamp)));
+      db_query("UPDATE {users} SET mail = '%s' WHERE uid = %d", $new_mail, $account->uid);
+      drupal_set_message(t('Your mail address is now %mail.', array('%mail' => $new_mail)));
+      drupal_goto();
+    }
+    else {
+      drupal_set_message(t('You have tried to use a one-time edit link which has either been used or is no longer valid. Please request a new one.'));
+      if ($user->uid) {
+        drupal_goto('user/'. $user->uid .'/edit');
+      }
+      else {
+        drupal_goto('user/login', 'user/'. $user->uid .'/edit');
+      }
+    }
+  }
+  else {
+    // Deny access, no more clues.
+    // Everything will be in the watchdog's URL for the administrator to check.
+    drupal_access_denied();
+  }
 }
 
 function user_edit($category = 'account') {
@@ -1523,6 +1574,10 @@ function _user_mail_text($messageid, $va
         return t('Replacement login information for !username at !site', $variables);
       case 'pass_body':
         return t("!username,\n\nA request to reset the password for your account has been made at !site.\n\nYou may now log in to !uri_brief clicking on this link or copying and pasting it in your browser:\n\n!login_url\n\nThis is a one-time login, so it can be used only once. It expires after one day and nothing will happen if it's not used.\n\nAfter logging in, you will be redirected to !edit_uri so you can change your password.", $variables);
+      case 'mail_change_subject':
+        return t('Email change information for %username at %site', $variables);
+      case 'mail_change_body':
+        return t("%username,\n\nA request to change your email address has been made at %site. You need to verify by your clicking on this link or copying and pasting it in your browser:\n\n%email_url\n\nThis is a one-time URL, so it can be used only once. It expires after one day and nothing will happen if it's not used.\n\n", $variables);
     }
   }
 }
