I'm attempting to send an email from a Drupal 8 module I'm developing, and it works except that special characters (' < >) seem to be getting escaped.

My module has a configuration to select whether the emails are plain text or HTML (using Swiftmailer). In plain text messages, apostrophes get replaced by &#039; while in the HTML messages, all HTML tags receive similar treatment, so the message arrives, but the HTML tags are all shown in the message, rather than formatting it.

Heres an extract from my hook_mail handler:

  $message['subject'] = $params['subject'];
  $body = $params['body'];
  if ($config->get('confirmation.format_html')) {
    // Set up HTML email.
    $message['headers']['Content-Type'] = 'text/html; charset=UTF-8';
    $message['body'][] = $body;  // HTML version of message body.
    $message['plain'] = \Drupal\Component\Utility\SafeMarkup::checkPlain($params['body']);  // Plain text version of body.
  } else {
    $message['body'][] = $params['body'];  // Plain text version of body.

It seems there's some escapement of special HTML characters going on, but I can't see where?

  • Have you tried to check_plain() the body field.
    – user72672
    Sep 6, 2017 at 12:10

1 Answer 1


Make sure what you're passing in is a renderable array... and render it before assigning it to the message body field:

  $markup = ['#markup' => "<strong>We do HTML</strong>"];
  $message['body'][] = render($markup);

Note: This makes some sense i guess but i really just stumbled onto the solution, so i'm not sure how correct it is, but it works.

Incidentally, for the plain-text version i recommend doing what Drupal core's PHP mailer does in its format method:

use Drupal\Core\Mail\MailFormatHelper;

// Join the body array into one string.
$message['body'] = implode("\n\n", $message['body']);

// Convert any HTML to plain-text.
$message['body'] = MailFormatHelper::htmlToText($message['body']);
// Wrap the mail body for sending.
$message['body'] = MailFormatHelper::wrapMail($message['body']);

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.