8.5.x MailManager.php MailManager::mail($module, $key, $to, $langcode, $params = [], $reply = NULL, $send = TRUE)
8.0.x MailManager.php MailManager::mail($module, $key, $to, $langcode, $params = array(), $reply = NULL, $send = TRUE)
8.1.x MailManager.php MailManager::mail($module, $key, $to, $langcode, $params = array(), $reply = NULL, $send = TRUE)
8.2.x MailManager.php MailManager::mail($module, $key, $to, $langcode, $params = array(), $reply = NULL, $send = TRUE)
8.3.x MailManager.php MailManager::mail($module, $key, $to, $langcode, $params = [], $reply = NULL, $send = TRUE)
8.4.x MailManager.php MailManager::mail($module, $key, $to, $langcode, $params = [], $reply = NULL, $send = TRUE)
8.6.x MailManager.php MailManager::mail($module, $key, $to, $langcode, $params = [], $reply = NULL, $send = TRUE)

Composes and optionally sends an email message.

Sending an email works with defining an email template (subject, text and possibly email headers) and the replacement values to use in the appropriate places in the template. Processed email templates are requested from hook_mail() from the module sending the email. Any module can modify the composed email message array using hook_mail_alter(). Finally \Drupal::service('plugin.manager.mail')->mail() sends the email, which can be reused if the exact same composed email is to be sent to multiple recipients.

Finding out what language to send the email with needs some consideration. If you send email to a user, her preferred language should be fine, so use \Drupal\Core\Session\AccountInterface::getPreferredAdminLangcode(). If you send email based on form values filled on the page, there are two additional choices if you are not sending the email to a user on the site. You can either use the language used to generate the page or the site default language. See Drupal\Core\Language\LanguageManagerInterface::getDefaultLanguage(). The former is good if sending email to the person filling the form, the later is good if you send email to an address previously set up (like contact addresses in a contact form).

Taking care of always using the proper language is even more important when sending emails in a row to multiple users. Hook_mail() abstracts whether the mail text comes from an administrator setting or is static in the source code. It should also deal with common mail tokens, only receiving $params which are unique to the actual email at hand.

An example:

function example_notify($accounts) {
  foreach ($accounts as $account) {
    $params['account'] = $account;

    // example_mail() will be called based on the first
    // MailManagerInterface->mail() parameter.
      ->mail('example', 'notice', $account->mail, $langcode, $params);
function example_mail($key, &$message, $params) {
  $data['user'] = $params['account'];
  $options['langcode'] = $message['langcode'];
  user_mail_tokens($variables, $data, $options);
  switch ($key) {
    case 'notice':

      // If the recipient can receive such notices by instant-message, do
      // not send by email.
      if (example_im_send($key, $message, $params)) {
        $message['send'] = FALSE;
      $message['subject'] = t('Notification from @site', $variables, $options);
      $message['body'][] = t("Dear @username\n\nThere is new content available on the site.", $variables, $options);

Another example, which uses MailManagerInterface->mail() to format a message for sending later:

$params = array(
  'current_conditions' => $data,
$to = 'user@example.com';
$message = \Drupal::service('plugin.manager.mail')
  ->mail('example', 'notice', $to, $langcode, $params, FALSE);

// Only add to the spool if sending was not canceled.
if ($message['send']) {


string $module: A module name to invoke hook_mail() on. The {$module}_mail() hook will be called to complete the $message structure which will already contain common defaults.

string $key: A key to identify the email sent. The final message ID for email altering will be {$module}_{$key}.

string $to: The email address or addresses where the message will be sent to. The formatting of this string will be validated with the PHP email validation filter. Some examples are:

string $langcode: Language code to use to compose the email.

array $params: (optional) Parameters to build the email.

string|null $reply: Optional email address to be used to answer.

bool $send: If TRUE, call an implementation of \Drupal\Core\Mail\MailInterface->mail() to deliver the message, and store the result in $message['result']. Modules implementing hook_mail_alter() may cancel sending by setting $message['send'] to FALSE.

Return value

array The $message array structure containing all details of the message. If already sent ($send = TRUE), then the 'result' element will contain the success indicator of the email, failure being already written to the watchdog. (Success means nothing more than the message being accepted at php-level, which still doesn't guarantee it to be delivered.)

Overrides MailManagerInterface::mail


core/lib/Drupal/Core/Mail/MailManager.php, line 166


Provides a Mail plugin manager.




public function mail($module, $key, $to, $langcode, $params = array(), $reply = NULL, $send = TRUE) {

  // Mailing can invoke rendering (e.g., generating URLs, replacing tokens),
  // but e-mails are not HTTP responses: they're not cached, they don't have
  // attachments. Therefore we perform mailing inside its own render context,
  // to ensure it doesn't leak into the render context for the HTTP response
  // to the current request.
  return $this->renderer
    ->executeInRenderContext(new RenderContext(), function () use ($module, $key, $to, $langcode, $params, $reply, $send) {
    return $this
      ->doMail($module, $key, $to, $langcode, $params, $reply, $send);


joco_sp’s picture

This is just a simple example that fires on hook_cron()

 * Implements hook_cron().
function MY_MODULE_cron() {
  $mailManager = \Drupal::service('plugin.manager.mail');
  $mailManager->mail($module, $key, $to, $langcode, $params = array(), $reply = NULL, $send = TRUE);

 * Implements hook_mail().
function MY_MODULE_mail($key, &$message, $params) {
  switch ($key) {
    case 'key':
      $message['subject'] = t('Test');
      $message['body'][] = 'Hello World!';

Pascal-’s picture

called from my custom module named eura_registerform
'registerMail' can be whatever key value you'd like to use
$params can be left empty too: $params = array();

public function submitForm(array &$form, FormStateInterface $form_state) {
    $newMail = \Drupal::service('plugin.manager.mail');
    $params['password'] = $password;
    $params['email'] = $userEmail;
    $newMail->mail('eura_registerform', 'registerMail', $userEmail, 'en', $params, $reply = NULL, $send = TRUE);
    drupal_set_message('Mail has been sent.', 'status');

and then in eura_registerform.module:

function eura_registerform_mail($key, &$message, $params) {

  // E-mail formatting will be exactly as below, so do not use indenting!
  $body =

I'm just showing off my work ...
Works nicely huh?
Should probably add a password here somewhere?

Your username: " . $params['email'] . "
Your password: " . $params['password'] . "

See ya!";

  $message['subject'] = "EuRA account registration";
  $message['body'][] = Drupal\Core\Mail\MailFormatHelper::htmlToText($body);
nehapandya55’s picture

I used below code to send mail :

 * Implements hook_cron().
function digicare_cron() {
    //module_load_include('inc', 'example');

function _digicare_drugs_reminder(){
   $bundle = 'medications';
   $query = \Drupal::entityQuery('node');
   $query->condition('status', 1);
   $query->condition('type', $bundle);
   $entity_ids = $query->execute();
   foreach($entity_ids1 as $value){
      // Get a node storage object.
     $node_storage = \Drupal::entityManager()->getStorage('node');
     // Load a single node.
     $node = $node_storage->load($value);
     $col = $node->get('field_medication')->value;
     $patient = $node->get('field_prescribed_for')->getValue();
     $pid = $patient[0]['target_id'];
     $account = \Drupal\user\Entity\User::load($pid);
     $to = $account->get('mail')->value;
     if($current == $prev){
	 $mailManager = \Drupal::service('plugin.manager.mail');
	 $mailManager->mail('digicare', 'medication_reminder', $to, $params = array(), $reply = NULL, $send =     TRUE);

 * Implements hook_mail().
function digicare_mail($key, &$message, $params) {
  switch ($key) {
    case 'medication_reminder':
      $message['subject'] = t('Prescription refill reminder');
      $message['body'][] = 'Please refill your prescription 1 day remaining.';