I would like to use the drupal_mail() function to send out emails but with a custom HTML template so that they are in keeping with my website design but I am a complete newbie to hooks and modules etc., so I'd appreciate some sort of explanation or beginners guide please.

I can create the template myself, I just need to know how to get drupal_mail() to use it.

4 Answers 4


If you are trying to send the mails via your custom module then you can follow the below mentioned guide. Say, I had one Module called "Commerce Canvas(commerce_canvas)" 1. First Alter the Drupal's mail function to support links and add other encoding types

 * Implements hook_mail_alter()
 * @param string $message
function commerce_canvas_mail_alter(&$message) {
    $headers = array(
        'MIME-Version' => '1.0',
        'Content-Type' => 'text/html; charset=iso-8859-1; format=flowed',
        'Content-Transfer-Encoding' => '8Bit',
        'X-Mailer' => 'Drupal',
    foreach ($headers as $key => $value) {
        $message['headers'][$key] = $value;
  1. Then next, hook the HOOK_mail in your module as

 * Implements hook_mail()
 * @param string $key
 * @param string $message
 * @param unknown_type $params
function commerce_canvas_mail($key, &$message, $params) {

    //Language Selection
    $options = array(
        'langcode' => $message['language']->language,
    switch($key) {
        case "user_payment_notification" :
            $message['subject'] = isset($params['subject']) ? $params['subject'] : $message['subject'] = t('Payment recieved @site-name', array('@site-name' => variable_get('site_name', 'Express Canvas')), $options);
            $message['body'][] = isset($params['body']) ? $params['body'] : NULL;
            if (isset($params['headers']) && is_array($params['headers'])) {
                $message['headers'] += $params['headers'];

  1. Then you need to create a wrapper function to invoke the mail from your module.

function commerce_canvas_mail_send(array $values = array()) {
    $module = $values['module'];
    $key = $values['key'];
    $to = $values['to'];
    $from = $values['form'];
    $language = isset($values['lang']) ? $values['lang'] : language_default();
    $params = array(
        'subject' => $values['subject'],
        'body' => $values['body'],
    if(array_key_exists('headers', $values)) {
        $params['headers'] = $values['headers']; //Assumed as an array
    $send = TRUE;
    $mail = drupal_mail($module, $key, $to, $language, $params, $from, $send);
    if($mail['result']) {
        return TRUE;
    } else {
        $error_msg = 'Failed to send the email in commerce_canvas Module';
        watchdog('canvas-email', $error_msg, array(), WATCHDOG_ALERT);
        return FALSE;

This function will send the email and as well as create debug messages if anything happens wrong. But still you won't be able to send the HTML mail because you need to extend the Drupal 7's default DefaultMailSystem with your own. So need to do as following,

class CommerceCanvasMailSystem extends DefaultMailSystem {
     * Concatenate and wrap the e-mail body for plain-text mails.
     * @param $message
     *   A message array, as described in hook_mail_alter().
     * @return
     *   The formatted $message.
    public function format(array $message) {
        $message['body'] = implode("\n\n", $message['body']);
        return $message;

     * Send an e-mail message, using Drupal variables and default settings.
     * @see http://php.net/manual/en/function.mail.php
        * @see drupal_mail()
     * @param $message
     *   A message array, as described in hook_mail_alter().
     * @return
     *   TRUE if the mail was successfully accepted, otherwise FALSE.
    public function mail(array $message) {
        $mimeheaders = array();
        foreach ($message['headers'] as $name => $value) {
            $mimeheaders[] = $name . ': ' . mime_header_encode($value);
        $line_endings = variable_get('mail_line_endings', MAIL_LINE_ENDINGS);
        return mail(
        // Note: e-mail uses CRLF for line-endings. PHP's API requires LF
        // on Unix and CRLF on Windows. Drupal automatically guesses the
        // line-ending format appropriate for your system. If you need to
        // override this, adjust $conf['mail_line_endings'] in settings.php.
        preg_replace('@\r?\n@', $line_endings, $message['body']),
        // For headers, PHP's API suggests that we use CRLF normally,
        // but some MTAs incorrectly replace LF with CRLF. See #234403.
        join("\n", $mimeheaders)

Next you need to register a new theme function that will call your custom template file in your hook_theme().

 * Implements hook_theme();
function commerce_canvas_theme($existing, $type, $theme, $path) {
  if($type == 'module') {
    return array(
      'tracking_code_email' => array(
        'variables' => array(
          'image_path' => NULL,
          'user' => NULL,
          'page' => NULL,
        'template' => 'commerce-canvas-tracking-code',
        'path' => drupal_get_path('module', 'commerce_canvas').'/theme',


Last you need to call this theme function in time of sending the email as,

function a_custom_function($params) {

$email_text_user = theme('tracking_code_email', array(
                    'image_path' => $base_url . '/' . drupal_get_path('module', 'commerce_canvas') . '/images',
                    'user' => null,
                    'page' => array(
                        'greet_text' => t('Thank you for your order at Express Canvas. Your order is ready and has shipped. You may track your order using FedEx tracking with your tracking number: '.$order->field_tracking_number['und']['0']['value'].''),

$sent_to_user = commerce_canvas_mail_send($email_values_user);


These are the full snippet to handle the HTML email correctly in Drupal 7 thus in the hook_theme you can give your custom template.

  • 2
    Thank you very much for your answer - it is exactly what I asked for! Unfortunately now that I've seen the work involved and that there are modules out there that could do everything for me I think I'll wait before I rush into creating my own hook. However, I can't thank you enough for your answer because it is everything I asked for. I wish I could upvote more than once
    – Andy
    Commented Jan 8, 2013 at 19:28
  • 11
    Great answer. I love the way Drupal makes basic things so simple ;-) Commented Jul 16, 2013 at 21:11
  • 1
    But still you won't be able to send the HTML mail..., right.
    – Ejaz
    Commented Dec 9, 2014 at 7:59
  • @Ejay, yes you can. This does that. Commented Dec 9, 2014 at 10:42
  • 1
    For the record: It's more easy using following module: drupal.org/project/simple_mail
    – gue
    Commented Mar 6, 2015 at 11:07

If you want to theme the outgoing mails with the help of custom templates, you should use the HTML Mail module.

Lets you theme your messages the same way you theme the rest of your website.

It works well with other modules, like Print, Mail mime, etc.

You have to install the Mail System module in order to use HTML mail.

  • 1
    Please note that HTML Mail works with the Mail Mime module, not Mime Mail (Mime Mail and HTML Mail do similar things and override each other). Commented Jan 7, 2013 at 14:32
  • 1
    @indrock Thank you for your answer too. Do you know if I can use the HTML Mail module to theme emails sent using php code?
    – Andy
    Commented Jan 8, 2013 at 19:20

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);
  • 4
    It is always recommended to send the mails using drupal_mail() rather than $system->mail(.. in order to use the hook_mail_alter function (which only works for mails sent using drupal_mail().
    – AjitS
    Commented Jan 7, 2013 at 7:57
  • I am fully aware of how to use the function (syntax/code wise), I would just like to know how to make a theme so that I can apply to all emails sent with drupal_mail etc, but thank you anyway
    – Andy
    Commented Jan 8, 2013 at 19:11
  • I am using this code, its working fine but as well as one blank mail has send. Commented Jul 20, 2016 at 14:43

To send HTML e-mail, you can use the Mimemail module. Once it's set up and configured, you can simply prepare the template, name it mimemail-message.tpl.php, drop it in your theme directory, and it will automatically be applied to all outgoing e-mail (assuming you have configured all mail to be sent out by Mimemail).

Setting up the module is probably easier than overriding drupal_mail().

  • Thank you for your answer! Can I send emails using PHP with this module? If so, could you show me how please?
    – Andy
    Commented Jan 6, 2013 at 15:36
  • Mimemail, when combined with the Mail System module, will take over all e-mails sent by the site. Thus, all e-mails sent by any module, including custom modules, will automatically be sent out through Mimemail. If you want to limit which e-mails are affected, you can use the Mail System's modules configuration options. Commented Jan 7, 2013 at 0:35
  • 1
    I think this's not what Andy asked exactly. True, you will need Mimemail module or roll your own MailSystem to do this but may be Andy asked about how to theme the email body which should be done in hook_mail() function and a theme('my_custom_theme') call in it ?
    – AKS
    Commented Jan 7, 2013 at 5:09
  • 1
    I think @Andy wants to know if the Mimemail module has a function that can be called to send emails.
    – apaderno
    Commented Jan 7, 2013 at 14:18
  • @kiamlaluno You are correct, this is what I would like to know please
    – Andy
    Commented Jan 8, 2013 at 19:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.