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. Commented 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. Commented Apr 18, 2016 at 15:34
  • that would be drupalcontrib.org/api/drupal/… Commented Apr 18, 2016 at 15:50
  • Still need to lookup the Country of the content first. Commented 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? Commented 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. Commented Nov 6, 2016 at 7:54
  • Merci Niall, never thought about that privacy issue, good point! Commented 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. Commented 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! Commented 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)));

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.