Index: src/bp-settings/bp-settings-actions.php
--- src/bp-settings/bp-settings-actions.php
+++ src/bp-settings/bp-settings-actions.php
@@ -67,11 +67,11 @@
 
 			// What is missing from the profile page vs signup -
 			// let's double check the goodies
-			$user_email     = sanitize_email( esc_html( trim( $_POST['email'] ) ) );
+			$user_email     = sanitize_email( trim( $_POST['email'] ) );
 			$old_user_email = $bp->displayed_user->userdata->user_email;
 
 			// User is changing email address
-			if ( $old_user_email != $user_email ) {
+			if ( $old_user_email !== $user_email ) {
 
 				// Run some tests on the email address
 				$email_checks = bp_core_validate_email_address( $user_email );
@@ -92,54 +92,10 @@
 
 				// Store a hash to enable email validation
 				if ( false === $email_error ) {
-					$hash = wp_hash( $_POST['email'] );
+					
+					// Send the email change verification email
+					bp_settings_send_email_change_verification_email( $user_email, $old_user_email );
 
-					$pending_email = array(
-						'hash'     => $hash,
-						'newemail' => $user_email,
-					);
-
-					bp_update_user_meta( bp_displayed_user_id(), 'pending_email_change', $pending_email );
-
-					$email_text = sprintf(
-						__( 'Dear %1$s,
-
-You recently changed the email address associated with your account on %2$s.
-If this is correct, please click on the following link to complete the change:
-%3$s
-
-You can safely ignore and delete this email if you do not want to take this action or if you have received this email in error.
-
-This email has been sent to %4$s.
-
-Regards,
-%5$s
-%6$s', 'buddypress' ),
-						bp_core_get_user_displayname( bp_displayed_user_id() ),
-						bp_get_site_name(),
-						esc_url( bp_displayed_user_domain() . bp_get_settings_slug() . '/?verify_email_change=' . $hash ),
-						$user_email,
-						bp_get_site_name(),
-						bp_get_root_domain()
-					);
-
-					/**
-					 * Filter the email text sent when a user changes emails.
-					 *
-					 * @since BuddyPress (2.1.0)
-					 *
-					 * @param string  $email_text     Text of the email.
-					 * @param string  $new_user_email New user email that the
-					 *                                current user has changed to.
-					 * @param string  $old_user_email Existing email address
-					 *                                for the current user.
-					 * @param WP_User $update_user    Userdata object for the current user.
-					 */
-					$content = apply_filters( 'bp_new_user_email_content', $email_text, $user_email, $old_user_email, $update_user );
-
-					// Send the verification email
-					wp_mail( $user_email, sprintf( __( '[%s] Verify your new email address', 'buddypress' ), wp_specialchars_decode( bp_get_site_name() ) ), $content );
-
 					// We mark that the change has taken place so as to ensure a
 					// success message, even though verification is still required
 					$_POST['email'] = $update_user->user_email;
@@ -495,6 +451,48 @@
 add_action( 'bp_actions', 'bp_settings_verify_email_change' );
 
 /**
+ * Resend email change verification email
+ *
+ * @since BuddyPress (2.3.0)
+ */
+function bp_settings_resend_email_change() {
+
+	// Bail if not settings
+	if ( ! bp_is_settings_component() ) {
+		return;
+	}
+
+	// Bail if not viewing own profile
+	if ( ! bp_is_my_profile() ) {
+		return;
+	}
+
+	// Bail if not resending verification email
+	if ( ! isset( $_GET['resend_verification'] ) ) {
+		return;
+	}
+
+	// Get redirect address and pending email change meta
+	$pending_email = bp_get_user_meta( bp_displayed_user_id(), 'pending_email_change', true );
+
+	// Bail if the hash provided doesn't match the one saved in the database
+	if ( urldecode( $_GET['resend_verification'] ) !== $pending_email['hash'] ) {
+		return;
+	}
+
+	// Attempt to resend email change verification
+	if ( bp_settings_send_email_change_verification_email( $pending_email['newemail'] ) ) {
+		$message = sprintf( __( 'An email has been sent to %1$s with a new verification link.', 'buddypress' ), $pending_email['newemail'] );
+		bp_core_add_message( $message );
+	}
+
+	// Redirect
+	$redirect_to   = trailingslashit( bp_displayed_user_domain() . bp_get_settings_slug() );
+	bp_core_redirect( $redirect_to );
+}
+add_action( 'bp_actions', 'bp_settings_verify_email_change' );
+
+/**
  * Removes 'Email' sub nav, if no component has registered options there.
  *
  * @since BuddyPress (2.2.0)
Index: src/bp-settings/bp-settings-functions.php
--- src/bp-settings/bp-settings-functions.php
+++ src/bp-settings/bp-settings-functions.php
@@ -9,3 +9,105 @@
 
 // Exit if accessed directly
 defined( 'ABSPATH' ) || exit;
+
+/**
+ * Send an email to the displayed user for them to verify that they want to
+ * change the main email address associated with their account.
+ *
+ * In the case of a resend, a new hash is saved and provided. This invalidates
+ * old links in previous emails, increasing security by validating the most
+ * recent user intent.
+ *
+ * @since BuddyPress (2.3.0)
+ *
+ * @param  string $new_email_address Email address to use going forward
+ * @param  string $old_email_address Email address previously being used
+ *
+ * @return type
+ */
+function bp_settings_send_email_change_verification_email( $new_email_address = '', $old_email_address = '' ) {
+
+	// This is for the displayed user ID, which is typically the logged in user
+	$user_id = bp_displayed_user_id();
+
+	// If no email address passed, attempt to use new address from pending meta
+	if ( empty( $new_email_address ) ) {
+		$pending_email = bp_get_user_meta( $user_id, 'pending_email_change', true );
+
+		// Bail if pending email is missing newemail key, or if no pending email
+		// change could be found in user meta for this user.
+		if ( empty( $pending_email['newemail'] ) ) {
+			return false;
+		}
+
+		$user_email = $pending_email['newemail'];
+	}
+
+	// If no email address passed, use currently displayed user email address
+	if ( empty( $old_email_address ) ) {
+		$old_email_address = bp_displayed_user_email();
+	}
+
+	// Rehash based on the user email, to invalidate previous emails
+	$hash = wp_hash( $user_email );
+
+	// Update displayed user meta with new hash
+	bp_update_user_meta( $user_id, 'pending_email_change', array(
+		'hash'     => $hash,
+		'newemail' => $user_email,
+	) );
+
+	// Setup a few string variables for concatenation later
+	$user_settings = trailingslashit( bp_displayed_user_domain() . bp_get_settings_slug() );
+	$user_name     = bp_core_get_user_displayname( $user_id );
+	$site_name     = wp_specialchars_decode( bp_get_site_name() );
+	$site_address  = bp_get_root_domain();
+	$email_link    = esc_url( add_query_arg( array( 'resend_verification' => $hash ), $user_settings ) );
+	$email_text    = __( 'Dear %1$s,
+
+You recently changed the email address associated with your account on %2$s.
+If this is correct, please click on the following link to complete the change:
+%3$s
+
+You can safely ignore and delete this email if you do not want to take this action or if you have received this email in error.
+
+This email has been sent to %4$s.
+
+Regards,
+%5$s
+%6$s', 'buddypress' );
+
+	// Format string
+	$email_content = sprintf(
+		$email_text,
+		$user_name,
+		$site_name,
+		$email_link,
+		$user_email,
+		$site_name,
+		$site_address
+	);
+
+	/**
+	 * Filter the email text sent when a user changes emails.
+	 *
+	 * @since BuddyPress (2.1.0)
+	 *
+	 * @param string  $email_text     Text of the email.
+	 * @param string  $new_user_email New email address that the user changed to.
+	 * @param string  $old_user_email Existing email address for the user.
+	 * @param WP_User $update_user    Userdata object for the user.
+	 */
+	$content = apply_filters( 'bp_new_user_email_content', $email_content, $user_email, $old_email_address, get_userdata( $user_id ) );
+
+	// Bail if destination or content were wiped out
+	if ( empty( $content ) || empty( $user_email ) ) {
+		return false;
+	}
+
+	// Send the verification email
+	wp_mail( $user_email, sprintf( __( '[%s] Verify your new email address', 'buddypress' ), $site_name ), $content );
+
+	// Email was successfully sent
+	return true;
+}
Index: src/bp-settings/bp-settings-template.php
--- src/bp-settings/bp-settings-template.php
+++ src/bp-settings/bp-settings-template.php
@@ -77,23 +77,89 @@
  *
  * @since BuddyPress (2.1.0)
  */
-function bp_settings_pending_email_notice() {
-	$pending_email = bp_get_user_meta( bp_displayed_user_id(), 'pending_email_change', true );
+function bp_settings_pending_email_notice( $args = array() ) {
+	echo bp_get_settings_pending_email_notice( $args );
+}
+add_action( 'bp_before_member_settings_template', 'bp_settings_pending_email_notice' );
 
+/**
+ * Get a pending email change notice, usually for a member's settings page.
+ *
+ * @since BuddyPress (2.3.0)
+ *
+ * @param  array $args
+ * @return array
+ */
+function bp_get_settings_pending_email_notice( $args = array() ) {
+
+	// Look for pending email change
+	$user_id       = bp_displayed_user_id();
+	$current_email = bp_get_displayed_user_email();
+	$pending_email = bp_get_user_meta( $user_id, 'pending_email_change', true );
+
+	// Bail if no pending email address change
 	if ( empty( $pending_email['newemail'] ) ) {
 		return;
 	}
 
-	if ( bp_get_displayed_user_email() == $pending_email['newemail'] ) {
+	// If pending change equals current address, delete the meta and bail
+	if ( $current_email === $pending_email['newemail'] ) {
+		bp_delete_user_meta( $user_id, 'pending_email_change' );
 		return;
 	}
 
-	?>
+	// Notice
+	$defaults['notice'] = array(
+		'before'      => '<div id="message" class="bp-template-notice error"><p>',
+		'after'       => '</p></div>',
+		'text'        => __( 'An email address change from %1$s to %2$s is still pending verification.', 'buddypress' ),
+		'old_address' => '<code>' . $current_email             . '</code>',
+		'new_address' => '<code>' . $pending_email['newemail'] . '</code>'
+	);
 
-	<div id="message" class="bp-template-notice error">
-		<p><?php printf( __( 'There is a pending change of your email address to <code>%1$s</code>.<br />Check your email (<code>%2$s</code>) for the verification link. <a href="%3$s">Cancel</a>', 'buddypress' ), $pending_email['newemail'], bp_get_displayed_user_email(), esc_url( bp_displayed_user_domain() . bp_get_settings_slug() . '/?dismiss_email_change=1' ) ) ?></p>
-	</div>
+	// Get te base URL for links
+	$base_url = trailingslashit( bp_displayed_user_domain() . bp_get_settings_slug() );
 
-	<?php
+	// Setup cancel link
+	$defaults['links']['cancel'] = array(
+		'before' => '<a href="%1$s" class="%2$s">',
+		'after'  => '</a>',
+		'text'   => __( 'Cancel', 'buddypress' ),
+		'url'    => add_query_arg( array( 'resend_verification' => $pending_email['hash'] ), $base_url ),
+		'class'  => 'cancel'
+	);
+
+	// Setup resend link
+	$defaults['links']['resend'] = array(
+		'before' => '<a href="%1$s" class="%2$s">',
+		'after'  => '</a>',
+		'text'   => __( 'Resend', 'buddypress' ),
+		'url'    => add_query_arg( array( 'dismiss_email_change' => '1' ), $base_url ),
+		'class'  => 'resend primary'
+	);
+
+	// Parse all the args
+	$r = bp_parse_args( $args, $defaults, 'settings_pending_email_notice' );
+
+	// Setup notice text
+	$notice_text = ! empty( $r['notice'] )
+		? sprintf( $r['notice']['text'], $r['notice']['old_address'], $r['notice']['new_address'] )
+		: '';
+
+	// Setup links, if any exist
+	if ( ! empty( $r['links'] ) ) {
+
+		// Setup links array
+		$links = array();
+
+		// Combine link text
+		foreach( $r['links'] as $link ) {
+			$links[] = sprintf( $link['before'] . $link['text'] . $link['after'], esc_url( $link['url'] ), $link['class'] );
+		}
+
+		// Join links together and concatenate with notice text
+		$notice_text .= join( '', $links );
+	}
+
+	return apply_filters( 'bp_get_settings_pending_email_notice', $notice_text, $r, $args );
 }
-add_action( 'bp_before_member_settings_template', 'bp_settings_pending_email_notice' );
