Scheduling Tasks In Node.js With Node Cron
Automate sending emails in your node.js application with node-cron
INTRODUCTION
The essence of technology is to make productiveness faster and easier. Have you ever wanted to automate some tasks on your application? Then this tutorial is for you.
In this article, you would learn how to automate scheduling emails in your node.js application using node-cron.
Even if you are not interested in scheduling a job in node.js, you may still find the knowledge of the cron syntax from this article very useful, so stick around👌
PREREQUISITES
This tutorial is a hands-on demonstration of how you can automate scheduled emails. Before proceeding, ensure you have the Javascript runtime environment Node.js on your local computer.
WHAT IS SCHEDULING AND WHY NODE-CRON?
According to Oxford Dictionary, Scheduling refers to “plan an activity at a specific date or time in the future”. This tutorial is based on the words that are being highlighted.
In node.js, we can plan(referred to as function) an activity(referred to as job) to run at a specific date or time(referred to as expression) in the future. This is paramount as you cannot schedule a task to run at a past time.
Node cron is an npm package used to schedule jobs that runs at specific time or date intervals. Instances of jobs that can be scheduled include logging at intervals, backing up a database, and sending out scheduled emails and email notifications. Node-cron is based on cron
, the time-based job scheduler in Unix-like systems.
There are several npm packages that handle scheduling in node.js, such as node-schedule
, node-cron
, Agenda
, Bree
, Cron
, and Bull
, but for the purpose of this tutorial, we would be working with node-cron
because it is quite mature and stable. It is also preferable because we are making a simple job scheduling.
PROJECT SETUP
To get started, we need to go to our terminal and create a project directory using the following command:
mkdir email-node-cron
We can then move into the created directory using the cd
command
cd email-node-cron
We need to create a new file index.js in the email-node-cron directory
touch index.js
The following command initializes the project and creates a package.json
file in the root folder.
npm init -y
The -y
suffix is a shortened form of the -yes
flag. It is used to accept the prompts that come from npm init
automatically. It will populate all the options automatically with the default npm init
values.
- Install dependencies
As stated earlier, node-cron
is an npm package, so we need to install it as a package dependency in our project.
npm install node-cron
We also need to install the nodemailer
and dotenv
package dependency. Nodemailer is an npm package that allows you to send emails.
Dotenv is a zero-dependency module that loads environment variables from a .env
file into process.env
.
npm install nodemailer
npm install dotenv
After setting up our project and installing dependencies, our folder structure should be like this.
SCHEDULING AN EMAIL AUTOMATION JOB
Let us start writing codes for our job and the code snippet below requires the node-cron
package in our index.js file
// index.js
const cron = require('node-cron');
To schedule a task, the node cron package has a schedule
method that takes in three arguments.
const cronJob = cron.schedule(expression, function, options)
- The first argument known as cron expression specifies the date and time at which the job should execute.
- The second argument specifies the function that executes at intervals.
- The third argument is an optional configuration of the node cron job.
NODE CRON EXPRESSION
The cron expression which is the first argument is a string that specifies the date and time interval of a job. It comes in the format * * * * * *
. Each *
is a field and the representation of each field with the values is illustrated in the image below.
The
seconds
field is an optional field and can be omitted when writing an expression.
There are various ways to populate a cron expression, but, in this tutorial, we would be populating the cron expression with single integer values.
For instance, if we want to send an email to our subscribers every Thursday at 9:50:10 AM,
our expression would be like 10 50 9 * * 4
This would run the node-cron
job at the tenth second of the fiftieth minute of the ninth hour. Since we did not specify a value for the day of the month and month field, it interprets *
to mean every month. But we specified the fourth day of the week, thus this job would run every Thursday at 9:50:10 AM.
Can we attempt writing a cron expression for sending an email to our subscribers on the 15th of every month at 2:30 pm? 😊
2. NODE CRON FUNCTION
The function is the second argument of the schedule method and it specifies the function that should execute. In our case, the function would be sending emails to our subscribers.
Here, we would require the nodemailer
package and then create a mail transporter transporter
that sets the username and password of our email account.
It is considered a good software development practice to always store credentials in an environment variable (.env) file.
So let us create a .env file in the root folder
touch .env
Run the following code snippets to add your credentials to the .env
file.
//.env file
EMAIL=youremailaddress@gmail.com
PASSWORD=youremailpassword
You need to configure the index.js
file so that it can have access to your .env
file variables.
const nodemailer = require('nodemailer');
const dotenv = require('dotenv');
// .env configuration
dotenv.config()
In the index.js file, the code snippet above requires the dependencies nodemailer
and dotenv
installed earlier. It is then configured using the .config()
method. In order to use nodemailer
, we are expected to do the following:
- Create a Transporter object
transporter
// creates a mail transporter here
let transporter = nodemailer.createTransport({
service: "gmail",
auth: {
user: process.env.EMAIL,
pass: process.env.PASSWORD,
},
});
- Create an object
MailOptions
let mailOptions = {
from: 'EMAIL NODE CRON APP',
to: process.env.EMAIL,
subject: "Scheduled Email",
html: `<p>Hello there,</p>
<p> You have an email scheduled from <b>EMAIL NODE CRON APP</b> </p>
<p>Keep learning👌👌</p>
Kind regards, <br>
<h4> EMAIL NODE CRON APP</h4>`
};
- Use the
sendMail
method on the objecttransporter
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
console.log("Email error application", error.message);
} else {
console.log(`${new Date().toLocaleString()} - Email sent successfully:` + info.response);
}
});
In the index.js file, we have the function that needs to execute to send emails to our subscribers. We would take a quick look at the optional argument before we set up our cron job properly.
3. NODE CRON OPTION
The option is the third argument of the cron schedule method and it is an optional configuration for the job scheduling. It is an object that contains the following:
scheduled: This is a boolean to set if the created task is scheduled. The default value is set to
true
. When scheduled is set to true, the job runs automatically when the cron expression is fulfilled, however when set to false, you need to invoke astart()
method to the job object like thisjob.start()
timezone: This is the timezone that is used for job scheduling. The default timezone is that of the system used in scheduling the cron job. You can check out moment-timezone for valid timezone values.
An instance of this is:
{
scheduled: false,
timezone: “Asia/Tokyo”
}
Now, we have a pretty good understanding of what each argument means and how they are important in creating a good cron job. We would set up our cron job and executes the job too.
In the code snippet below, we would create a node cron job that schedules emails sent to our subscribers every minute.
Our index.js file should be like this:
const cronJob = require('node-cron');
const nodemailer = require('nodemailer');
const dotenv = require('dotenv');
// .env configuration
dotenv.config();
// creates a mail transporter here
let transporter = nodemailer.createTransport({
service: "gmail",
auth: {
user: process.env.EMAIL,
pass: process.env.PASSWORD,
},
});
// Sending emails every minute
cronJob.schedule('59 * * * * *', () => {
let mailOptions = {
from: 'EMAIL NODE CRON APP',
to: process.env.EMAIL,
subject: "Scheduled Email",
html: `<p>Hello there,</p>
<p> You have an email scheduled from <b>EMAIL NODE CRON APP</b> </p>
<p>Keep learning👌👌</p>
Kind regards, <br>
<h4> EMAIL NODE CRON APP</h4>`
};
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
console.log("Email error application", error.message);
} else {
console.log(`${new Date().toLocaleString()} - Email sent successfully:` + info.response);
}
});
});
console.log('Application started.....');
In your terminal, type in the code snippet node index.js
to start your application.
NB: If you are having an error message of
Email error application Invalid login: 535-5.7.8 Username and Password not accepted.
You might need to allow less secured apps to test if you are using a Gmail address.
This is a screenshot of my terminal and the email delivered to my inbox.
- Terminal
- Email Inbox
CONCLUSION
In this tutorial, you have learned how to automate scheduling emails in your node.js application using node-cron. This knowledge can be applied in your future projects to be more productive and also avoid repetitive tasks that node-cron can handle.
You can access the GitHub repository for the sample code used in this tutorial.
REFERENCES
A quick and simple editor for cron schedule expressions by Cronitor