4

I want to send a node via rules. I can send it using the [node:body] token. However, I want to be able to use tokens in the actual node body as well. (Note: These are not global tokens)

Think of it like a newsletter and in the body field I am using

Dear [field_ef_first_name], ...

I can get the token to render if I put it directly in the rules action mail message body, but if it is in the node body field itself, it doesn't render.

The name field is coming form a views rule loop.

Rule exported:

{ "rules_send_newsletter_when_published" : {
"LABEL" : "Send newsletter when published",
"PLUGIN" : "reaction rule",
"OWNER" : "rules",
"REQUIRES" : [ "rules" ],
"ON" : { "node_insert--blog" : { "bundle" : "blog" } },
"DO" : [
  { "VIEW LOOP" : {
      "VIEW" : "entityforms",
      "DISPLAY" : "views_rules_1",
      "ROW VARIABLES" : {
        "field_ef_email" : { "email" : "Email" },
        "field_ef_first_name" : { "first_name" : "First Name" }
      },
      "DO" : [
        { "mail" : {
            "to" : "[email:value]",
            "subject" : "[node:title]",
            "message" : "[node:body]",
            "language" : [ "" ]
          }
        }
      ]
    }
  }
]

} }

1
+150

[EDIT]

While the other answers are workable, this is the simplest and closest to your current implementation using Views Rules.

First of all, be sure to enable the module PHP Filter

Also: the body of your blog needs to use the following custom token format: !first_name!. This string gets replaced inside your rule with the value of the Entityform field_ef_first_name field.

Here's the exported version of the Rule, modified from your original. SCROLL DOWN for an explanation.

{ "rules_send_newsletter_when_published" : {
    "LABEL" : "Send newsletter when published",
    "PLUGIN" : "reaction rule",
    "OWNER" : "rules",
    "REQUIRES" : [ "php", "rules" ],
    "ON" : { "node_insert--blog" : { "bundle" : "blog" } },
    "DO" : [
      { "VIEW LOOP" : {
          "VIEW" : "entityforms",
          "DISPLAY" : "views_rules_1",
          "ROW VARIABLES" : {
            "field_ef_first_name" : { "first_name" : "First name" },
            "field_ef_email" : { "email" : "Email" }
          },
          "DO" : [
            { "variable_add" : {
                "USING" : {
                  "type" : "text",
                  "value" : "\u003C?php\r\n$text = str_replace(\u0027!first_name!\u0027, $first_name, $node-\u003Ebody[LANGUAGE_NONE][0][\u0027value\u0027]);\r\necho $text;\r\n?\u003E"
                },
                "PROVIDE" : { "variable_added" : { "processed_body" : "Processed body" } }
              }
            },
            { "mail" : {
                "to" : "[email:value]",
                "subject" : "Subject",
                "message" : "[processed-body:value]",
                "language" : [ "" ]
              }
            }
          ]
        }
      }
    ]
  }
}

Here's an explanation:

This implementation of your Rule uses the action "Add a Variable" before sending the email. I named this variable "processed_body." I use PHP Evaluation to set the value of this variable:

<?php
$text = str_replace('!first_name!', $first_name, $node->body[LANGUAGE_NONE][0]['value']);
echo $text;
?>

Basically, this snippet replaces the "token" !first_name! with the value of the Views Rule loop-provided variable $first_name. Then, I use the variable processed_body to send in the email body.

NOTICE that you will need to manually process any other custom tokens that you would like to add to your Blog body. For example, if you want the body to contain the last name of the recipient (e.g. !last_name!), you'll need to manually add a str_replace function that replaces !last_name! with the correct value.

[EDIT 2]

Here's the code with an added !last_name! "token" replacement. I assume your entityform field is field_ef_last_name and it has been added to the Rules View as such.

{ "rules_send_newsletter_when_published" : {
    "LABEL" : "Send newsletter when published",
    "PLUGIN" : "reaction rule",
    "OWNER" : "rules",
    "REQUIRES" : [ "php", "rules" ],
    "ON" : { "node_insert--blog" : { "bundle" : "blog" } },
    "DO" : [
      { "VIEW LOOP" : {
          "VIEW" : "entityforms",
          "DISPLAY" : "views_rules_1",
          "ROW VARIABLES" : {
            "field_ef_first_name" : { "first_name" : "First name" },
            "field_ef_email" : { "email" : "Email" },
            "field_ef_last_name" : { "last_name" : "Last name" }
          },
          "DO" : [
            { "variable_add" : {
                "USING" : {
                  "type" : "text",
                  "value" : "\u003C?php\r\n$text = str_replace(\u0027!last_name!\u0027, $last_name, $node-\u003Ebody[LANGUAGE_NONE][0][\u0027value\u0027]);\r\n$text =  str_replace(\u0027!first_name!\u0027, $first_name, $text);\r\necho $text;\r\n?\u003E"
                },
                "PROVIDE" : { "variable_added" : { "processed_body" : "Processed body" } }
              }
            },
            { "mail" : {
                "to" : "[email:value]",
                "subject" : "[node:title]",
                "message" : "[processed-body:value]",
                "language" : [ "" ]
              }
            }
          ]
        }
      }
    ]
  }
}

The PHP code in the added Rules Variable value is

<?php
$text = str_replace('!last_name!', $last_name, $node->body[LANGUAGE_NONE][0]['value']);
$text =  str_replace('!first_name!', $first_name, $text);
echo $text;
?>
  • Sorry, I guess my example is a little too basic. I tried to keep it simple but I guess if I need to stuff some php is there to get what I want, I need to be more specific. I am using a rules views loop to loop over results of entity form submissions. In the rues view, I am setting the variable field_ef_first_name and using the core "send mail". – Nigel Waters Apr 15 '17 at 22:56
  • I have also come across this issue for Mime mail, however I am using html mail due to other dependencies in the project. drupal.org/node/2791341 – Nigel Waters Apr 15 '17 at 22:58
  • 1
    Could you export your Rule and paste in your OP above? That's probably the best way to understand what you have so far... – argiepiano Apr 16 '17 at 4:56
  • Will do. Added above in question. – Nigel Waters Apr 16 '17 at 13:15
  • 1
    @Nigel Waters: see edited answer with the added !last_name! token replacement. Thanks – argiepiano Apr 22 '17 at 3:35
2

Using tokens within the body of a node, combined with using [node:body] in a Rules Action, will only result in the token being included as is (without rendering). However, based on what you're trying to do, you may want to have a look at an entirely different approach to achieve your goal ...

Enable the Forena module (disclosure: I'm a co-maintainer), and have a look at Active Users Email (using FRX syntax), which is one of the samples included in the module (which can be used to eMail a template message body to all registered users).

These are the parts in this FRX file that are relevant to the question here:

  • The datablock drupal/active_users, which is (just) an SQL statement that looks like so:

    --ACCESS=access administration pages

    SELECT uid, name, mail, login, status

    FROM {users}

    WHERE status=1 order by name

  • The frx:foreach="*", which will cause an iteration for each row included in the results of the data block, for everything inside that div (related to the datablock).

  • The div with class="email-body", which starts with Dear {name}, and which includes a replacement token indicated with {name}.

  • The line with <frx:doc type="email" />, to enable document format "Send eMail".

After you enabled the module, and visit the relative path at /reports/drupaladmin.sample_active_users_letter, this is what will happen:

  1. Run the SQL query (as contained in the datablock).
  2. Iterate over each of the results returned by the datablock (SQL statement).
  3. For each iteration resolve all the tokens (i.e. as within that Dear {name}).
  4. Display how the eMail will actually look like (for each iteration).
  5. Add link (upper right) titled "eMail". If you actually click that "eMail" link, a confirmation screen will be shown with these details:
    • number of eMails that will be eMailed (= number of rows in the datablock).
    • radio button to either send an eMail, or actually send all eMails.

With the above in mind, this is what you'd need to get it to work for your case:

  • Clone the delivered sample, and tune it as detailed below.
  • Adapt the datablock to retrieve the desired data (columns), similar to what your view is doing. Or create a new one that fits your needs and use that one instead. Make sure to include the data related to your field_ef_email and field_ef_first_name.
  • Adapt the From, To and Subject to fit your needs.
  • Use whatever tokens you need, anywhere in the Body of your eMail. E.g. to replace that Dear {name}. If you need more, or other, data, just add an appropriate name to your datablock (as an extra column). As a sample, here is part of an FRX file I created to transform webform submissions into some kind of followup-eMail to each of those who submitted the form:

    <p>Hello,</p>

    <p>thank you for using our form (with node id = {node}) to submit your feedback (with submission id = {submission}). You're now confirmed via the eMail Id you entered (= {fieldvalue}) to receive eMails from us.</p>

    <p>We'll get back to you shortly for an additional followup eMail.</p>

1

The following creates a mail message based on a profile & commerce product, custom entity, commerce credit.

Trying to pull all these things in together without coding up your own rule or rule handler is a bit much too expect. The comment regarding random complexity and disparate objects means you don't have a sane alternative. This answer goes a long way out of the domain of rules.

There is mimemail in this setup to detect and send html mail.

I did start off with a handler, but the custom rule makes things explicit.

Rule

function yhivepasses_rules_action_info() {
  $items = array();

  $items['yhivepasses_email_passes'] = array(
    'label' => t('Send pass email'),
    'group' => t('YogaHive Passes'),
    'parameter' => array(
    'commerce_order' => array(
      'type' => 'commerce_order',
      'label' => t('Order'),
      'description' => t('The order containing the credits bought.'),
    ),
  ),
  'callbacks' => array(
    'execute' => 'yhivepasses_rules_action_send_pass_on_checkout',
  ),
);

return $items;
}

Callback function

I have just

function yhivepasses_rules_action_update_on_checkout($order) {
  $yogaHivePasses = new YogaHivePasses();
  $yogaHivePasses->checkoutRule($order);
}

Data building classes

The callback function calls a set of classes that bring the data together from the rule and secondary sources.

I shove this all into a data object.

Call drupal mail

protected function sendToStudio(YogaHivePassDao $passDao) {
 $message_studio_contact = [];
 $message_studio_contact['module'] = YogaHivePasses::MODULE_NAME;

 $this->studioContactEmail($message_studio_contact, $passDao);
 $langStudio = $this->mailSetLanguage($message_studio_contact, $passDao->getStudioUser());
 $result = drupal_mail(YogaHivePasses::MODULE_NAME, YogaHivePasses::EMAIL_KEY, $passDao->getStudioUser()->mail, $langStudio, $message_studio_contact);
}

This calls a method that builds the html mail body from a template.

Mail template processing

This relies on hook_theme which defines the templates.

public function studioContactEmail(&$message, YogaHivePassDao $passDao) {

// Needs User object. Not bothering with printing out actual order details.
$content_templated = theme('yhivepasses_studiocontact_purchase_studio_email', array(
  'passDao' => $passDao,
 ));

 $content_templated .= theme('yhivepasses_email_footer', array());
 $message['body'][] = $content_templated;
 $message['subject'] = 'Studio pass purchased on YogaHive';
 $current_credit = current($credit);
 $message['subject'] .= ' ' . $current_credit->credit_type;

 $headers = array(
  'MIME-Version' => '1.0',
  'Content-Type' => 'text/html; charset=UTF-8; format=flowed',
  'Content-Transfer-Encoding' => '8Bit',
  'X-Mailer' => 'Drupal'
 );
 foreach ($headers as $key => $value) {
  $message['headers'][$key] = $value;
 }
}

Hook mail

Hook mail is needed to add the body, subject and headers in the correct places.

function yhivepasses_mail($key, &$message, $params) {
 switch ($key) {
  case YogaHivePasses::EMAIL_KEY :
  $message['subject'] = $params['subject'];
  $message['body'] = $params['body'];

  // May not be any parameters. Parameters are mainly used to send attachments. 
  if (array_key_exists('params', $params)) {
    $message['params'] = $params['params'];
  }

  foreach ($params['headers'] as $key => $value) {
    $message['headers'][$key] = $value;
  }
  break;
default:
  return;

} }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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