Introduction
In this article we will explain how you can send reports automatically and periodically using a NodeJs whether you embed the logic inside your application or you make it a separate script its up to the developer but separate script is recommended(we use this approach), before you start you should know what is NodeJs you can benefit from this A Quick Guide to Node.js in 2019
Requirements
Two packages is required for this tutorial
-
node-cron
used for scheduling tasks -
node-mailer
used to send emails to some user list using some SMTP providers googles Gmail will be used for this purpose as it is free and easy to setup
Project setup
Start by creating new NodeJs project
- create a folder & cd to the folder using command line something like
exampleFolder
run
npm init
this will ask you couple of questions after you finish there will be a file calledpackage.json
alternatively if you don't want to answer questions typenpm init -y
this will answer yes for all question,install
node-cron
typenpm i node-cron --save
in the consoleinstall
nodemailer
typenpm i nodemailer --save
in the console
After the installation you should see a folder called node_modules
and generated package.json
should look something like this
{
"name": "exampleFolder",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"node-cron": "^2.0.3",
"nodemailer": "^6.3.0"
}
}
Let's start coding
We need an entry point for our application(script) start by creating a file called main.js
and add "start": "node main.js"
line to package.json
under "scripts"
property so it becomes like this
{
"name": "exampleFolder",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "node main.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"node-cron": "^2.0.3",
"nodemailer": "^6.3.0"
}
}
Add console.log("Hello world")
inside main.js
then in the console type npm start
this should output Hello world
to the console this is used to make sure our application runs
Configure nodemailer
We will start by configuring nodemailer follow these steps
- create a file called
reportSender.js
- paste this script inside the file
const nodemailer = require('nodemailer');
const defaultMailingList = "example1@vultr.com,example2@vultr.com";
const senderEmail = "sender.example@gmail.com";
const senderPassword = "gmail_app_password"; // gmail app password
module.exports = {
sendMail: async (subject, text, to = defaultMailingList) => {
try {
const transporter = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: senderEmail,
pass: senderPassword,
},
});
const message = {
from: `report sender <${senderEmail}>`,
to,
subject,
text: subject,
html: text,
};
transporter.sendMail(message, () => {});
} catch (e) {
// handle errors here
}
},
};
Note that nodemailer provides handful of transports including custom ones
Values are hardcoded i would recommend using something like dotenv
which loads .env
file and creates environment variables based on the environment variable but for sake of simplicity we did that here,
What this file does is that it exports an object with key sendMail
which is a function that configures node mailer and setup a generic method for sending our reports as we please for future uses you can add extra keys to main object for example you want the report to be sended via telegram by a bot you can add the logic in this file
you can get gmail app password following this link get app password
Test if node mailer can send emails for us
- after you change these variables in a correct way [
senderEmail
,senderPassword
,defaultMailingList
] open
main.js
and importsendMail
fromreportSender.js
using this syntaxconst {sendMail} = require('./reportSender')
note that no file extension is required when importingmake a call to
sendMail
function so it can send and email examplesendMail("Hello world", "this is email body it can contain html also")
if you didnt updatedefaultMailingList
to contain your email you can pass the email after msg body
the complete body of our main.js
is something like this
const {sendMail} = require('./reportSender');
console.log('sending email...')
sendMail("Hello world", "this is email body it can contain html also")
console.log('email sent ✓')
With this we can send emails to some specific emails as you can predict that you can somehow generate a string which contains a valid html and this html is generated using data from our database then you can send reports or even data to your mailing list
if you are wondering what is a good module for database connection i would recommend using kenxjs
the only thing remains is to automate sending reports(emails) with that comes node-cron
module
Configure node-cron
Configuring node-cron is an easy task you tell it when do you want for some action to take place then you provide the action definition and whenever the call triggers it will call this action, ction is a function
for sake of this tutorial let's say i want to receive a report every 1 min
what you can do according to their documentation is something like this
var cron = require('node-cron');
cron.schedule('* * * * *', () => {
console.log('running a task every minute');
});
You can test this code just comment everything inside main.js
then wait for 1 min and you should see running a task every minute
output every 1 min on the console as you can see the callback is our action and its the place that we want to implement and generate our reports then send the emails (generated reports)
Combine our nodemailer and node-cron
As you can see by combining just two modules we could make an automated system that can send reports or even anything that we want periodically so lte's show our final main.js
const {sendMail} = require('./reportSender');
var cron = require('node-cron');
let counter = 1;
cron.schedule('* * * * *', () => {
/*
generate your report here then send the report using
any reportSender logic that you implemnted email, telegram bot,...
*/
sendMail(`hello world ${counter}`, "this is email body it can contain html also");
counter++;
});
Final words
The idea have alot of potential so you could get creative and make anything you want, the reason i recommended making this as a separate script is that it become another process on the CPU so simply terminate the process if you want to stop the service, in production you have your separate system this script works as an assistant and provides a nice simple feature it could be run using something like pm2
which is strongly recommend.
Top comments (2)
This article just saved me so much time 🎉
Very well written and clearly lays out the path from start to finish.
Loved it!
Thanks look good. Will give it a try.