Using Alibaba Cloud DirectMail with Web Application

By Sai Sarath Chandra, Alibaba Cloud Tech Share Author. Tech Share is Alibaba Cloud’s incentive program to encourage the sharing of technical knowledge and best practices within the cloud community.

In previous articles, we learned about the features of DirectMail and saw a complete step-by-step guide on setting up Alibaba Cloud DirectMail service. In this particular article, we will see how we can use the DirectMail service within a web application by leveraging the SDK’s provided.

We will create a web application running on a NodeJS as the server. We will also see a brief about the pugJS template engine. We will be using SMTP for sending the emails in the web application.

These are the frameworks/technologies used in the web application:

  1. HTML5
  2. CSS3
  3. MaterializeCSS
  4. ExpressJS
  5. NodeJS

Material Design is created by Google. Material Design is a guideline for developing great user interfaces and creating the best user experience. Inspired by Material Design, MaterializeCSS is a top independent framework that helps us in adopting Material Design.

ExpressJS is a web application framework that helps us in developing web applications and NodeJS very easily. Express JS never overwrite existing node JS functionalities this feature makes Express JS get compared to other frameworks. We shortly see in detail how easy it is to develop applications with Express JS particularly web application and API’s.

NodeJS is built based on Chrome JavaScript runtime. NodeJS helps in running the applications on the server side in a very lightweight fashion. Node JS is actively improving. It is an asynchronous event-driven JavaScript runtime and is designed to build scalable network applications.

Creating the Web Application

About the App

We are going to create a simple login, password reset, and registration flow. Whenever an event (login, forgot password, registration) occurs, we trigger an email from the DirectMail service to inform the user that the event has occurred.

We are going to create the whole application in two steps:

  1. Creating the web application and the API’s
  2. Integrating the web application with the DirectMail service

Setting Up DirectMail

Before we go further, you should make sure the Alibaba Cloud DirectMail service is properly set up and working with one sender Email ID under a Domain.

The whole code is available in GitHub, find the link below: https://github.com/saichandu415/AC-Direct-Mail-Demo

We will be referring to this code during this article. You can start exploring the code by cloning/downloading the repository.

Before we start we need to know some basic principles of pugJS, which is a template engine (helps creating the html pages quickly and easily).

Similar to how html pages bearing .html extension, these pages/files with pugjs ends with .pug

Extends Layout

If you have a file named ‘layout.pug’ which bears some html code, and if we want to reuse the same code across pages you can place ‘extends layout’. This will replace this statement with the content in the ‘layout.pug’. This is one of the features of pugjs that will help us to reuse the code.

Block Content

This is some placeholder within the template. Suppose you extend another layout file, which simply consists of the “block content” statement, you can not only extend the ode but also replace the statement with other content in the runtime. This greatly increases the reusability and makes the code more dynamic.

Pug Markdown to HTML Translation

Let’s look at the similarities and differences of pug markdown by comparing a few examples with HTML.

div.col.s6.offset-s3 translates to <div class="col s6 offset-s3"></div>

div.#signin.row.tabContent translates to <div id="signin" class="row tabContent"></div>

div.row
div.col.s6.offset-s3
div.card

translates to

<div class= "row">
<div class="col s6 offset-s3">
<div class="card">….</div>
</div>
</div>

Note: You need to make sure they are properly indented to currently follow the expected nesting of div/elements.

input#password(type='password') translates to <input id="password" type="password">

This is all you need to know for now to get started with pugjs. There is lot more to learn and you can find it in their official page.

Project Directory Structure

Let’s see the project directory structure first.

/bin

This folder has all the logic related start the server on port number 3000 and also handling the errors if the port is already in use. It consists one file named ‘www’. Copy paste the below code in the file. All methods are self-explanatory, but the key method if you want to change the port:

var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);

The changes in the above two lines is required to change the port. One more thing to notice here is we used the ‘http’ module to create the server. If you want to use ‘https’, then you need to require the https module and bootstrap the SSL Certificates.

/node_modules

This folder consists of all the dependencies downloaded by running the command “npm install”.

/package.json

This file contains all the information related to the dependency & their versions.

{
"name": "AC-Direct-Mail-Demo",
"version": "1.0.0",
"private": true,
"scripts": {
"start": "node ./bin/www"
},
"dependencies": {
"cookie-parser": "~1.4.3",
"debug": "~2.6.9",
"express": "~4.16.0",
"http-errors": "~1.6.2",
"morgan": "~1.9.0",
"nodemailer": "^4.6.7",
"pug": "2.0.0-beta11"
}
}

You can also update this file by running the npm install <package-name> --save command. This installs the latest and update the same in the package.json

/routes

We can relate that routes folder contains the backend logic on the server required for manipulating the html page using nodejs modules. It is good practice to have a separate js files for every html page in the front end.

index.js

var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
module.exports = router;

We import the dependency for the express and create an express router object to register the router. Then we register the get functionality to the express router on the base path ‘/’. This means that this particular index.html will be loaded when the application is invoked on http://localhost:3000/. And then we will export the method on the router.

If you see the line res.render('index', { title: 'Express' });, this provides us an ability to send the information to the html page to render the information even though we are not using that in this specific scenario. This also make sure it searches for the index.pug file within the applications 'views' folder and then translates to the valid html and send back to the client/user.

/public

This folder consists of the client-side scripts required for the functionalities, images used in the application & stylesheets required.

Images

This contains all the images required for the applications

Stylesheets

This contains all the CSS/SCSS file required for the application. Although SCSS needs to be converted to CSS before rendering the page to client from server.

Javascripts

This contains all the script files required to while rendering the html page at the client side for execution.

/views

Contains the pugjs template files for the translations. If we are not using the pugjs, we should have the .html files in the same folder.

layout.pug

This file consists of the basic layout related code, which is repeatable across pages

doctype html
html
head
style
include ../public/stylesheets/style.css
title= 'Alibaba Cloud | Direct Mail Demo'
link(rel="stylesheet", href="https://fonts.googleapis.com/icon?family=Material+Icons")
link(rel="stylesheet", href="https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-rc.2/css/materialize.min.css")
script(src='https://cdnjs.cloudflare.com/ajax/libs/materialize/1.0.0-rc.2/js/materialize.min.js', type="text/javascript")

Block Content

The key thing to notice here is that pug allows us to keep HTML along with the pugjs markdown, which helps developers at times to include plain html code if they feel any limitation with pugjs.

This file in particular contains all the header information of the html, and a placeholder to insert the body related information. As said we will be using the materialize.css, imported the CDN version of the files and we will also be needing the materialize.js files for some of the components to work as expected along with the Material Icons.

error.pug

This is the fallback error page in case of any issues.

index.pug

This file consists of the complete logic for the whole web application, I have took the advantage of the ‘tabs’ functionality, which helps me to create both login and registration flows on a single page.

Let’s see the code for this page:

extends layoutblock content
body
.container
h1 Alibaba Cloud DirectMail Demo
div.row
div.col.s6.offset-s3
div.card
div.card-tabs
ul.tabs.tabs-fixed-width
li.tab.col.s6
a(href='#signin')
strong Sign In
li.tab.col.s6
a(href='#signup')
strong Sign Up
div.card.content.grey.lighten-4
#signin.row.tabContent
form.col.s12
.row
.col.s12.input-field.inline
input#email_inline.validate(type='email')
label(for='email_inline') Email
span.helper-text(
data-error='Please provide valid email'
data-success='Valid Email'
)
.col.s12.input-field.inline
input#password(type='password')
label(for='password') Password
.row
button.col.s4.offset-s1.btn.waves-effect.waves-light(
type=button
onclick='login()'
) Login
i.material-icons.right send
button.col.s4.offset-s2.waves-effect.waves-teal.btn-flat(
type=button
onclick='forgotPassword()'
) Forgot Password
i.material-icons.right help_outline
#signup.row.tabContent
form.col.s12
.row
.col.s6.input-field.inline
input#first_name(type='text')
label(for='first_name') First Name
.col.s6.input-field.inline
input#last_name(type='text')
label(for='last_name') Last Name
.col.s12.input-field.inline
input#phnNumber(type='number')
label(for='phnNumber') Phone Number
.col.s12.input-field.inline
input#email_reg(type='email')
label(for='email_reg') Email
.col.s12.input-field.inline
input#password(type='password')
label(for='password') Password
button.col.s12.btn.waves-effect.waves-light(
type=button
onclick='register()'
) Register Me !!
script
include ../public/javascripts/utilities.js

There are couple of things to note here:

extends layout

As mentioned earlier, we are using the base layout file and reusing the common code.

div.card

This contains the tabs in the card layout.

div.card.content.grey.lighten-4

This division contains the content for each tab.

include ../public/javascripts/utilities.js

This will include the utilities script when the html pages are rendered.

app.js

This is the complete logic for the server-side app.

var nodemailer = require('nodemailer');
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
app.use('/', indexRouter);
app.use('/users', usersRouter);

We will create the router objects and bootstrap with the application object (app).

var transporter = nodemailer.createTransport({
"host": "smtpdm-ap-southeast-2.aliyun.com",
"port": 25,
"secureConnection": false, // use SSL
"auth": {
"user": 'admin@mail.actestdomain.xyz', // user name
"pass": 'AdMIN12345'
}
});

We will create the transporter object with all the information required.

app.post('/sendMail', function (req, res, next) {
var reqBody = req.body;
var mailOptions = {
from: 'admin@mail.actestdomain.xyz', // sender address mailfrom must be same with the user.
to: reqBody.email_inline, // list of receivers
cc: '', // copy for receivers
bcc: '', // secret copy for receivers
subject: reqBody.subject, // Subject line
text: '', // plaintext body
html: reqBody.body // html body
};
transporter.sendMail(mailOptions, function(error, info){
if(error){
return console.log(error);
}
console.log('Message sent: ' + info.response);
res.send('');
});
});

app.post will create a /sendMail which receives an object and create mailOptions object which contains all the information required for the mail.

transporter.sendMail will use the mailOptions to send the mail send the response if the mail send is success.

You can see all the detailed code at the below GitHub repository for detailed instructions
https://github.com/saichandu415/AC-Direct-Mail-Demo

You are welcome to improve the project by raising the GitHub issues or pull requests.

Reference:

https://www.alibabacloud.com/blog/using-alibaba-cloud-directmail-with-web-application_593948?spm=a2c4.11980437.0.0

Written by

Follow me to keep abreast with the latest technology news, industry insights, and developer trends.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store