× {{alert.msg}} Never ask again
Receive New Tutorials
GET IT FREE

Node.js Async Tutorial: Building a Mass Mailer

– {{showDate(postTime)}}

This quick Node.js tutorial will teach you how to implement the Node.js async package in a sample mass mailer app. The tutorial was originally posted at Shaikh Sahid’s blog.


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 is 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 the Mass Mailer from Github

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 how to use the Async package, I am going to show you how to build a mass mailer program which can run as background job and pick up emails from a database, invoke email sending operation parallel. Once it’s done, it gives you a complete result.

For example : 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 of which ones have been successfully sent and which ones have failed, so I need database updates on those too.

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

After the function updates the database, it will check whether the list is empty or not. If not, it will repeat itself. 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 an email to all of them at once because none of them is related with each other. There is no point to wait to send email to abc@xyz.com after abc@yfg.com is done.

Too much explanation. Let’s talk code!

About Async.

Async is a Node.js package and it is designed to control the execution flow of an asynchronous program. Async is available for Node.js as well as for browsers. In this tutorial I am going to use two functions: the .each and .waterfall functions. 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": "~0.9.0",
     "nodemailer": "^1.3.2"
   }
 }

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 = ["rwtc66@gmail.com","shahid@codeforgeek.com"]; 
 // 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({
         service: "Gmail",
         auth: {
             user: "Your gmail ID",
             pass: "Your gmail password"
         }
     });
     // 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: 'shahid@codeforgeek.com',     
                 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 what it’s doing better.

async.each will take the email list from an array and call the sendMail() function “n” number of times at once. Inside the sendMail() function, I am executing an email sending operation and updating database operation in waterfall way. In other words, I’d first send the mail, get the result (whether the email has been sent or not ), then I update the database. Once all the parallel process is done. You will see the result in your console.

Here is the 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 the project 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 !



Author
Shahid Shaikh
Shahid Shaikh
Engineer, Blogger from Mumbai.
Hey there, i am Shahid, Engineer and Blogger from mumbai.
Hire the Author

Questions about this tutorial?  Get Live 1:1 help from Node.js experts!
Yuriy Linnyk
Yuriy Linnyk
5.0
Webdev Coach • 18yr+ Javascript Developer • 5yr+ CodeMentor.
You can understand it! Whether you're catching up in a coding bootcamp, or nailing a bug — reach me in the chat and we'll figure it out. I know you...
Hire this Expert
David Y. Stephenson
David Y. Stephenson
5.0
React/TypeScript engineer with 10+ years experience (david@objective.enterprises)
Reach out anytime at david@objective.enterprises I am a React and TypeScript engineer with over 10 years experience. My specialties are absolute...
Hire this Expert
comments powered by Disqus