[Drupal] How to send E-mail notification on profile update by user

| | 4 min read

A website will be having two kinds of users mainly, users with administrative privileges and simple users. Most of all a single root user. An administrator one of the main challenge will be in monitoring the site users and its contents. Admin should be notified regarding the new user registration and extra add-ons, etc. For a website with multiple users managing site contents and updates from user roles could become a nightmare.

In this article I wish to share my knowledge on notifying the administrator regarding the user profile update and the changes he has done. If only an update notification is needed Drupal provides a core feature to implement this. To do this login as administrator.

GOTO Rules > triggered rules > Add a new rule. A form will appear will field 'label, event, categories, weight'. Type in the appropriate label. For the events select the suitable one based on your needs in this case we are dealing with user profile update. So select the event 'User account details have been updated' and save. In the next step, select 'Add action' > select action "Send a mail to an arbitrary mail address". Final step is, configuring the mail. Under the title 'Token replacement patterns' you could find the list of replacement patterns. Saving the action notification option will be enabled for your profile update event.

With the above option as I mentioned before, it will be notification mail with limited information. If you want to see the edited/updated items the above option won't work. So I will be explaining an alternative method for this solution.

We need to write a custom code for this in our module file, implementing the hook_user() and hook_mail(). The hook_user() will be invoked when any user related activities take place. hook_user as got certain parameters such as $op, $edit, $account, $category you could find better explanation from this link https://api.drupal.org/api/drupal/developer!hooks!core.php/function/hook_user/6. We will be needed to implement the hook_user in the following way to get the updated details, the values for $op 'update', 'after_update' denotes the current state, or say the type of action performed. The parameter $category will hold the section names of the profile, as we could add a number of sections to the profile such as tabs with account information, personal information, settings etc, those will be stored in the $category variable.

The parameter '$op' tells us what kind of action is performed for users. In our case we use action 'update' and 'after_update'. First check the 'update' condition and the sections in the user profile updated.

function mymodule_user($op, &$edit, &$account, $category = NULL) {
  static $account_unchanged;

  // We don't support updates for other categories than 'account' and others validated below.
  if ($op == 'update' && $category == 'account' || $category == '<category-2>' || 
    $category == '<category-3>' || $category == '<category-4>') {
    // Save the unchanged account for the use with op after_update.
    $account_unchanged = drupal_clone($account);
  }
}

The above code will be executed on user update action. And in the 'else' condition, we check the 'after_update' condition, to get the updated content. We can get the fields by checking the difference between the '$account' and '$account_unchanged' arrays.

  else if ($op == 'after_update') {
    $user_id = $account_unchanged->uid;
    $user_name = $account_unchanged->name;
    // convert stdClass data to array.
    $account = json_decode(json_encode($account), TRUE); 
    // convert stdClass data to array.
    $account_unchanged = json_decode(json_encode($account_unchanged), TRUE); 
    // get updated fields.
    $profile_update_details = array_diff($account, $account_unchanged); 
    $profile_update_value['user_id'] = $user_id;
    $profile_update_value['user_name'] = $user_name;
    foreach($profile_update_details as $key => $profile_update_values) {
      $profile_update_value[$key] = $profile_update_values;
    }
    $to = variable_get('site_mail', 'Drupal');
    drupal_mail('jok_custom', 'profile_update', $to, user_preferred_language($account), $profile_update_value, $from = NULL, $send = TRUE);
  }

Finally, the mailing section we use drupal_mail to send mail to admin users.

<?php
/**
 * Implement hook_user().
 */
function mymodule_user($op, &$edit, &$account, $category = NULL) {
  static $account_unchanged;

  // We don't support updates for other categories than 'account'
  if ($op == 'update' && $category == 'account' || $category == '<category-2>' || 
      $category == '<category-3>' || $category == '<category-4>') {
    // Save the unchanged account for the use with op after_update.
    $account_unchanged = drupal_clone($account);
  }
  else if ($op == 'after_update') {
    $user_id = $account_unchanged->uid;
    $user_name = $account_unchanged->name;
    $account = json_decode(json_encode($account), TRUE);
    $account_unchanged = json_decode(json_encode($account_unchanged), TRUE);
    $profile_update_details = array_diff($account, $account_unchanged);
    $profile_update_value['user_id'] = $user_id;
    $profile_update_value['user_name'] = $user_name;
    foreach($profile_update_details as $key => $profile_update_values)  {
      $profile_update_value[$key] = $profile_update_values;
    }
    $to = variable_get('site_mail', 'Drupal');
    drupal_mail('mymodule', 'profile_update', $to, user_preferred_language($account), $profile_update_value, $from = NULL, $send = TRUE);
  }
}
?>

For altering the mail before send you need to implement the hook_mail function. As below,

/**
 * Implements hook_mail().
 */
function mymodule_mail($key, &$message, $params) {
  switch($key) {
    case 'profile_update':
      // code here.
    break;
  }
}

Updated values will be available in the '$params' variable as an array, in the 'profile update' condition the message can be edited, listing the updated fields.

Hope you find this article useful, there may be alternative methods to perform this that you can share with us, if any question please feel free to ask.