4

What's the point to have hook_mail_alter if I already have hook_mail?

For example, I saw that hook_mail_alter is used to add a footer to my mail message. But I could use hook_mail() to add it, instead of using 2 functions… What am I missing?

Maybe it is done to add the footer after some other function is invoked?

apaderno
  • 28,547
  • 16
  • 75
  • 90
aneuryzm
  • 63,052
  • 100
  • 273
  • 488

1 Answers1

8

hook_mail() should be used from a module to alter its own mail message, while hook_mail_alter() should be used from a module to alter the message sent by other modules.

This is clear from the following code taken from drupal_mail():

// 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);

$module is the first parameter passed to drupal_mail().
It's clear the function doesn't invoke the implementation of hook_mail() of every module implementing it, but it invokes the hook just for the module calling the function.

There are other differences, such as when the two hooks are invoked (hook_mail_alter() cannot set the language for the message, which is set before hook_mail_alter() is invoked), and the parameters they get (hook_mail($key, &$message, $params) versus hook_mail_alter(&$message)).

apaderno
  • 28,547
  • 16
  • 75
  • 90
  • @kiamlaluno: "It's clear the function doesn't invoke the implementation of hook_mail() of every module implementing it". Does it invoke the implementation of hook_mail_alter of every module instead ? – aneuryzm Aug 03 '10 at 16:47
  • @Patrick: Yes, it does. That is the purpose of `drupal_alter()`: to call every module implementing the alter hook that matches the name passed as first argument to the function. – apaderno Aug 03 '10 at 17:08
  • @Patrick: after a hook (say, hook_example) is invoked, and something calls `drupal_alter`, `hook_example_alter` is run. So `hook_*_alter` is always run after the regular hook. See http://api.drupal.org/api/function/drupal_alter/6 and the functions that call it to get an idea of how it works. –  Aug 03 '10 at 17:08
  • `hook_example_alter()` will be invoked if a module calls `drupal_alter('example')`; not all the modules that use `hook_example()` use also `hook_example_alter()`. It is true that generally `hook_example_alter() is invoked after `hook_example()`. – apaderno Aug 03 '10 at 17:42
  • @kiamlaluno: ok Thanks. One more thing.. just for my understanding: if I invoke "module_invoke_all('mail')", I would invoke all hooks (and probably sending wrong e-mails without reason.. so it is not a substitute for mail_alter, but just to understand..). Correct ? – aneuryzm Aug 04 '10 at 09:33
  • 1
    @Patrick: That is correct. Some implementations of `hook_mail()` don't check the first parameter (compare [`user_mail()`](http://api.drupal.org/api/function/user_mail/6) with [`contact_mail()`](http://api.drupal.org/api/function/contact_mail/6)) because they just send a type of message. If you would call `module_invoke_all('mail')`, those implementations would think they are getting a message they sent, and they would probably alter the message in a way that is not correct. – apaderno Aug 04 '10 at 10:18
  • You can still access the `$key` as `$message['key']`, the `$params` as `$message['params']`, and you can probably change the language by changing `$message['language']`. – mbomb007 Jul 11 '19 at 19:13