I'm using Profile2 module to assign a Country to a Role. For example I have:

  • User1 | Role: "International Members" | Country: "UK"
  • User2 | Role: "International Members" | Country: "Poland"
  • User3 | Role: "International Members" | Country: "Japan"
  • User4 | Role: "International Members" | Country: "US"

My content also has a field Country.

I have this Rule:


  • After saving new content
  • After updating existing content


  • Content is published


  • Send mail to all users of a role (International Members)

That is sending email to all users in Role "International Members". I would like to:

  1. Lookup the Country of the content
  2. Send email to only those "International Members" whose profile Country matches the one of the content.

So If I publish a content with Country set as "US" it should only send an email to User4.

Any idea?

  • All I can think of is making a custom rules actions. let see if we can get something from contrib. Apr 18, 2016 at 15:22
  • I think I could accomplish it easily by overwriting TO field in the Rule action "Send Email". But don't know which hook allows to do that. Apr 18, 2016 at 15:34
  • that would be drupalcontrib.org/api/drupal/… Apr 18, 2016 at 15:50
  • Still need to lookup the Country of the content first. Apr 18, 2016 at 15:53

3 Answers 3


You need to use the action "fetch entity by property" and then use the country field and supply the country.

That will create a list to loop through so you can send mails.

  • Hey Niall, not to hijack your answer, but am I correct that you mean "Send a separated eMail to each of the selected users (so NOT just 1 eMail with in the 'to' all selected users)"? If my assumption is correct: can you think of any technique in rules actions to send only 1 eMail, but "to" multiple eMail IDs? Or do you think I should post that as a brand new question? Nov 5, 2016 at 16:25
  • To be honest, I've never done too much with emails so I don't know but few sites would ever want multiple users in the to: of one email unless they were bcc'd. It's a breach of privacy if done wrong. Nov 6, 2016 at 7:54
  • Merci Niall, never thought about that privacy issue, good point! Nov 6, 2016 at 16:29

To make this work you may want to give it a try to process the results of a VBO enabled view via Rules, whereas your rule performs 2 Rules Actions:

  • Load the VBO list that you want to be processed.
  • Add a loop to perform a Rules Action, for each row contained in your Views results.

some more details about the VBO-view you'd have to create for this:

  • It should include an appropriate filter of the Country.
  • It should have exactly 1 result (row) for each user to be eMailed.
  • One of the columns should be the eMail Id (I don't see other columns needed for this to work).

For more details, have a look at the tutorial "How to process the results of a VBO enabled view via Rules?".

  • Thanks for reply, ended up doing custom action for Rules. it just seemed easier to implement. Oct 31, 2016 at 8:10
  • 1
    @KlaatuVerataNecto : merci beaucoup for sharing your own solution just now (via your extra answer)! I'd say "depends what you call easier, but that's the beuty of Drupal of course. Though I must admit your own solution/answer is a great illustration of writing custom rules! so therefor also +1 from me! Oct 31, 2016 at 8:15

In the end I ended up doing custom Action for Rules module

enter image description here

function rulesemailsamecountry_rules_action_info() {
$actions = array(
    'rulesemailsamecountry_action_sendemailroleandcountry' => array(
        'label' => t('Send mail to all users of a role that match country node'),
        'group' => t('Custom'),
          'parameter' => array(
            'roles' => array(
              'type' => 'list<integer>',
              'label' => t('Roles'),
              'options list' => 'entity_metadata_user_roles',
              'description' => t('Select the roles whose users should receive the mail.'),
            'subject' => array(
              'type' => 'text',
              'label' => t('Subject'),
              'description' => t("The mail's subject."),
            'message' => array(
              'type' => 'text',
              'label' => t('Message'),
              'description' => t("The mail's message body."),
            'from' => array(
              'type' => 'text',
              'label' => t('From'),
              'description' => t("The mail's from address. Leave it empty to use the site-wide configured address."),
              'optional' => TRUE,
      'base' => 'rules_action_mail_to_users_of_role_by_country',
      'access callback' => 'rules_system_integration_access', 

return $actions;

function rules_action_mail_to_users_of_role_by_country($roles, $subject, $message, $from = NULL, $settings, RulesState $state, RulesPlugin $element) {

  $from = !empty($from) ? str_replace(array("\r", "\n"), '', $from) : NULL;

  // All authenticated users, which is everybody.
  if (in_array(DRUPAL_AUTHENTICATED_RID, $roles)) {
    $result = db_query('SELECT mail FROM {users} WHERE uid > 0');
  else {
    $rids = implode(',', $roles);
    $country_code = $state->get('node')->value()->field_country['und'][0]['iso2'];    
    // Avoid sending emails to members of two or more target role groups.
    $query = "
    DISTINCT u.mail 
    FROM {users} u 
    INNER JOIN {users_roles} r ON u.uid = r.uid
    INNER JOIN profile p ON p.uid = u.uid
    INNER JOIN field_data_field_profile_country c ON c.entity_id = p.pid
    WHERE r.rid IN ('".$rids."')
    AND c.field_profile_country_iso2 = '".$country_code."'";

    $result = db_query($query);    

  // Now, actually send the mails.
  $params = array(
    'subject' => $subject,
    'message' => $message,
  // Set a unique key for this mail.
  $name = isset($element->root()->name) ? $element->root()->name : 'unnamed';
  $key = 'rules_action_mail_to_users_of_role_' . $name . '_' . $element->elementId();  $languages = language_list();

  $message = array('result' => TRUE);
  foreach ($result as $row) {
    $message = drupal_mail('rules', $key, $row->mail, language_default(), $params, $from);
    // If $message['result'] is FALSE, then it's likely that email sending is
    // failing at the moment, and we should just abort sending any more. If
    // however, $mesage['result'] is NULL, then it's likely that a module has
    // aborted sending this particular email to this particular user, and we
    // should just keep on sending emails to the other users.
    // For more information on the result value, see drupal_mail().
    if ($message['result'] === FALSE) {
  if ($message['result'] !== FALSE) {
    $role_names = array_intersect_key(user_roles(TRUE), array_flip($roles));
    watchdog('rules', 'Successfully sent email to the role(s) %roles.', array('%roles' => implode(', ', $role_names)));

This site is temporarily in read-only mode and not accepting new answers.

Not the answer you're looking for? Browse other questions tagged .