1 mail.inc backdrop_mail($module, $key, $to, $language, $params = array(), $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 backdrop_mail_system()->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 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 email 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 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 backdrop_mail() parameter.
      backdrop_mail('example', 'notice', $account->mail, user_preferred_language($account), $params);

  function example_mail($key, &$message, $params) {
    $data['user'] = $params['account'];
    $options['language'] = $message['language'];
    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;
        $langcode = $message['language']->langcode;
        $message['subject'] = t('Notification from !site', $variables, array('langcode' => $langcode));
        $message['body'][] = t("Dear !username\n\nThere is new content available on the site.", $variables, array('langcode' => $langcode));

Another example, which uses backdrop_mail() to format a message for sending later:

  $params = array('current_conditions' => $data);
  $to = 'user@example.com';
  $message = backdrop_mail('example', 'notice', $to, $language, $params, FALSE);
  // Only add to the spool if sending was not canceled.
  if ($message['send']) {


$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 email sent. The final email id for email altering will be {$module}_{$key}.

$to: The email address or addresses where the message will be sent to. The formatting of this string must comply with RFC 2822. Some examples are:

$language: Language object to use to compose the email.

$params: Optional parameters to build the email.

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

$send: If TRUE, backdrop_mail() will call backdrop_mail_system()->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

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.)


core/includes/mail.inc, line 119
API functions for processing and sending email.


function backdrop_mail($module, $key, $to, $language, $params = array(), $reply = NULL, $send = TRUE) {
  $from = config_get('system.core', 'site_mail');
  if (empty($from)) {
    $from = ini_get('sendmail_from');

  // Bundle up the variables into a structured array for altering.
  $message = array(
    'id' => $module . '_' . $key,
    'module' => $module,
    'key' => $key,
    'to' => $to,
    'from' => $from,
    'reply-to' => isset($reply) ? $reply : $from,
    'language' => $language,
    'params' => $params,
    'send' => TRUE,
    'subject' => '',
    'body' => array()

  // Build the default headers. Note that the first letter of each word is
  // always capitalized. See: https://tools.ietf.org/html/rfc5322
  $headers = array(
    'MIME-Version' => '1.0',
    'Content-Type' => 'text/plain; charset=UTF-8; format=flowed; delsp=yes',
    'Content-Transfer-Encoding' => '8Bit',
    'X-Mailer' => 'Backdrop CMS'
  if ($from) {
    // To prevent email from looking like spam, the addresses in the Sender and
    // Return-Path headers should have a domain authorized to use the originating
    // SMTP server.
    $headers['From'] = $headers['Sender'] = $headers['Return-Path'] = $from;
  if ($reply) {
    $headers['Reply-To'] = $reply;
  $message['headers'] = $headers;

  // Build the email (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 email.
  backdrop_alter('mail', $message);

  // Retrieve the responsible implementation for this message.
  $system = backdrop_mail_system($module, $key);

  // Format the message body.
  $message = $system->format($message);

  // Optionally send email.
  if ($send) {
    // The original caller requested sending. Sending was canceled by one or
    // more hook_mail_alter() implementations. We set 'result' to NULL, because
    // FALSE indicates an error in sending.
    if (empty($message['send'])) {
      $message['result'] = NULL;
    // Sending was originally requested and was not canceled.
    else {
      $message['result'] = $system->mail($message);
      // Log errors.
      if (!$message['result']) {
        watchdog('mail', 'Error sending email (from %from to %to).', array('%from' => $message['from'], '%to' => $message['to']), WATCHDOG_ERROR);
        backdrop_set_message(t('Unable to send email.'), 'error');

  return $message;