diff --git role_change_notify.module role_change_notify.module
index ccd81c7..3e03c8b 100644
--- role_change_notify.module
+++ role_change_notify.module
@@ -77,7 +77,7 @@ function role_change_notify_perm() {
  * implements hook_info to provide 'role_added/removed' op from hook_user.
  */
 function role_change_notify_hook_info() {
-  return array(
+  $triggers = array(
     'user' => array(
       'user' => array(
         'role_added' => array(
@@ -89,6 +89,17 @@ function role_change_notify_hook_info() {
       ),
     ),
   );
+
+  $roles = user_roles(TRUE);
+  unset($roles[DRUPAL_AUTHENTICATED_RID]);
+  foreach ($roles as $roleid => $rolename) {
+    $triggers['user']['user']['role_' . $roleid . '_added']['runs when'] =
+      t("When the %role role is added to an account", array('%role' => $rolename));
+    $triggers['user']['user']['role_' . $roleid . '_removed']['runs when'] =
+      t("When the %role role is removed from an account", array('%role' => $rolename));
+  }
+
+  return $triggers;
 }
 
 /**
@@ -97,10 +108,16 @@ function role_change_notify_hook_info() {
  */
 function role_change_notify_action_info_alter(&$info) {
   $my_hooks = array('role_added', 'role_removed');
-  $actions_to_alter = array('token_actions_message_action', 'token_actions_send_email_action');
+  $roles = user_roles(TRUE);
+  unset($roles[DRUPAL_AUTHENTICATED_RID]);
+  foreach ($roles as $roleid => $rolename) {
+    $my_hooks[] = 'role_' . $roleid . '_added';
+    $my_hooks[] = 'role_' . $roleid . '_removed';
+  }
+  $actions_to_alter = array('token_actions_message_action', 'token_actions_send_email_action', 'views_bulk_operations_delete_user_action', 'views_bulk_operations_user_roles_action');
   foreach ($actions_to_alter as $action) {
     if (isset($info[$action])) {
-      if (empty($info[$action]['hooks']['user'])) {
+      if (!isset($info[$action]['hooks']['user'])) {
         $info[$action]['hooks']['user'] = array();
       }
       $info[$action]['hooks']['user'] = array_merge($info[$action]['hooks']['user'], $my_hooks);
@@ -212,7 +229,6 @@ function _role_change_notify_trigger_actions($op, $account) {
  */
 function role_change_notify_user_update($edit, $account) {
   $roles = user_roles(TRUE);
-  $account = user_load($account->uid);
   $oldroles = array_keys($account->roles);
   $newroles = array_keys($edit['roles']);
   $rolesadded = array_diff($newroles, $oldroles);
@@ -232,6 +248,7 @@ function role_change_notify_user_update($edit, $account) {
     }
     // Invoke actions that should take place on role addition.
     _role_change_notify_trigger_actions('role_added', $account);
+    _role_change_notify_trigger_actions('role_' . $roleid . '_added', $account);
 
     if (variable_get("role_change_notify_$roleid", FALSE)) {
       if (valid_email_address($account->mail) && valid_email_address($from)) {
@@ -267,8 +284,10 @@ function role_change_notify_user_update($edit, $account) {
     $role = $roles[$roleid];
     $account->rolename = $role;
     _role_change_notify_trigger_actions('role_removed', $account);
+    _role_change_notify_trigger_actions('role_' . $roleid . '_removed', $account);
   }
 }
+
 /**
  * Implementation of hook_mail().
  *
@@ -323,9 +342,12 @@ function _role_change_notify_get_variables($account, $rolename) {
   if ($account->uid && module_exists('profile')) {
     profile_load_profile($account);
     $role_change_user_keys = array_keys(get_object_vars($account));
-    foreach($role_change_user_keys as $keys){
-      if(strpos($keys, 'profile_') === 0){
-        $variables['['.$keys.']'] = check_plain($account->$keys);
+    foreach($role_change_user_keys as $key){
+      if (strpos($key, 'profile_') === 0) {
+        $value = _role_change_notify_format_profile_field($account->$key);
+        if (!empty($value)) {
+          $variables['['.$key.']'] = $value;
+        }
       }
     }
   }
@@ -350,8 +372,11 @@ function role_change_notify_token_values($type, $account = NULL) {
     if (module_exists('profile')) {
       $keys = array_keys(get_object_vars($account));
       foreach($keys as $key) {
-        if(strpos($key, 'profile_') === 0 && !empty($account->$key)) {
-          $tokens[$key] = check_plain($account->$key);
+        if (strpos($key, 'profile_') === 0) {
+          $value = _role_change_notify_format_profile_field($account->$key);
+          if (!empty($value)) {
+            $tokens[$key] = $value;
+          }
         }
       }
     }
@@ -360,6 +385,34 @@ function role_change_notify_token_values($type, $account = NULL) {
 }
 
 /**
+ * Format a profile field value into an HTML-escaped string
+ *
+ * @param $value
+ *   The profile field value
+ *
+ * @return
+ *   Formatted string
+ */
+function _role_change_notify_format_profile_field($value) {
+  if (is_string($value)) {
+    return check_plain($value);
+  } elseif (is_array($value) && isset($value['day'])) {
+    // duplicate the date formatting in profile_view_field()
+    $format = substr(variable_get('date_format_short', 'm/d/Y - H:i'), 0, 5);
+    $replace = array(
+      'd' => sprintf('%02d', $value['day']),
+      'j' => $value['day'],
+      'm' => sprintf('%02d', $value['month']),
+      'M' => map_month($value['month']),
+      'Y' => $value['year'],
+      'H:i' => NULL,
+      'g:ia' => NULL,
+    );
+    return strtr($format, $replace);
+  } // else return NULL (all profile fields should be strings or date arrays)
+}
+
+/**
  * Implementation of hook_token_list().
  */
 function role_change_notify_token_list($type = 'profile') {
diff --git role_change_notify.test role_change_notify.test
index 4e3ce7f..899fdec 100644
--- role_change_notify.test
+++ role_change_notify.test
@@ -45,6 +45,7 @@ class TriggerWebTestCase extends DrupalWebTestCase {
 class RoleChangeNotifyTestCase extends TriggerWebTestCase {
   protected $web_user;
   protected $admin_user;
+  protected $prev_mail_count = 0;
 
   public static function getInfo() {
     return array(
@@ -73,34 +74,34 @@ class RoleChangeNotifyTestCase extends TriggerWebTestCase {
     // Login the admin user.
     $this->drupalLogin($this->admin_user);
     // Create a role that we'll use for testing.
-    $newrole = $this->drupalCreateRole(array('access content'), 'testrole');
+    $newrole1 = $this->drupalCreateRole(array('access content'), 'testrole1');
+    $newrole2 = $this->drupalCreateRole(array('access content'), 'testrole2');
 
     // Configure notifications for the new role
-    $edit = array("role_change_notify_$newrole" => TRUE);
-    $this->drupalPost("admin/user/role_change_notify", $edit, t('Save configuration'));
+    $edit = array("role_change_notify_$newrole1" => TRUE);
+    $this->drupalPost('admin/user/role_change_notify', $edit, t('Save configuration'));
 
     // Test the typical use from the role_change_notify form.
-    $this->assignRole($this->web_user, $newrole);
+    $this->assignRole($this->web_user, $newrole1);
 
-    $this->assertText(t("User @user notified of added role @role", array('@user' => $this->web_user->name, '@role' => 'testrole')));
-    $this->assertMail('to', $this->web_user->mail, t("Email is to the correct user"));
+    $this->assertText(t('User @user notified of added role @role', array('@user' => $this->web_user->name, '@role' => 'testrole1')));
+    $this->assertMail('to', $this->web_user->mail, t('Email is to the correct user'));
 
-    $msg = t('The role "@role" has been added', array('@role' => 'testrole'));
-    $this->assertEmailBodyText($msg, t("Expected 'role has been added' text found in email body"), $msg);
-    $this->verboseEmail();
+    $this->assertEmailBodyText(t('The role "@role" has been added', array('@role' => 'testrole1')));
+    $this->prev_mail_count = $this->verboseEmail();
 
     // Turn off standard non-trigger notifications.
-    $edit = array("role_change_notify_$newrole" => FALSE);
-    $this->drupalPost("admin/user/role_change_notify", $edit, t('Save configuration'));
+    $edit = array("role_change_notify_$newrole1" => FALSE);
+    $this->drupalPost('admin/user/role_change_notify', $edit, t('Save configuration'));
 
     // Create an advanced system_message_action to issue a message.
-    $message = "Message: Role added=[role_changed] User=[user]";
+    $message = 'Message: Role added=[role_changed] User=[user]';
     $actions_edit = array(
       'actions_description' => 'RCN Add Role',
       'message' => $message,
     );
 
-    if (defined("Issue736598Committed")) {
+    if (defined('Issue736598Committed')) {
       $aid = $this->configureAdvancedAction('token_actions_message_action', $actions_edit);
       $edit = array('aid' => md5($aid));
       // And assign it to the role_added trigger.
@@ -113,37 +114,63 @@ class RoleChangeNotifyTestCase extends TriggerWebTestCase {
       $this->assertEqual(1, count($actions), t('One Action assigned to the hook'));
       $this->assertEqual($actions[$aid]['label'], $actions_edit['actions_description'], t('Correct action label found.'));
 
-      // Now change the role and see if we get the system message.
-      $this->assignRole($this->admin_user, $newrole);
+      // Also assign the action to the role_$newrole2_added trigger.
+      $this->drupalPost('admin/build/trigger/user', $edit, t('Assign'), array(), array(), 'trigger_user_role_' . $newrole2 . '_added_assign_form');
 
-      $this->assertText(t("Message: Role added=@role User=@user", array('@role' => 'testrole', '@user' => $this->admin_user->name)));
 
+      // Verify that the action has been assigned to the correct hook.
+      $actions = $this->trigger_get_assigned_actions('role_' . $newrole2 . '_added');
+      $this->assertEqual(1, count($actions), t('One Action assigned to the hook'));
+      $this->assertEqual($actions[$aid]['label'], $actions_edit['actions_description'], t('Correct action label found.'));
+
+      // Assign role1 and see if we get the general system message, but not the role2 specific one
+      $this->assignRole($this->admin_user, $newrole1);
+
+      $this->assertUniqueText(t('Message: Role added=@role User=@user', array('@role' => 'testrole1', '@user' => $this->admin_user->name)));
+
+      // Assign role2 and see if we get both the general and specific system messages
+      $this->assignRole($this->admin_user, $newrole2);
+
+      $this->assertNoUniqueText(t('Message: Role added=@role User=@user', array('@role' => 'testrole2', '@user' => $this->admin_user->name)));
 
       // Create a system email message that will be sent when a role is removed.
-      $message = "Message: Role removed=[role_changed] User=[user]";
+      $message = 'Message: Role removed=[role_changed] User=[user]';
       $actions_edit = array(
-      'actions_description' => 'RCN Remove Role',
-      'recipient' => 'nobody@example.com',
-      'subject' => t('Role removal message'),
-      'message' => $message,
+        'actions_description' => 'RCN Remove Role',
+        'recipient' => 'nobody@example.com',
+        'subject' => t('Role removal message'),
+        'message' => $message,
       );
       $aid = $this->configureAdvancedAction('token_actions_send_email_action', $actions_edit);
       $edit = array('aid' => md5($aid));
       // And assign it to the role_removed trigger.
       $this->drupalPost('admin/build/trigger/user', $edit, t('Assign'), array(), array(), 'trigger_user_role_removed_assign_form');
 
-
       // Verify that the action has been assigned to the correct hook.
       $actions = $this->trigger_get_assigned_actions('role_removed');
       $this->assertEqual(1, count($actions), t('One Action assigned to the hook "role_removed"'));
       $this->assertEqual($actions[$aid]['label'], $actions_edit['actions_description'], t('Correct action label found.'));
 
-      // Now change the role and see if we get the system message.
-      $this->removeRole($this->admin_user, $newrole);
+      // Also assign the action to the role_$newrole2_removed trigger.
+      $this->drupalPost('admin/build/trigger/user', $edit, t('Assign'), array(), array(), 'trigger_user_role_' . $newrole2 . '_removed_assign_form');
 
-      $this->verboseEmail();
-      $this->assertEmailBodyText(t("Message: Role removed=@role User=@user", array('@role' => 'testrole', '@user' => $this->admin_user->name)));
-      $this->assertMail('to', $actions_edit['recipient'], t("Correct recipient for role removed email"));
+      // Verify that the action has been assigned to the correct hook.
+      $actions = $this->trigger_get_assigned_actions('role_' . $newrole2 . '_removed');
+      $this->assertEqual(1, count($actions), t('One Action assigned to the hook "role_%rid_removed"', array('%rid' => $newrole2)));
+      $this->assertEqual($actions[$aid]['label'], $actions_edit['actions_description'], t('Correct action label found.'));
+
+      // Remove role1 and see if we get the general email, but not the role2 specific one
+      $this->removeRole($this->admin_user, $newrole1);
+
+      $this->assertEmailBodyText(t('Message: Role removed=@role User=@user', array('@role' => 'testrole1', '@user' => $this->admin_user->name)));
+      $this->assertMail('to', $actions_edit['recipient'], t('Correct recipient for role removed email'));
+      $this->prev_mail_count = $this->verboseEmail();
+
+      // Remove role2 and see if we get both the general and specific emails
+      $this->removeRole($this->admin_user, $newrole2);
+
+      $this->assertEmailBodyText(t('Message: Role removed=@role User=@user', array('@role' => 'testrole2', '@user' => $this->admin_user->name)), 2);
+      $this->prev_mail_count = $this->verboseEmail();
     } // End comment-out of section.
   }
 
@@ -154,19 +181,26 @@ class RoleChangeNotifyTestCase extends TriggerWebTestCase {
    * @param string $message
    *   Message for simpletest.
    */
-  protected function assertEmailBodyText($regex) {
+  protected function assertEmailBodyText($regex, $expected = 1) {
     $mails = $this->drupalGetMails();
-    $mail = end($mails);
-    $regex_found = preg_match("/$regex/", $mail['body']);
-    $this->assertTrue($regex_found, t("Email notification of role was sent."));
+    $mail_count = count($mails);
+    $regex_found = 0;
+    for ($i = $this->prev_mail_count; $i < $mail_count; $i++) {
+      $regex_found += preg_match("/$regex/", $mails[$i]['body']);
+    }
+    $this->assertTrue($regex_found == $expected, t('Email notification of role was sent.'));
   }
+
   /**
    * Output the most recent email sent.
    */
   protected function verboseEmail() {
     $mails = $this->drupalGetMails();
-    $mail = end($mails);
-    $this->verbose(t("Email  was:") . "<pre>" . print_r($mail, TRUE) . "</pre>");
+    $mail_count = count($mails);
+    for ($i = $this->prev_mail_count; $i < $mail_count; $i++) {
+      $this->verbose(t('Email  was:') . '<pre>' . print_r($mails[$i], TRUE) . '</pre>');
+    }
+    return $mail_count;
   }
 
   /**
@@ -179,8 +213,8 @@ class RoleChangeNotifyTestCase extends TriggerWebTestCase {
    */
   protected function assignRole($account, $role) {
     $edit = array('operation' => "add_role-$role", "accounts[{$account->uid}]" => TRUE);
-    $this->drupalPost("admin/user/user", $edit, t("Update"));
-    $this->assertText(t("The update has been performed"));
+    $this->drupalPost('admin/user/user', $edit, t('Update'));
+    $this->assertText(t('The update has been performed'));
   }
 
   /**
@@ -193,8 +227,8 @@ class RoleChangeNotifyTestCase extends TriggerWebTestCase {
    */
   protected function removeRole($account, $role) {
     $edit = array('operation' => "remove_role-$role", "accounts[{$account->uid}]" => TRUE);
-    $this->drupalPost("admin/user/user", $edit, t("Update"));
-    $this->assertText(t("The update has been performed"));
+    $this->drupalPost('admin/user/user', $edit, t('Update'));
+    $this->assertText(t('The update has been performed'));
   }
   /**
    * This is stolen from D7 trigger_get_assigned_actions().
