Node.js async tutorial – Mass Mailer example

Node.js is asynchronous in nature and runs on single threaded event loop. But how that work ? Well let’s say you have fired a database query and you are waiting for query to execute and then proceed further, but in a same scenario what will happen to the piece of code which are not dependent on that database query ? they won’t execute and wait for their turn.

Asynchronous is exactly opposite of this. While you are doing database query Node.js will continue executing code and when database query will be done, it will come back to process it.

DOWNLOAD

This is one of the great feature to improve performance of the application but as a developer you got little more pain to handle particular scenarios ( like sending E-mail Mass mailer ) or your code will turn-up into callback hell.

Our demo application :

To demonstrate use of Async package i am going to show you how to build mass mailer program which can run as background job and pick up email from database, invoke email sending operation parallel and once done, gives you complete result.

For.eg : Let’s say i have 100 emails and i want to invoke email operation but other than sending an email what i need to do is to have a record of emails which are successfully sent and also which are failed so i need database update too.

What i can normally is write a Node.js function which returns me list of emails, invoke another function which send email to one of the email from the list, once it is done, another function to update database.

After updating database check whether list is empty or not and if not repeat same. Very well, simple and sweet.

But i am not gonna do that ! What i am gonna do is invoke email sending operation at once. That means if i got 100 emails, i should send email all of them at once because none of them is related with each other so there is no point to wait to send email to [email protected] after [email protected] is done.

Too much explanation. Let’s talk code !

About Async.

Async is node.js package and it is designed to control execution flow of asynchronous program like JavaScript. Async is available for Node.js as well as for browsers. In this tutorial i am going to use two function called .each and .waterfall function. There are many more in the documentation.

.each : This is like For loop in asynchronous nature, you can call modules using .each in parallel.
.waterfall : Modules written in waterfall will pass data to next module until last module is over.

Implementation:

Here is our package.json file.

package.json
{
  "name": "async-nodejs-demo",
  "version": "0.0.1",
  "dependencies": {
    "async": "latest",
    "nodemailer": "latest"
  }
}

Type

npm install

to install those packages.

Server.js :

Server.js
/*
 * File Name : Server.js
 * Task : Run Server and fetch multiple emails from DB to send reminder
 * Invoke all the email task at once and update DB once the email is sent
*/


/*
 * Load all the required modules
*/


var async = require("async");
var http = require("http");
var nodemailer = require("nodemailer");
// This will store emails needed to send.
// We can fetch it from DB (MySQL,Mongo) and store here.
var listofemails = ["[email protected]","[email protected]"];
// Will store email sent successfully.
var success_email = [];
// Will store email whose sending is failed.
var failure_email = [];

var transporter;

/* Loading modules done. */

function massMailer() {
    var self = this;
    transporter = nodemailer.createTransport("SMTP",{
          host: 'smtp.gmail.com',
          port: 587,
          auth: {
            user: '',
            pass: ''
         },
          tls: {rejectUnauthorized: false},
          debug:true
        });
    // Fetch all the emails from database and push it in listofemails
        // Will do it later.
    self.invokeOperation();
};

/* Invoking email sending operation at once */

massMailer.prototype.invokeOperation = function() {
    var self = this;
    async.each(listofemails,self.SendEmail,function(){
        console.log(success_email);
        console.log(failure_email);
    });
}

/*
* This function will be called by multiple instance.
* Each instance will contain one email ID
* After successfull email operation, it will be pushed in failed or success array.
*/


massMailer.prototype.SendEmail = function(Email,callback) {
    console.log("Sending email to " + Email);
    var self = this;
    self.status = false;
    // waterfall will go one after another
    // So first email will be sent
    // Callback will jump us to next function
    // in that we will update DB
    // Once done that instance is done.
    // Once every instance is done final callback will be called.
    async.waterfall([
        function(callback) {               
            var mailOptions = {
                from: [email protected]',    
                to: Email,
                subject: 'Hi ! This is from Async Script',
                text: "Hello World !"
            };
            transporter.sendMail(mailOptions, function(error, info) {              
                if(error) {
                    console.log(error)
                    failure_email.push(Email);
                } else {
                    self.status = true;
                    success_email.push(Email);
                }
                callback(null,self.status,Email);
            });
        },
        function(statusCode,Email,callback) {
                console.log("Will update DB here for " + Email + "With " + statusCode);
                callback();
        }
        ],function(){
            //When everything is done return back to caller.
            callback();
    });
}

new massMailer(); //lets begin

Code is little bit tricky because there is so much callbacks but i am sure after looking to this diagram you will understand it better.
explanation
async.each will take email list from an array and call sendMail() function “n” number of times at once. Inside sendMail() function i am executing email sending operation and updating database operation in waterfall way, i.e first send mail, get the result ( email send or not ) then update the database. Once all the parallel process is done. You will see the result in console.

Here is the output.
output

More about Async package:

Async is one of the great contribution to node.js community. With this package you can control the flow of execution of your program like never before. Whether its serial, parallel, waterfall or queuing, async won’t disappoint you.

Please visit their documentation once and don’t forget to star it on Github.

Conclusion:

I have lot to say about Async but at same time i don’t wanna increase the size of this tutorial. Next couple of weeks you will hear more about Async and its example usage in various real time scenarios. Meantime you can visit their documentation and learn more !

Shahid (UnixRoot) Shaikh

Hey there, This is Shahid, an Engineer and Blogger from Bombay. I am also an Author and i wrote a programming book on Sails.js, MVC framework for Node.js.

Related Posts

9 Comments

    1. Asycn.parallel will execute those task in parallel while async.waterfall will call one after another by passing one function data to another and so on. Here my need was that, i want to send the mail and update DB but only after mail is sent. If i do it parallel both operation will execute on same time and this won’t solve my problem.

  1. Hi,
    I’m beginer.
    Please help me explain about code:

    callback(null,self.status,Email); <—- null : what is this ?

    Can I move position of this parameter ?

    callback(self.status,Email,null);

    Thanks!

      1. Thanks for quick reply,

        Case 1:
        What happens when i remove “callback” function ?
        massMailer.prototype.SendEmail = function(Email, )

        “ReferenceError: callback is not defined” <— error msg from optional callback
        function(){ //When everything is done return back to caller.
        callback(); // error from here }

        Result:
        Sending email to A
        Sending email to B
        Send mail is success
        Will update DB here for A With true
        optionalCallback
        ReferenceError: callback is not defined

        Why ?

        Case 2:
        Remove "callback" at the first task array
        function() { var mailOptions = {…} …}

        I don’t see error msg as case 1, but It just doesn’t go to next functions
        function(statusCode,Email,callback) {..} and optional callback function.
        and then
        Dump: success_email, failure_email into aysnc.each();

        Result
        Sending email to A
        Sending email to B
        Send mail is success
        Send mail is success
        Success: [A, B]
        Failure: []

        Case 3:
        Remove “call back” function into transporter.sendMail();
        //callback(null,self.status,Email); <—–
        Doesn't go to next functions
        function(statusCode,Email,callback) {..} and optional callback function.
        and not dump into aysnc.each();

        Result :
        Sending email to A
        Sending email to B
        Send mail is success
        Send mail is success

        Please help me about three case!

        Regards,

        1. Sure.

          Basically callback in async is way to say that this is done.

          Considering every cases you mentioned, if you remove callback it will not push the execution order of it into async execution array and hence you will either not get to next function or get an error.

          I have written detailed tutorial on how to handle the async nature of Node, here it is.

Leave a Reply

Your email address will not be published. Required fields are marked *