Choose to Send an Email Now or at a Later Date using Laravel ,VueJS and CronJob (Task Scheduler)

victor steven
Apr 15 · 7 min read
Home page
Send Email Modal
Choose Time to Send Mail

Let’s Build This

What is Cron?

Cron is a task scheduler, that runs shell commands at specified intervals.

Laravel have standard time intervals built in to run cron job, which any body can easily use. But the draw back is, what if the user wants to choose a custom date to send notification/emails? Thats where this article becomes handy.

You have a website or a CMS that you need to send special mails at dynamic time intervals to all authenticated users by choosing the date when this email should be sent, with the aid of a calendar rather than going to the source code all the time to write the code for that.

The knowledge you will gain from the article can be used in any situation you want to automate. For simplicity, we automate sending mails.

For development purpose, we will use . You can signup if you don’t have an account already. Just to see how the email is sent, of course you can use your custom email providers such as mailgun, Amazon SES, postmark in your real project.

Step 1:

Basic Setup

Spin up a new laravel project:

laravel new choose_dateor:composer create-project --prefer-dist laravel/laravel choose_date

You can call the project anything you want, here i called it choose_date.

Go to your terminal, PhpMyadmin, Sequel Pro, Table Plus, or any GUI you use to access your database, create a database called choose_date or whatever you think.

Edit the .env file to add your migration details:

DB_DATABASE=choose_date
DB_USERNAME=username
DB_PASSWORD=password

Also edit the mailtrap config details:

MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=null
MAIL_PASSWORD=null
MAIL_ENCRYPTION=null

Should be edited with your config details obtained from mailtrap to look like:

MAIL_DRIVER=smtp
MAIL_HOST=smtp.mailtrap.io
MAIL_PORT=2525
MAIL_USERNAME=mailtrap_username
MAIL_PASSWORD=mailtrap_password
MAIL_ENCRYPTION=null

To cache latest changes, run:

php artisan config:cache

To demonstrate the topic of this article, we will be sending mails to users, that we can either send now or send or a later time. So we will need a table to store the emails we generate, a model to interact with our database and a controller to interface between the view and the model.

To create all at once, we run the command:

php artisan make:model Message -mc

That line of code produces the model, controller and the migration file:

  • Message.php
  • MessageController.php
  • 2019_04_14_154651_create_messages_table.php

Observe the date in the migration file. Yours will definitely be different

Where the m flag will create the required migration and the c the controller.

Edit the migration file to look like this:

Next: Since we need to send these mails to users, we need to seed come users. Create the user seeder file:

php artisan make:seeder UsersTableSeeder

We will create only five users:

Go to the DatabaseSeeder.php and comment out the line:

$this->call(UsersTableSeeder::class);

Save all files and run migrations with seed:

php artisan migrate:fresh --seed

You can check the users table to confirm that there are 5 users.

Step 2:

Building the backend:

Let’s use the MessageController.php we created in step 1.

We will get all the users, get all the messages that will be created in the future and also send mails to the users. your code should be identical to this:

A simple work through:

  • The getUsers() function fetches all the users in the database which will use in our Vue component.
  • The getMessages() function fetches all the messages the user will create in the future. For now, it returns an empty array.
  • The sendMail() function send mails the users.

Exploring the sendMail() further, you will observe that we looped through our users and dispatched a new job called SendMailJob which has two parameters: the user's email and the mail to send which is in the mail class called NewArrivals. Note that we are yet to create both the job and the mail class.

Lets create both the job file and the mail class:

php artisan make:job SendMailJob

Your job file should be identical to this:

Now lets create the mail class with markdown to give us nice email UI:

php artisan make:mail NewArrivals --markdown=emails.newarrivals

Your email class file should be identical to this:

NewArrivals.php

The email class is called NewArrivals simply means that we want to notify our users about the arrival new products.

Next: Let’s define the routes in the web.php file:

web.php

Step 3:

Building the frontend

For simplicity, we will use welcome.blade.php file.

We will add the Vue component, the app.js script and bootstrap for basic front end styling:

While creating the mail class: NewArrivals above, we also created a blade file called newarrivals.blade.php. Now let’s edit the file located in the path: /resources/views/emails, to look like this:

Create the Vue Component:

In the resources/js/components create a Vue component called NewArrivals.vue . Your file should be identical to this:

Next: Edit the app.js file located in resources/js/app.js to be identical to this:

Observe that there are two javascript libraries we need to install: sweetalert2 and VueCtkDateTimePicker

Simply add this to your package.json file:

"dependencies": {   "vue-ctk-date-time-picker": "^2.0.6",   "sweetalert2": "^7.30.0"}

Now to install two above two packages and all other javascript file we need for this project, run:

npm install

Once done, run:

npm run dev

Before we test the application, let’s build the Scheduler

Step 4:

Build Task Scheduler using Laravel CronJob Scheduler

Remember the whole aim of this tutorial is, we want to enable the admin or the website owner to be able to either send mails now or choose a time in the future to do so.

First, we will create an artisan command that we will schedule.

Let’s call the command NotifyUsers:

php artisan make:command NotifyUsers --command=notify:users

This file is located in the path: app/Console/Command.

Yours should be identical to this:

Observe this line:

$now = date("Y-m-d H:i", strtotime(Carbon::now()->addHour()));

We formatted our time such that we excluded seconds. Since we will be checking if two time values are the same, is better our least time unit be minutes instead of seconds, as we will get an accurate comparison.

Another thing to notice is that we add the function addHour() This is to compensate for the one hour that PHP adds by default. This is chiefly a time zone issue. For this tutorial i am using the default UTC timezone laravel ships with. To avoid writing the addHour() function, you will to setup your time zone in config/app.php

'timezone' => 'UTC',

You can change to your own timezone. For the sake of this tutorial, you can leave it the way it is.

Next: Register this command in the kernel.php file

Locate the kernel.php file in the path: app/Console/

Register the command like so:

protected $commands = [ 'App\Console\Commands\NotifyUsers',];

Now, to run this command in the terminal, type in the terminal:

php artisan notify:users

What this command will do is: when you choose a particular time other time now, once that time arrives, run the above command in the terminal, then the mails will be sent to the users.

But, as you have observed, this is not possible to do all the time because, you will always manually time this command when the time you have chosen to send mails to users reaches.

To automate this, we will need to Schedule the command.

When you eventually run this application, and you want to send mails, the least time you can choose is one minute ahead of the current time. So, it will make sense to schedule the NotifyUsers command to run every minute.

So, in the kernel.php we edited earlier, we will have:

protected function schedule(Schedule $schedule){   $schedule->command('notify:users')            ->everyMinute();}

The only thing that we need to do now is to start the cronjob that will run every minute and execute the SendMailJob if the date_string is equal to now, from the handle function in the NotifyUsers.php file above.

I assume that you are in your local machine, run this command in your terminal:

php artisan schedule:runor: while true; do php artisan schedule:run; sleep 60; done

This will run every minute without your interference. You exit using: Ctrl+C

On a production server, you will need to register this command in the crontab. Crontab is a file that contains a list of scripts that will run periodically. Open using:

sudo crontab -e

Go the end of the file and include this line:

* * * * * php /path-to-your-project/artisan schedule:run >> /dev/null 2>&1

Where path-to-your-project is the path of your Laravel project. Remember only do this in a production server on your local machine, run either of the commands stated before this explanation.

So, you can test the application: run these sets of commands:

composer dump-autoloadphp artisan config:clearphp artisan config:cache

Then, serve the application:

php artisan serve

Make sure you open a different terminal pointing to the path of your Laravel and start the scheduler, if not, the send later feature wont work.

while true; do php artisan schedule:run; sleep 60; done

Remember if you want to make any changes to the Vue file, you can start the watcher, for real time compilation: npm run watch

Hmmm. This article is somewhat demanding. Thank you for taking time to read. Feel free to ask any questions or express your observations.

Get the code here:

Happy Coding!

victor steven

Written by

Am a software developer that specializes in Go, NodeJS, PHP, Javascript, ReactJS, Laravel, VueJS,