Understanding Drupal 7 hook_mail()

Understanding Drupal’s hook_mail() implementation is essential if you want your custom modules to send emails. It is, however, one of the strangest hook implementations you will find in Drupal.

But have no fear! In this post we will dig into the details of sending emails with Drupal. The focus will be on Drupal 7 but not much has changed in the newest version so most of the information presented will still apply for Drupal 6. In order to understand sending mail in Drupal you will need to learn how to implement hook_mail() and grasp the inner workings of the drupal_mail() function. Let’s start by looking at drupal_mail(). You can find the documentation at http://api.drupal.org/api/drupal/includes%21mail.inc/function/drupal_mail/7. Let’s see an example of sending an email from the user module. Imagine that you have a custom module that wants to send the default user registration mail. Simply add a call to drupal_mail() like this:

1
2
3
4
5
6
7
8
<?php
$to = 'alice@example.com';
$params['account'] = user_load_by_mail($to);
$message = drupal_mail('user', 'register_no_approval_required', $to, language_default(), $params, 'no-reply@example.com', TRUE);
if (!empty($message['result']) {
  drupal_set_message("Mail sent!");
}
?>

The following parameters are expected by drupal_mail().

Parameter Description Example Default
$module The module that defines this mail template. ‘user’ N/A
$key A string that identifies the template to send. This will be defined in hook_mail() for the module provided in the first parameter. ‘register_no_approval_required’ N/A
$to Send the email to this address. ‘alice@example.com’ N/A
$language The language object for mail translation. language_default() N/A
$params An array of params to send to the template. These will be used in the hook_mail() implementation. array('account' => $account) An empty array()
$from Send the email from this address. ‘no-reply@example.com’ An empty string
$send TRUE to send the mail. Can be set to FALSE to generate the mail from the template but not actually send. FALSE TRUE

But where does the value for $key come from? And what happens to $params? I’m glad you asked. Before a mail can be sent using drupal_mail(), a ‘template’ must be defined in a hook_mail() implementation. hook_mail() is responsible for filling the message text and subject line for the mail message. A typical hook_mail() implementation might look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?php
/**
 * Implements hook_mail().
 */
function my_module_mail($key, &$message, $params) {
  switch($key) {
    case 'awesome_mail_one':
      $message['subject'] = "Awesome message #1";
      $message['body'][] = "This is a very important message!";
      break;
 
    case 'awesome_mail_two':
      $message['subject'] = "Awesome message #2";
      $message['body'][] = "This is another very important message!";
      break;
  }
}
?>

Now when drupal_mail() is called and passed ‘my_module’ and ‘awesome_mail_one’ for the $module and $key parameters respectively, the appropriate body and subject will be filled in before the mail is sent. Note: $message['body'] is an array of lines for the mail body. Each line will be separated by a blank line in the final message. See DefaultMailSystem::mail(). Any values passed to drupal_mail() in the $params array can be used as replacement text in hook_mail(). For example, you can pass first name value to hook_mail() by defining it in $params.

1
2
3
4
5
<?php
// Add this where you what to send the mail.
$params = array('first_name' => 'Bob');
drupal_mail('my_module', 'awesome_mail_one', 'bob@example.com', language_default(), $params);
?>

Then use the passed in parameter as a replacement in hook_mail().

1
2
3
4
5
6
7
<?php
// Change this in my_module_mail().
case 'awesome_mail_one':
  $message['subject'] = t("Awesome message #1 for @name", array('@name' => $params['first_name']));
  $message['body'][] = "This is a very important message!";
  break;
?>

Note: One downside of this method is that you must know what $params a mail key requires before calling drupal_mail(). There is currently no way to programmatically determine what $params a key requires.

Here are some other thing to keep in mind.

Further reading

Tweet

Comments:

Subscribe & Contact

Know how to listen, and you will profit even from those who talk badly.
~ Plutarch ~