Skip to content

Email

views

Send email

Function to send an email in your module with a hook_mail() to set the parameters. Also don't forget the hook_mail function below that needs to be in your module file.

php
use Drupal\Core\Mail\MailManagerInterface;
use Drupal\Core\Language\LanguageManagerInterface;

/**
 * Function to send an email in your module.
 *
 * @param string $to
 *   The recipient of the email.
 * @param array $params
 *   An array of parameters to use in the email.
 * @param string $subject
 *   The subject of the email.
 * @param string $body
 *   The body of the email.
 *
 * @return bool
 *   TRUE if the email was sent successfully, FALSE otherwise.
 */
function send_my_email($to, $params, $subject, $body) {
  // Get the language manager service.
  $language_manager = \Drupal::service('language_manager');

  // Get the default language.
  $default_language = $language_manager->getDefaultLanguage()->getId();

  // Get the mail manager service.
  $mail_manager = \Drupal::service('plugin.manager.mail');

  // Set up the email parameters.
  $module = 'my_module';
  $key = 'my_email_key';

  // Get the email headers.
  $headers = [
    'Content-Type' => 'text/html; charset=UTF-8; format=flowed; delsp=yes',
    'From' => 'sender@example.com',
    'Reply-To' => 'reply-to@example.com',
  ];

  // Set up the email body.
  $body_params = [
    'message' => $params['message'],
    'name' => $params['name'],
  ];

  // Send the email.
  $result = $mail_manager->mail($module, $key, $to, $default_language, $body_params, NULL, TRUE, $headers);

  // Return the result.
  return $result['result'];
}

Note

Don`t forget to add this to your .module file or no email will ever be sent!

php
/**
 * Implements hook_mail().
 */
function my_module_mail($key, &$message, $params) {
  switch ($key) {
    case 'my_email_key':
      $message['subject'] = t('My Email Subject');
      $message['body'][] = $params['message'];
      $message['body'][] = t('From: @name', ['@name' => $params['name']]);
      break;
  }
}

General send email function with logging

php
  /**
   * Send email notification.
   *
   * @param array $to_email_addresses
   *   Array of email addresses.
   * @param string|null $from
   *   From email address.
   * @param string $subject
   *   Message subject.
   * @param string $message_body
   *   Message in plain text.
   *
   * @return array
   *   The render array for screen display.
   */
  public function sendEmail(array $to_email_addresses, string|null $from, string $subject, string $message_body): array {
    /*
     * Notifications will only be sent from prod environment.
     * Configured in settings.php (or settings.local.php)
     * For development, use this in settings.local.php:
     * $config['tabcblah.status_change_notifications']
     * ['send_notifications'] = TRUE;
     */
    $send_notifications = \Drupal::config('tea_teks.status_change_notifications')->get('send_notifications');

    if (is_null($from)) {
      $from = \Drupal::config('system.site')->get('mail');
    }
    $results = [];
    $email_validator = \Drupal::getContainer()->get('email.validator');
    if (!$send_notifications) {
      $results[0]['status'] = 'success';
      return $results;
    }
    foreach ($to_email_addresses as $to_email_address) {
      // Check if it's a valid email address.
      if (!$email_validator->isValid($to_email_address)) {
        continue;
      }
      $language_code = \Drupal::config('system.site')->get('langcode');
      // Get the mail manager service.
      $mail_manager = \Drupal::service('plugin.manager.mail');
      $headers = ['Content-Type' => 'text/html; charset=UTF-8'];
      $params = [
        'headers' => $headers,
        'from' => $from,
        'subject' => $subject,
        'body' => $message_body,
      ];

      // Send the email.
      $response = $mail_manager->mail('tea_teks', 'tea_teks_public_comment_error_form_notification', $to_email_address, $language_code, $params, NULL, TRUE);
      $response_message = t('Email to %to, from: %from, subject: %subject: Send result: %result.', [
        '%result' => $response['result'] ? t('success') : t('fail'),
        '%subject' => $subject,
        '%from' => $from,
        '%to' => implode('; ', $to_email_addresses),
      ]);
      $results[] = [
        'status' => $response['result'] ? t('success') : t('fail'),
        'message' => $response_message,
      ];
      if (!$response['result']) {
        \Drupal::logger('tea_teks_srp')->error($response_message);
      }
    }
    return $results;
  }

Note

Don't forget to add the hook_mail in your .module file.

php
/**
 * Implements hook_mail().
 */
function tea_teks_mail($key, &$message, $params) {

  $site_name = \Drupal::config('system.site')->get('name');
  $site_mail = \Drupal::config('system.site')->get('mail');

  switch ($key) {
    case 'tea_teks_public_comment_error_form_notification':
      $message['headers']['Reply-To'] = $site_mail;
//      $message['headers']['Content-Type'] = 'text/html';
//      $message['headers']['Content-Type']= 'text/html; charset=utf-8; format=flowed; delsp=yes';
      $message['headers']['Content-Type'] = 'text/plain; charset=utf-8';
      $message['headers']['From'] = $site_name .'<' . $site_mail . '>';
      $message['subject'] = t('@subject', array('@subject' => $params['subject']));
      $message['body'][] = Xss::filter($params['body'], ['a', 'b', 'br', 'em', 'i', 'strong', 'u', 'p']);
      break;
    case 'tea_teks_publisher_status_notification':
    default:
      $message['headers']['Reply-To'] = $site_mail;
      $message['headers']['Content-Type'] = 'text/html';
      $message['headers']['From'] = $site_name .'<' . $site_mail . '>';
      $message['subject'] = t('@subject', array('@subject' => $params['subject']));
      $message['body'][] = Xss::filter($params['body']);
      break;
  }
}

Using tokens in hook_mail

Here is an example in a hook_mail call where tokens are used:

php
/**
 * Implements hook_mail().
 */
function hello_world_mail($key, &$message, $params) {
  switch ($key) {
    case 'hello_world_log':
      $message['from'] = \Drupal::config('system.site')->get('mail');
      $message['subject'] = t('There is an error on your website');
      $message['body'][] = $params['message'];
      if (isset($params['user'])) {
        $user_message = 'The user that was logged in: [current-user:name]';
        $message['body'][] = \Drupal::token()->replace($user_message, ['current-user' => $params['user']]);
      }

      break;
  }
}

Useful helper functions

See docroot/core/lib/Drupal/Core/Mail/MailFormatHelper.php for more.

php
// Break a body field into paragraphs.
$message['body'] = implode("\n\n", $message['body']);

// Transforms an HTML string into plain text, preserving its structure.
$message['body'] = MailFormatHelper::htmlToText($message['plaintext']);

// Performs format=flowed soft wrapping for mail (RFC 3676).
$message['body'] = MailFormatHelper::wrapMail($message['plaintext']);

and here are a few more.

  • MailFormatHelper::htmlToText() - Transforms an HTML string into plain text, preserving its structure.
  • MailFormatHelper::wrapMailLine() - Wraps words on a single line.
  • MailFormatHelper::htmlToMailUrls() - Keeps track of URLs and replaces them with placeholder tokens.
  • MailFormatHelper::htmlToTextClean() - Replaces non-quotation markers from a piece of indentation with spaces.
  • MailFormatHelper::htmlToTextPad() - Pads the last line with the given character.

Troubleshooting

Mail sends but no subject or body

This means you either forgot to create the hook_mail module or that your key doesn't match. Try changing the key in your hook mail to be a default and see if that works

php
function tea_teks_mail($key, &$message, $params) {

  $site_name = \Drupal::config('system.site')->get('name');
  $site_mail = \Drupal::config('system.site')->get('mail');
  switch ($key) {
    case 'tea_teks_public_comment_error_form_notification':
      $message['headers']['Reply-To'] = $site_mail;
      $message['headers']['Content-Type'] = 'text/html';
      $message['headers']['From'] = $site_name .'<' . $site_mail . '>';
      $message['subject'] = t('@subject', array('@subject' => $params['subject']));
      break;
    default:
      $message['headers']['Reply-To'] = $site_mail;
      $message['headers']['Content-Type'] = 'text/html';
      $message['headers']['From'] = $site_name .'<' . $site_mail . '>';
      $message['subject'] = t('@subject', array('@subject' => $params['subject']));
      $message['body'][] = Xss::filter($params['body']);
      break;
  }
}

Reference