3
votes

Laravel 5.6.

I have a table which cointains a column called "end" and it's a timestamp and "user_id". That date is in the future. I need to send an email (always the same email) to that user when that date is reached.

I've read about:

https://laravel.com/docs/5.6/scheduling

https://laravel.com/docs/5.6/mail#queueing-mail

https://laravel.com/docs/5.6/notifications#mail-notifications

But I'm not sure where to start.

Every of those tools send emails but, what will be the best approach on what I need to do?

2

2 Answers

3
votes

As sending email can be blocking process, I would advise making use of queues, specifically the later($when, new Mailable()) method.

$when = now()->addMinutes(10);

Mail::to($request->user())
    ->cc($moreUsers)
    ->bcc($evenMoreUsers)
    ->later($when, new OrderShipped($order));

You can queue up your email at the same time your are saving your data to the database as you'll have all the information you need at that point.

Alternatively you could use the scheduler which runs every x minutes, compares the current time with your end time and adds an email to a queue for sending if the current time equals or exceeds your end time. This feels a little clunky though considering Laravel has the queue API.

2
votes

Here is what I propose and I have been using this approach from quite a while now and it works like a charm:

  1. Create a migration for a table, let's call it cron_jobs. Make two columns in it other than id, created_at and updated_at: signature(string) and flag(boolean).
  2. Of course, create a model for it which will be CronJob and define fillable array in it.
  3. Migrate the table and create an entry in it with:

    • signature = 'send:email'
    • flag = 1
  4. Create a command, with signature: send:email

  5. Inside the command, check for the entry of flag in cron_jobs table where signature is 'send:email'. If it is 0, send an email to yourself that your CRON has crashed for some reason so that you can go in and check the logs and see whats wrong and return from the function.
  6. If it is 1, make it 0 and check for the current date-time and match it with your end:

    • if it does not match, do nothing. make flag back to 1.
    • if it does match then send the email, make flag back to 1.
  7. Now go to the cPanel of your Server and set a cron which runs this command each minute.

If your sending email process takes more than a minutes then run the cron per 2 minutes or per 15 minutes, based upon how time-consuming your command process is. However if you do make it more than a minute then make sure how you handle matching timestamp as script wont run every minute so you might wanna take different approach for sending emails than matching the exact timestamp.

This approach ensures that a buggy script does not run twice and informs you right away that something is wrong with your command.

Also, we do not user scheduler so we don't risk entering any bug or unexpected behavior which many people have experienced with laravel scheduler.

Sure enough, in future, if you want to do something again which is iterating, just add another signature in the table and you can use the same approach so it's expandable.

Needless to say if you receive bug report email..go on and resolve it and make flag entry back to 1 manually so that script can run fully the next time.

I hope it helps.