drupal_mail
- Versions
- 5
drupal_mail($mailkey, $to,$subject,$body, $from = NULL,$headers= array())- 6 – 7
drupal_mail($module, $key, $to, $language, $params = array(), $from = NULL, $send = TRUE)
Compose and optionally send an e-mail message.
Sending an e-mail works with defining an e-mail template (subject, text and possibly e-mail headers) and the replacement values to use in the appropriate places in the template. Processed e-mail templates are requested from hook_mail() from the module sending the e-mail. Any module can modify the composed e-mail message array using hook_mail_alter(). Finally drupal_mail_send() sends the e-mail, which can be reused if the exact same composed e-mail is to be sent to multiple recipients.
Finding out what language to send the e-mail with needs some consideration. If you send e-mail to a user, her preferred language should be fine, so use user_preferred_language(). If you send email based on form values filled on the page, there are two additional choices if you are not sending the e-mail to a user on the site. You can either use the language used to generate the page ($language global variable) or the site default language. See language_default(). The former is good if sending e-mail to the person filling the form, the later is good if you send e-mail 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 e-mails 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 e-mail at hand.
An example:
<?php
function example_notify($accounts) {
foreach ($accounts as $account) {
$params['account'] = $account;
// example_mail() will be called based on the first drupal_mail() parameter.
drupal_mail('example', 'notice', $account->mail, user_preferred_language($account), $params);
}
}
function example_mail($key, &$message, $params) {
$language = $message['language'];
$variables = user_mail_tokens($params['account'], $language);
switch($key) {
case 'notice':
$message['subject'] = t('Notification from !site', $variables, $language->language);
$message['body'][] = t("Dear !username\n\nThere is new content available on the site.", $variables, $language->language);
break;
}
}
?>
Parameters
$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.
$key A key to identify the e-mail sent. The final e-mail id for e-mail altering will be {$module}_{$key}.
$to The e-mail address or addresses where the message will be sent to. The formatting of this string must comply with RFC 2822. Some examples are: user@example.com user@example.com, anotheruser@example.com User <user@example.com> User <user@example.com>, Another User <anotheruser@example.com>
$language Language object to use to compose the e-mail.
$params Optional parameters to build the e-mail.
$from Sets From to this value, if given.
$send Send the message directly, without calling drupal_mail_send() manually.
Return value
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 e-mail, 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.)
Code
includes/mail.inc, line 82
<?php
function drupal_mail($module, $key, $to, $language, $params = array(), $from = NULL, $send = TRUE) {
$default_from = variable_get('site_mail', ini_get('sendmail_from'));
// Bundle up the variables into a structured array for altering.
$message = array(
'id' => $module .'_'. $key,
'to' => $to,
'from' => isset($from) ? $from : $default_from,
'language' => $language,
'params' => $params,
'subject' => '',
'body' => array()
);
// Build the default headers
$headers = array(
'MIME-Version' => '1.0',
'Content-Type' => 'text/plain; charset=UTF-8; format=flowed; delsp=yes',
'Content-Transfer-Encoding' => '8Bit',
'X-Mailer' => 'Drupal'
);
if ($default_from) {
// To prevent e-mail from looking like spam, the addresses in the Sender and
// Return-Path headers should have a domain authorized to use the originating
// SMTP server. Errors-To is redundant, but shouldn't hurt.
$headers['From'] = $headers['Sender'] = $headers['Return-Path'] = $headers['Errors-To'] = $default_from;
}
if ($from) {
$headers['From'] = $from;
}
$message['headers'] = $headers;
// Build the e-mail (get subject and body, allow additional headers) by
// invoking hook_mail() on this module. We cannot use module_invoke() as
// we need to have $message by reference in hook_mail().
if (function_exists($function = $module .'_mail')) {
$function($key, $message, $params);
}
// Invoke hook_mail_alter() to allow all modules to alter the resulting e-mail.
drupal_alter('mail', $message);
// Concatenate and wrap the e-mail body.
$message['body'] = is_array($message['body']) ? drupal_wrap_mail(implode("\n\n", $message['body'])) : drupal_wrap_mail($message['body']);
// Optionally send e-mail.
if ($send) {
$message['result'] = drupal_mail_send($message);
// Log errors
if (!$message['result']) {
watchdog('mail', 'Error sending e-mail (from %from to %to).', array('%from' => $message['from'], '%to' => $message['to']), WATCHDOG_ERROR);
drupal_set_message(t('Unable to send e-mail. Please contact the site administrator if the problem persists.'), 'error');
}
}
return $message;
}
?>Login or register to post comments 
If you want to just send a freaking e-mail...
...like you could in Drupal 5, without going through this convoluted e-mail template registry system, you can call the drupal_mail_send() function directly.
For example:
<?php
$message = array(
'to' => 'example@mailinator.com',
'subject' => t('Example subject'),
'body' => t('Example body'),
'headers' => array('From' => 'example@mailinator.com'),
);
drupal_mail_send($message);
?>
I'm sure someone from the i18n team will jump in here and explain why this is pure, unadulterated evil, but sometimes this is all you need. :P
Caveats:
- Because drupal_mail() isn't called, other modules will not be able to hook_mail_alter() your output, which can cause unexpected results.
- drupal_mail_send() is ignorant about which language to send the message in, so this needs to be figured out beforehand.
- You'll have to manually specify any other e-mail headers that are required ('Content-Type', etc.). These are normally taken care of for you by drupal_mail().
In the case where your module sends several different types of e-mails, and you want those e-mail templates to be editable (for example, user module's various registration notification/password reset/etc. e-mails), using hook_mail() is still the best way to go.
Sounds like you already know why it's evil
I'm not officially on the i18n team, though I may one day be, so apologies if I'm talking out of turn, but you did more or less ask to be told this!
Your caveats are surely sufficiently major issues, especially the first two which look 'proper evil' (as the kids round here would say).
Why would you ever want to skip the mechanisms put in place to make the email system work flawlessly? I don't understand. I'm no advocate of excessive complexity, but the email registry system seems to me to be a two-step system rather than the one-step (with at least two big caveats) which you propose.
Perhaps all it needs is a significantly clearer documentation page here?
Done well, the registry needn't seem convoluted, the code need scarcely be longer than what I imagine you had in Drupal 5 (correct me if I'm wrong though) and more to the point no-one's module will break anyone else's. Drupal heaven!
drupal_mail needs body and subject arguments
I agree with webchick. Although the system is robust and powerful for involved modules, sending a simple email is like having go to the next building to use the bathroom. drupal_mail just needs the obvious missing arguments -- subject, body, and maybe email_type = plain text or html. Then you would not have to implement hook_mail just so you can grab subject and body from the params array and put them where drupal_mail wants them in the first place. I think everyone expects to be able to just pass those arguments in along with to and from.
Alternatively, drupal_mail_send could take the email_type argument and it would be almost as good. But you don't get any of the benefits of drupal_mail. Thanks webchick for the helpful documentation.