move fields in the user profile form in fieldsets
As you mentioned the problem appears in user_account_form_validate() because you changed the account index from $form['account']['mail'] to $form['change_mail']['mail']

the issue is with this line form_set_value($form['account']['mail'], $mail, $form_state);

In order to achieve what you are looking for you need to replace existing form validation with a custom validation as the following code:

function MODULE_NAME_form_user_profile_form_alter(&amp;$form, &amp;$form_state, $form_id) {

  $form['change_mail'] = array(
    '#type' =&gt; 'fieldset',
    '#title' =&gt; 'change email address cake',
    '#weight' =&gt; 6,
    '#collapsible' =&gt; FALSE,
    '#tree' =&gt; FALSE,
  );

  $form['change_mail']['mail'] = $form['account']['mail'];
  unset($form['account']['mail']);
  $form['change_mail']['confirm_mail'] = $form['account']['confirm_mail'];
  unset($form['account']['confirm_mail']);


  $form['#validate'][0] = 'MODULE_NAME_user_account_form_validate';
}


function MODULE_NAME_user_account_form_validate($form, &amp;$form_state) {
  $form['account']['mail'] = $form['change_mail']['mail'];
  // original validation function
  user_account_form_validate($form, $form_state);
}