8.5.x core.api.php hook_mail($key, &$message, $params)
8.0.x core.api.php hook_mail($key, &$message, $params)
8.1.x core.api.php hook_mail($key, &$message, $params)
8.2.x core.api.php hook_mail($key, &$message, $params)
8.3.x core.api.php hook_mail($key, &$message, $params)
8.4.x core.api.php hook_mail($key, &$message, $params)
8.6.x core.api.php hook_mail($key, &$message, $params)
6.x core.php hook_mail($key, &$message, $params)
7.x system.api.php hook_mail($key, &$message, $params)

Prepare a message based on parameters; called from drupal_mail().


$key: An identifier of the mail.

$message: An array to be filled in. Keys in this array include:

  • 'id': An id to identify the mail sent. Look at module source code or drupal_mail() for possible id values.
  • 'to': The address or addresses the message will be sent to. The formatting of this string must comply with RFC 2822.
  • 'subject': Subject of the e-mail to be sent. This must not contain any newline characters, or the mail may not be sent properly. drupal_mail() sets this to an empty string when the hook is invoked.
  • 'body': An array of lines containing the message to be sent. Drupal will format the correct line endings for you. drupal_mail() sets this to an empty array when the hook is invoked.
  • 'from': The address the message will be marked as being from, which is set by drupal_mail() to either a custom address or the site-wide default email address when the hook is invoked.
  • 'headers: Associative array containing mail headers, such as From, Sender, MIME-Version, Content-Type, etc. drupal_mail() pre-fills several headers in this array.

$params: An arbitrary array of parameters set by the caller to drupal_mail.

Related topics

8 functions implement hook_mail()

Note: this list is generated by pattern matching, so it may include some functions that are not actually implementations of this hook.

contact_mail in modules/contact/contact.module
Implementation of hook_mail().
drupal_mail in includes/mail.inc
Compose and optionally send an e-mail message.
drupal_wrap_mail in includes/mail.inc
Perform format=flowed soft wrapping for mail (RFC 3676).
system_mail in modules/system/system.module
Implementation of hook_mail().
update_mail in modules/update/update.module
Implementation of hook_mail().

... See full list


developer/hooks/core.php, line 2643
These are the hooks that are invoked by the Drupal core.


function hook_mail($key, &$message, $params) {
  $account = $params['account'];
  $context = $params['context'];
  $variables = array(
    '%site_name' => variable_get('site_name', 'Drupal'),
    '%username' => $account->name,
  if ($context['hook'] == 'taxonomy') {
    $object = $params['object'];
    $vocabulary = taxonomy_vocabulary_load($object->vid);
    $variables += array(
      '%term_name' => $object->name,
      '%term_description' => $object->description,
      '%term_id' => $object->tid,
      '%vocabulary_name' => $vocabulary->name,
      '%vocabulary_description' => $vocabulary->description,
      '%vocabulary_id' => $vocabulary->vid,

  // Node-based variable translation is only available if we have a node.
  if (isset($params['node'])) {
    $node = $params['node'];
    $variables += array(
      '%uid' => $node->uid,
      '%node_url' => url('node/' . $node->nid, array(
        'absolute' => TRUE,
      '%node_type' => node_get_types('name', $node),
      '%title' => $node->title,
      '%teaser' => $node->teaser,
      '%body' => $node->body,
  $subject = strtr($context['subject'], $variables);
  $body = strtr($context['message'], $variables);
  $message['subject'] .= str_replace(array(
  ), '', $subject);
  $message['body'][] = drupal_html_to_text($body);


ransom’s picture

!site_name' => variable_get('site_name', 'Drupal'),
'!username' => $account->name, 
'!login_url' => url($base_path ."user", array("absolute" => TRUE)),

and you wouldn't get EM's if you happen to pass it through t() at some point for example to localize languages. like

$language = $message['language'];
$account = $params['account'];
$variables = user_mail_tokens($params['account'], $language);

$body =  t("This is an email "$variables, $language->language);
$message['body'][] = str_replace($frommsg,$tomsg, $body);

please note the code is non-functional just bits from what I've been working however should give you an idea of what I'm talking about.. if your sending localized node content this concept would probably work better for you.

Perhaps though I'm off base when it comes to core however, I used this to formulate a hook that the EM's and other things were driving me a bit nuts for more days than I'd like to admit. That and discrepancy's that come into mailing from sending mail through diferent methods. Perhaps I should file an issue however I'm not confidant in my own abilities to do that.

Anyhow hope it helps someone.

fuerst’s picture

If you are surprised why hook_mail() does not fire please note http://drupal.org/node/945456: hook_mail, unlike a hook_mail_alter, executes only on behalf of emails generated from within its own module.

Use hook_mail_alter() if you want to modify emails generated by other modules.

flyzi’s picture


on drupal 7,
I want to send a notification email with links.
But I am faced with the links that appear as:
LeTitreDeMonLien [1]
[1] http://monlien

I would like to integrate my direct link without this strange formatting.

First, I create an action from the administration interface:
Panel> actions> send an email
I have in the body of my mail:


%Resume is a list of articles (in the end, an article on one line)

function MYMODULE_mail($key, &$message, $params) {
  switch($key) {
      case "resume" :
        $variables = array('%Resume' => 'Test google');

  $subject = strtr($params['subject'], $variables);
  $message['subject'] .= str_replace(array("\r", "\n"), '', $subject);
  foreach($params['body'] as $aline) {
$body = strtr($aline, $variables);
$message['body'][] = drupal_html_to_text($article);

In another function:

/ / I retrieve the various data in advance of the action set above (subject, body, etc.). 
drupal_mail('MYMODULE', 'resume', $to, language_default(), $params, $from, TRUE) 

Where someone can come see my problem?

Thank you in advance,