2

I am trying to implement html mail notifications using htmlmail module. I am not certain if message should be formatted as array in $message["body][] before the template or passed as a string in $message['body'].

The reason I am asking is that I first expected the email to be sent in as a string but then saw the HTMLMAILSystem::format function that flattens the body array:

  public function format(array $message) {
    $eol = variable_get('mail_line_endings', MAIL_LINE_ENDINGS);
    // @todo Remove this when issue #209672 gets resolved.
    $default_from = variable_get('site_mail', ini_get('sendmail_from'));
    if ( !empty($message['headers']['From'])
      && $message['headers']['From'] == $default_from
      && valid_email_address($default_from)
    ) {
      $message['headers']['From'] = '"'
      . str_replace('"', '', variable_get('site_name', 'Drupal'))
      . '" <' . $default_from . '>';
    }
    // Collapse the message body array.
    if (module_exists('mailmime')) {
      $body = $this->formatMailMIME($message);
      $plain = $message['MailMIME']->getTXTBody();
    }
    else {
      if (is_array($message['body'])) {
        $message['body'] = implode("<br />$eol<br />$eol", $message['body']);
      }
      $body = theme('htmlmail', $message);
      if ($message['body'] && !$body) {
        watchdog(
          'htmlmail',
          'The %theme function did not return any text.  Please check your template file for errors.',
          array('%theme' => "theme('htmlmail', \$message)"),
          WATCHDOG_WARNING
        );
        $body = $message['body'];
      }

So if I understood correctly, message must be preformatted with correct html in $message["body"][] , but I am not 100% sure there are lots of code-bits involved for email sendouts. I also need to validate if this will allow me to send mail as plaintext?

2
  • Where are the email notifications originating from? Custom module? Are you worried whether or not they are going to be formatted in HTML or not?
    – Brady
    Jul 16, 2015 at 9:00
  • Wow, this was asked two and a half years ago!
    – Brady
    Jul 16, 2015 at 9:03

1 Answer 1

1

In Drupal 7, it's the implementation of MailSystemInterface::format() that formats the message body and changes it to a string; before that, $message['body'] is supposed to be an array.
In Drupal 6, drupal_mail() receives an array for $message['body'], and changes it in a string.

// drupal_mail() in Drupal 6

// Build the e-mail (get subject and body, allow additional headers) by
  // invoking hook_mail() on this module. We cannot use module_invoke() as
  // we need to have $message by reference in hook_mail().
  if (function_exists($function = $module . '_mail')) {
    $function($key, $message, $params);
  }

  // Invoke hook_mail_alter() to allow all modules to alter the resulting e-mail.
  drupal_alter('mail', $message);

  // Concatenate and wrap the e-mail body.
  $message['body'] = is_array($message['body']) ? drupal_wrap_mail(implode("\n\n", $message['body'])) : drupal_wrap_mail($message['body']);

Compare the code you are showing with the code used by the Drupal 7 implementation (DefaultMailSystem::format()).

public function format(array $message) {
  // Join the body array into one string.
  $message['body'] = implode("\n\n", $message['body']);
  // Convert any HTML to plain-text.
  $message['body'] = drupal_html_to_text($message['body']);
  // Wrap the mail body for sending.
  $message['body'] = drupal_wrap_mail($message['body']);
  return $message;
}

Drupal requiring $message['body'] to be an array of strings is made clear in hook_mail_alter(), which describes it as follows:

  • 'body': An array of strings containing the message text. The message body is created by concatenating the individual array strings into a single text string using "\n\n" as a separator.

Since hook_mail_alter() is invoked right before the format() method, that method is supposed to get an array, not a string.

 // drupal_mail() in Drupal 7

 // Bundle up the variables into a structured array for altering.
  $message = array(
    'id' => $module . '_' . $key,
    'module' => $module,
    'key' => $key,
    'to' => $to,
    'from' => isset($from) ? $from : $default_from,
    'language' => $language,
    'params' => $params,
    'send' => TRUE,
    'subject' => '',
    'body' => array(),
  );

  //  …

  // Build the e-mail (get subject and body, allow additional headers) by
  // invoking hook_mail() on this module. We cannot use module_invoke() as
  // we need to have $message by reference in hook_mail().
  if (function_exists($function = $module . '_mail')) {
    $function($key, $message, $params);
  }

  // Invoke hook_mail_alter() to allow all modules to alter the resulting e-mail.
  drupal_alter('mail', $message);

  // Retrieve the responsible implementation for this message.
  $system = drupal_mail_system($module, $key);

  // Format the message body.
  $message = $system->format($message);

The only reason I could see to check if $message['body'] is a string is to protect the code against modules not correctly updated in the passage from Drupal 5 to Drupal 6. In fact, Drupal 5 passed a string for body, as evident in the example for hook_mail_alter() shown in the documentation.

function hook_mail_alter(&$mailkey, &$to, &$subject, &$body, &$from, &$headers) {
  $body .= "\n\n--\nMail sent out from " . variable_get('sitename', t('Drupal'));
}

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.