Hello,

I'm a newbie. This is the first module I've tried to write. It is basically a D8 version of Date Reminder. I'm taking it in baby steps. Step one is to cause it to run when cron runs using hook_cron. That works. Step two is to generate a simple email using hook_mail then there is hook_mail_send to deal with.

Being a newbie I assumed that all hooks could be in the same module. Maybe this is not the case. Maybe mail should be in a separate module? If this is the case is there some magic that will cause cron to run the hook_cron module first than magically run the hook_mail module? Please explain.

I'd attach my code if I could figure out how to do so in this forum ...

Comments

Jaypan’s picture

Your question isn't clear. Why are you thinking that your mail hook should be in a different module? And your other question isn't answerable without understanding how you expect cron and mail to work together.

samstamport’s picture

Sorry my question is not clear. I incorrectly assumed that since I mentioned that my moduled will have the same functionality as the D7 Date Reminder module that it would be easy to understand what I want my module to do.

My new module, like Date Reminder, runs when cron runs. It will search the Event content type in the data base to see if there is an event date that is within two days of occurring. (This part is not yet a part of my new module.) If an Event is found that matches this criteria an email address in the Event will be sent a reminder email.

I was thinking that maybe I would have to code a separate module for the email part of this problem since that is what I found in an example. Also, when my incomplete module runs the function for hook_mail is not executed. I know this because I coded a simple message to say that I was inside the function. I'll try to paste the code below.

<?php

/**
 * 
 * Implements hook_cron().
 * 
 */
use Drupal\Core\Routing\RouteMatchInterface;

/*
 * Tell cron to run this module each time cron runs
 */
function emailreminder_cron() {
  drupal_set_message(t('Hello from emailreminder'));
}

/**
* Implements hook_mail().
* Part 1 of 2 of actually sending an email
*/
function emailreminder_mail($key, &$message, $params) {
  $options = array(
    'langcode' => $message['langcode'],
    );
 /* switch ($key) {
    case 'node_insert': */
      $message['from'] = \Drupal::config('system.site')->get('mail');
      $message['to'] = t('sam.stamport@gmail.com');
      $message['subject'] = t('Columbia Blooms watering reminder', $options);
      $message['body'][] = $params[t('This is a friendly reminder that your day to water is: ')];
      /* break; */
      drupal_set_message('inside emailremider_mail');
      drupal_set_message($message);
  }  

Jaypan’s picture

Sorry my question is not clear. I incorrectly assumed that since I mentioned that my moduled will have the same functionality as the D7 Date Reminder module that it would be easy to understand what I want my module to do.

I've never used it, and have no idea what it does.

I'm pretty sure you won't see the output of drupal_set_message() in a hook_cron() implementation.

It's not the best way to ensure code has been hit in Drupal, as often it won't work. Use the Drupal logger to write to the log instead (https://www.drupal.org/docs/8/api/logging-api), as it will be more consistent.

As for your code, you have implemented hook_mail(), which is essentially like creating a template for your email. But it doesn't actually do anything until you tell Drupal to send a mail using that template. You can do this with MailManager::mail().

samstamport’s picture

Figured out how to log, but my log code is not executed in hook_mail. What's going on?

I'm trying to determine if I've set up hook_mail properly and I really want to learn how this works.

function emailreminder_mail($key, &$message, $params) {
  $options = array(
    'langcode' => $message['langcode'],
    );
 /* switch ($key) {
    case 'node_insert': */
      $message['from'] = \Drupal::config('system.site')->get('mail');
      $message['to'] = t('sam.stamport@gmail.com');
      $message['subject'] = t('Columbia Blooms watering reminder', $options);
      $message['body'][] = $params[t('This is a friendly reminder that your day to water is: ')];
      /* break; */
      drupal_set_message('inside emailremider_mail');
      \Drupal::logger('emailreminder')->notice('hook_mail @message'); 
  }  
Jaypan’s picture

What does your hook_cron look like? Have you added the code to send the mail?

samstamport’s picture

hook_cron:

function emailreminder_cron() {
  drupal_set_message(t('Hello from emailreminder'));
  \Drupal::logger('emailreminder')->notice('hook_cron'); 
}

Both set_message & logger work.

I've not yet added the code to send mail. I guess I'll go ahead and do that and hope that I coded mail correctly.

Jaypan’s picture

That's why it's not sending mail you haven't told it to send mail. That's also why your hook_mail() is not entered - unless it's sending a mail, it's not going to enter hook_mail().

samstamport’s picture

OK. I added code to send mail, but it doesn't work. I'm getting some warning messages from NetBeans that I don't know how to fix since I'm new to all this. I actually went through module building videos on OSTraining.com, but they didn't address hook. I'd appreciate continued support.

function emailreminder_cron() {
  drupal_set_message(t('Hello from emailreminder'));
  \Drupal::logger('emailreminder')->notice('hook_cron'); 
}

/**
* Implements hook_mail().
* Part 1 of 2 of actually sending an email
*/
function emailreminder_mail($key, &$message, $params) {
  $options = array(
    'langcode' => $message['langcode'],
    );

  $key = 'mail';
  $message['from'] = \Drupal::config('system.site')->get('mail');
  $message['to'] = t('sam.stamport@gmail.com');
  $message['subject'] = t('Columbia Blooms watering reminder', $options);
  $message['body'][] = $params[t('This is a friendly reminder that your day to water is: ')];
  drupal_set_message('inside emailremider_mail');
   \Drupal::logger('emailreminder')->notice('hook_mail @message'); 
  }  

  function emailreminder_mail_send() {
    drupal_set_message('inside emailremider_mail_send');
      \Drupal::logger('emailreminder')->notice('hook_mail_send @message');  
  /* Source: https://github.com/adityaanurag/demoMail.git */
  $module = 'emailreminder_mail';
  $key = 'mail';
  $to = 'sam.stamport@gmail.com';
  $from = 'admin@collumbiablooms.org';
  $language = language_default();
  $result = drupal_mail($module, $key, $to, $language, $params, $from, $send);
  if ($result['result'] == TRUE) {
    drupal_set_message(t('Your message has been sent.'));
  }
  else {
    drupal_set_message(t('There was a problem sending your message and it was not sent.'), 'error');
  }
    drupal_set_message('inside emailremider_mail_send');
      \Drupal::logger('emailreminder')->notice('hook_mail_send @message');
}

nitin.k’s picture


function emailreminder_cron() {
   emailreminder_mail_send(); // You need to put it here for calling.
  drupal_set_message(t('Hello from emailreminder'));
  \Drupal::logger('emailreminder')->notice('hook_cron'); 
}


samstamport’s picture

Ah. This is making a bit more sense. It is similar to C# programs I wrote a year ago where everything starts in main() (for C#).

I've inserted the latest version of my code. There are issues in the mail_send function due to my lack of understanding and lack of tutorials I've found thus far on the web. Or, maybe I'm misunderstanding the tutorials. At any rate, I would appreciate your continued help.

<?php

/**
 * 
 * Implements hook_cron().
 *
 */


/*
 * Tell cron to run this module each time cron runs
 */
function emailreminder_cron() {
  emailreminder_mail(); 
  emailreminder_mail_send(); 
  drupal_set_message(t('Hello from emailreminder'));
  \Drupal::logger('emailreminder')->notice('hook_cron'); 
}

/**
* Implements hook_mail().
* Part 1 of 2 of actually sending an email
*/
function emailreminder_mail($key, &$message, $params) {
  $options = array(
    'langcode' => $message['langcode'],
    );

  $key = 'mail';
  $message['from'] = \Drupal::config('system.site')->get('mail');
  $message['to'] = t('sam.stamport@gmail.com');
  $message['subject'] = t('Columbia Blooms watering reminder', $options);
  $message['body'][] = $params[t('This is a friendly reminder that your day to water is: ')];
  drupal_set_message('inside emailremider_mail $key');
   \Drupal::logger('emailreminder')->notice('hook_mail @message %key :params'); 
  }  

  function emailreminder_mail_send() {
    drupal_set_message('inside emailremider_mail_send');
      \Drupal::logger('emailreminder')->notice('hook_mail_send @message');  
  /* Source: https://github.com/adityaanurag/demoMail.git */
     
  $module = 'emailreminder_mail';
  $key = 'mail';

  // Specify 'to' and 'from' addresses.
  $to = 'sam.stamport@gmail.com';
  $from = 'admin@collumbiablooms.org';

  /* $params = $form_values; */

  $language = language_default(); 
  $send = TRUE;
  $result = emailreminder_mail($module, $key, $to, $language, $params, $from, $send);
  if ($result['result'] == TRUE) {
    drupal_set_message(t('Your message has been sent.'));
  }
  else {
    drupal_set_message(t('There was a problem sending your message and it was not sent.'), 'error');
  }
    drupal_set_message('inside emailremider_mail_send');
      \Drupal::logger('emailreminder')->notice('hook_mail_send @message');
}
Jaypan’s picture

Sending mail in Drupal is a 2 step process:

1) You define the contents of the mail in hook_mail(). This is like a template for a mail, as it defines the contents of the mail. After you have created hook_mail(), nothing will yet happen. But you never need to call this hook yourself. The system will call it for you in step 2:

2) You actually send the mail by calling drupal_mail(). When you use this function, Drupal invokes hook_mail() (step 1) to build the mail, then drupal_mail() sends the mail for you. This is the only function you will need to call, you never call hook_mail().

You are trying to send mails in hook_cron(). So in hook_cron(), you need to add a call to drupal_mail(). This function call will invoke hook_mail(), build your mail from that hook, then send it.

samstamport’s picture

OK. I searched the web for drupal_mail. I did not find one for Drupal 8. My module has to work with Drupal 8. Is there another way?

You seem to be saying that I don't need to fool with hook_mail_send.

Jaypan’s picture

Sorry I forgot we were talking about Drupal 8. drupal_mail() has been replaced with MailManager::mail in Drupal 8.

samstamport’s picture

Thanks for MailManager::mail.

Part of getting all this to work is customizing XAMPP so my email will actually get out on the Internet. I searched for quite some time today looking for how to use Mercury which comes with XAMPP, but found only old stuff that's probably no longer current. Can you give me a link for current documentation?

Thanks!

Jaypan’s picture

I've never used XAMPP and know nothing about it.

But you don't need to have a mail server to confirm that your code works locally. If the mail fails, there will be an entry in the logs (you need to have the Database Logging module enabled).

Or, you can use the SMTP module, and use a remote SMTP server, like gmail, bypassing the need for a mail server on your local system.