7 mail.inc drupal_mail($module, $key, $to, $language, $params = array(), $from = NULL, $send = TRUE)
5 common.inc drupal_mail($mailkey, $to, $subject, $body, $from = NULL, $headers = array())
6 mail.inc drupal_mail($module, $key, $to, $language, $params = array(), $from = NULL, $send = TRUE)

Composes and optionally sends 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_system()->mail() 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:

  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) {
    $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;
          break;
        }
        $langcode = $message['language']->language;
        $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));
        break;
    }
  }

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

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

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 will be validated with the PHP e-mail validation filter. Some examples are:

$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: If TRUE, drupal_mail() will call drupal_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 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.)

8 calls to drupal_mail()
contact_personal_form_submit in modules/contact/contact.pages.inc
Form submission handler for contact_personal_form().
contact_site_form_submit in modules/contact/contact.pages.inc
Form submission handler for contact_site_form().
hook_watchdog in modules/system/system.api.php
Log an event message.
MailTestCase::testCancelMessage in modules/simpletest/tests/mail.test
Test that message sending may be canceled.
MailTestCase::testPluggableFramework in modules/simpletest/tests/mail.test
Assert that the pluggable mail system is functional.

... See full list

File

includes/mail.inc, line 122
API functions for processing and sending e-mail.

Code

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,
    'module' => $module,
    'key' => $key,
    'to' => $to,
    'from' => isset($from) ? $from : $default_from,
    'language' => $language,
    'params' => $params,
    'send' => TRUE,
    '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.
    $headers['From'] = $headers['Sender'] = $headers['Return-Path'] = $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);

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

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

  // Optionally send e-mail.
  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 e-mail (from %from to %to).', array('%from' => $message['from'], '%to' => $message['to']), WATCHDOG_ERROR);
        drupal_set_message(t('Unable to send e-mail. Contact the site administrator if the problem persists.'), 'error');
      }
    }
  }

  return $message;
}

Comments

Make your emails support HTML. Put code snippet inside hook_mail() or hook_mail_alter() (remove php tags).

<?php
 
// Make emails HTML friendly
 
$message['headers']['Content-Type'] = 'text/html; charset=UTF-8; format=flowed';
?>

This no longer appears to work in Drupal 7. Everything gets converted to plain text.

I tried it by using the following lines:

$message = drupal_mail($module, $key, 'someone[@t]nilecode.com', language_default(), array(), 'anothermail[@t]nilecode.com', FALSE);

$message['headers']['Content-Type'] = 'text/html; charset=UTF-8; format=flowed';

$sentMessage = array();
$sentMessage[] = 'Line1..........';
$sentMessage[] = 'Line2..........';

$message['body'] = implode('<br/>', $sentMessage);

// Make sure the following line is commented/omitted
//  $message = $system->format($message);

// Send e-mail.
$message['result'] = $system->mail($message);

It actually worked perfectly on Drupal 7. I included it in the hook_mail function of my module, in which I switch among possible email ids. Be careful to set it before you set the 'body' elements. I had no HTML-based message setting it after the 'body' elements.

I tried sending a drupal mail and added a footer to the mail and added a link to the footer but the text is not linked to the url instead, it seperated both the text and the link. Example of the output in my mail is this:

* Testing Page 1 [1]
* Testing Page 2 [2]
You are subscribed to email updates from JUST NEWS [3].
To stop receiving these emails, you may unsubscribe now [4].
Email Delivery Powered by LORRIS [5]

[1] http://website.com/article/testing-page-1
[2] http://website.com/article/testing-page-2
[3] http://www.website.tv
[4] http://www.website.tv/?q=unsubscribe_subscription
[5] http://www.website.com

and the source code is:

$unsubscribe_msg = "
You are subscribed to email updates from JUST NEWS.
To stop receiving these emails, you may unsubscribe now.
Email Delivery Powered by LORRIS";

$rows = array();
try
{
$query = db_select('node','n')->extend('PagerDefault');
$query->join('field_data_body','fdb','n.nid=fdb.entity_id');
$query->limit(25);
$query->condition('created',$from_when,'>=');
$query->condition('bundle','article');

$query = $query->extend('TableSort');
$query->fields('n');
$query->fields('fdb');

$result = $query->execute();
$summary = "";

foreach ($result as $row)
{

$rows[] =
array(
array('data'=>l($row->title, get_url_alias($row->nid) ,array('attributes' => array('target'=>'_blank'))),),
);

$link_titles[] = l($row->title, get_url_alias($row->nid) ,array('attributes' => array('target'=>'_blank')));
}

$link = "";
foreach ($link_titles as $key) {
$link .= "

  • $key
  • ";
    }

    $msg_prefix = $link."".$unsubscribe_msg;

    return $msg_prefix;
    }

    How do i get the output be linked together not separated from itself

    Example usage:

        $module = 'module_name';
        $key = 'key';
        $language = language_default();
        $params = array();
        $from = NULL;
        $send = FALSE;
        $message = drupal_mail($module, $key, $email, $language, $params, $from, $send);

        $message['subject'] = $subject;
        $message['body'] = array();
        $message['body'][] = $line1;
        $message['body'][] = $line2;

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

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

        // Send e-mail.
        $message['result'] = $system->mail($message);

    The "Examples for Developers" module (http://drupal.org/project/examples) has a really nice example and it explains how everything works in more detail that what's on this page. Here is the source code of their example:

    http://drupalcode.org/project/examples.git/blob_plain/refs/heads/7.x-1.x...

    Below is the tutorial of usage in D6:
    drupal_mail usage tutorial

    ...and since many things have changed in Drupal 7, here's a tutorial on how to use a wrapper function to easily send mail using drupal_mail().

    The given example code cannot correctly replace placeholders in email subject and body. Here is the correct code:

    <?php
      $message
    ['subject'] = t('Alert from !site', array('!site' => variable_get('site_name', "Default site name")), array('langcode' => $langcode));
     
    $message['body'][] = t("Dear !username\n\nThere is new content available on the site.", array('!username' => $params['account']->name), array('langcode' => $langcode));
    ?>

    The Parameter $language must not be an object, but a string like "de" or "en".

    This is actually completely wrong; the $language parameter must be an object and NOT a 2-letter langcode string. The docs really need updating to make this clearer, but if you read the source code of functions like language_default() you'll see they return a language object.

    If you need further evidence, search Drupal 7 core's modules for drupal_mail() calls, and you'll find it either passes in language_default() as above, or the global $language object.

    Is it possible to use more than one email address to $FROM?

    how can i also include Cc and Bcc fields in $message so that drupal_mail sends mails to them aswell ....

    https://api.drupal.org/comment/26814#comment-26814

    $message['headers']['CC'] = user_email;

    Parameters for BCC and CC

    $params = array(
    'body' => $body,
    'subject' => $subject,
    'headers' => array(
    'Bcc' => $header_bcc,
    'Cc' => $header_cc
    )
    );
    $email = drupal_mail('ModuleName', 'message_key', $to, LANGUAGE_NONE, $params, $from, true);

    I m using drupal_mail for sending emails. How to make the arabic email content aligned from Right to Left? Should i work on css or any seperate templates for emails? Please help me

    The propper way to use this:

    /**
    * Implements hook_entity_insert().
    *
    */
    function dummy_module_node_insert($node) {
      $module = 'dummy_module';
      $key = 'dummy_key';
      $language = language_default();
      $params = array(
        '@url' => url('node/' . $node->nid, array('absolute' => TRUE)),
        '@title' => $node->title,
      );

      drupal_mail($module, $key, $mail, $language, $params);
    }

    /**
    * Implements hook_mail().
    */
    function dummy_module_mail($key, &$message, $params) {
      $message['subject'] = t("@title event registration confirmation", $params);
      $message['body'] = array();
      $message['body'][] = t("Hello", $params);
      $message['body'][] = t("Node has been created @title (@url).", $params);
    }

    There may some errors but this the overall way to use it.

    Thanks for posting this! It helped a lot. I wasn't including the

    <?php
     
    array('absolute' => TRUE);
    ?>

    part on my url parameter.

    How to change the direction of the content as RTL for emails in arabic language ?

    using this in a custom function built off the examples module caused a fail. renaming the module to MODULENAME rather than MODULENAME_OTHERNAME did the trick. FYI.

    I tried sending a drupal mail and added a footer to the mail and added a link to the footer but the text is not linked to the url instead, it seperated both the text and the link. Example of the output in my mail is this:

    * Testing Page 1 [1]
    * Testing Page 2 [2]
    You are subscribed to email updates from JUST NEWS [3].
    To stop receiving these emails, you may unsubscribe now [4].
    Email Delivery Powered by LORRIS [5]

    [1] http://website.com/article/testing-page-1
    [2] http://website.com/article/testing-page-2
    [3] http://www.website.tv
    [4] http://www.website.tv/?q=unsubscribe_subscription
    [5] http://www.website.com

    and the source code is:

    $unsubscribe_msg = "
    You are subscribed to email updates from JUST NEWS.
    To stop receiving these emails, you may unsubscribe now.
    Email Delivery Powered by LORRIS";

    $rows = array();
    try
    {
    $query = db_select('node','n')->extend('PagerDefault');
    $query->join('field_data_body','fdb','n.nid=fdb.entity_id');
    $query->limit(25);
    $query->condition('created',$from_when,'>=');
    $query->condition('bundle','article');

    $query = $query->extend('TableSort');
    $query->fields('n');
    $query->fields('fdb');

    $result = $query->execute();
    $summary = "";

    foreach ($result as $row)
    {

    $rows[] =
    array(
    array('data'=>l($row->title, get_url_alias($row->nid) ,array('attributes' => array('target'=>'_blank'))),),
    );

    $link_titles[] = l($row->title, get_url_alias($row->nid) ,array('attributes' => array('target'=>'_blank')));
    }

    $link = "";
    foreach ($link_titles as $key) {
    $link .= "

  • $key
  • ";
    }

    $msg_prefix = $link."".$unsubscribe_msg;

    return $msg_prefix;
    }

    How do i get the output be linked together not separated from itself

    I tried to change from email address using hook_mail_alter(). The code is given below:

    <?php
    /**
     * Implements hook_mail_alter() for send mail to admin in cc
     */
    function test_commerce_mail_alter(&$message) {
      if (
    $message['id'] == 'rules_rules_action_mail_commerce_checkout_order_email_3') {

        if (!empty(
    $store_email)) {
         
    $message['from'] = '"'. variable_get('site_name', 'Test commerce') .'" <xxx@gmail.com>';
         
    $message['headers']['From'] = $message['from'];
         
    $message['headers']['Reply-To'] = $message['from'];
         
    //$message['headers']['Return-Path'] = $message['from'];
          //$message['headers']['Sender'] = $message['from'];
         
    $message['headers']['Cc'] = xxx@gmail.com;
        }
      }
    }
    ?>

    But i can't change from email addres. By default it sets site_mail.