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.
drupal_mail()
calls$module_mail()
directly. There is no call tomodule_invoke_all()
.- You can alter a mail before it is sent using
hook_mail_alter()
. See http://api.drupal.org/api/drupal/modules!system!system.api.php/function/hook_mail_alter/7 - You can disable a mail by implementing
hook_mail_alter()
and setting$message['send'] = FALSE;
.
Comments: