By Russell Taylor, Growth Engineer, at Lob.
Here at Lob we specialize in print and mail. More specifically, we have built an API that provides a RESTful interface for printing and mailing postcards, letters, checks, photos, and more. Over the years we’ve seen all sorts of creative implementations of our APIs, but one use case we keep seeing is the need for companies to verify a user's physical mailing address.
Companies like Couchsurfing, Google Local, and Yelp have all solved this problem by sending address verification postcards to users that contain individualized activation codes. Several of our own customers are doing this and we are excited to share a simple solution that utilizes our Postcard Printing API, the Mandrill Email API, and the hapi Node.js web server.
In this tutorial we are going to walk you through how to setup a user registration form that will send a confirmation email and a postcard that contains a validation code. After a user receives the postcard, they will visit the website on the postcard and enter the validation code to confirm their mailing address.
This is not an exhaustive tutorial since we will not be persisting any data. Instead I hope to show you a basic skeleton that you can use in your own Node.js project and extend to meet your needs.
Contents
- Introduction
- Configure email sending via Mandrill
- Configure postcard sending via Lob
- Wire up registration form and sending with Hapi
- Testing
Before you start
- You will need to head over to Lob and Mandrill to register for test API keys.
- I’m assuming you are somewhat familiar with JavaScript and Node.js. You don’t need to be an expert, but it will be advantageous if you have used server side JavaScript before.
- I’ll be using the the Bluebird promise library to chain together asynchronous API calls. If you aren’t familiar with promises, I suggest a little light reading before getting started.
- This project’s source code is available on GitHub. Just clone the repository and follow the instructions in the README.md to get started. It is a good idea to get the project running locally so you can reference it during the tutorial.
Quick Preview
Here is a screenshot of the Lob dashboard and the postcard we will be sending out to users as they sign up:
Project Structure
This whole project will live inside the hapi framework. Hapi is minimalistic Node.js framework that favors configuration over code. All the functionality of the project will live inside the plugin called lob-registration-postcard
which will utilize two reusable services called email.js
and lob.js
. Again, make sure to check out the GitHub repository to download and run the full project.
Here is what the src
folder of our project looks like:
Main server.js File
This is our main application file. It serves to include the necessary plugins and services, as well as create the server connection.
'use strict';
var Hapi = require('hapi');
var server = new Hapi.Server();
server.register([
require('./services/config'),
require('./services/lob'),
require('./services/email')
], function (err) {
if (err) {
throw err;
}
});
server.connection({
port: server.plugins.config.port,
labels: ['http']
});
server.views({
engines: {
hbs: require('handlebars')
},
relativeTo: __dirname,
path: './views',
layoutPath: './views/layouts',
layout: 'defaultLayout'
});
server.register([
require('./plugins/lob-registration-postcard')
], function (err) {
if (err) {
throw err;
}
});
server.start();
console.log('Server Started on:', server.info.uri);
Notice that one of the registered services is require('./services/config')
. Take a peek at this directory and you will notice a development.json
file which contains some of our configuration variables for the project. This includes a default FROM address and our API keys.
Once you have signed up for your Lob and Mandrill API keys, go ahead and plug them in here.
{
"port": 3000,
"lob_api_key": "XXX",
"mandrill_api_key": "XXX"
"fromAddress": {
"name": "Lob",
"email": "joe@example.com",
"address_line1": "185 Berry",
"address_line2": "Suite 1851",
"address_city": "San Francisco",
"address_state": "CA",
"address_zip": "94117",
"address_country": "US"
}
}
The Services
For the purposes of this tutorial, I’ll be organizing our code into two categories, Services and Plugins. Services will be used to create wrappers around both the Lob and Mandrill APIs. It’s completely possible to use both these APIs right inside our main plugin, but by creating services we can easily reuse their functionality across the project.
Configure email sending via Mandrill
The main goal of the email.js
service will be to provide a single sendEmail()
function that will accept a FROM and TO address as parameters. The strategy here is to abstract away all the logic that builds and sends a message, so that when we call sendEmail()
we will be returned a promise that can be used in a promise chain.
Here is the complete code for email.js
which I’ll explain in detail below:
var Bluebird = require('bluebird');
exports.register = function (server, options, next) {
var mandrill = require('mandrill-api/mandrill');
var mandrill_client = new mandrill.Mandrill(server.plugins.config.mandrill_api_key);
var send = function (message) {
return new Bluebird(function (resolve, reject) {
mandrill_client.messages.send({
message: message,
async: false
}, function (result) {
return resolve(result);
}, function (e) {
return reject(e);
});
});
};
var buildEmailMessage = function (toAddress) {
var msg = '<p>Hey ' + toAddress.name + ',</p>';
msg += '<p>We are happy you have decided to user our service. ';
msg += 'An address verification postcard has been sent to:</p>';
msg += '<p>' + toAddress.name + '</p>';
msg += '<p>' + toAddress.address_line1 + '</p>';
msg += '<p>' + toAddress.address_city + ', ';
msg += toAddress.address_state + ', ';
msg += toAddress.address_zip + '</p>';
msg += '<p>When you receive the postcard, follow the instruction on the card to verify your home address</p>';
msg += '<p>-- The Team</p>';
return msg;
}
var sendEmail = function sendEmail (fromAddress, toAddress) {
var message = {
'html': buildEmailMessage(toAddress),
'subject': 'Welcome to the Club!',
'from_email': fromAddress.email,
'from_name': fromAddress.name,
'to': [{
'email': toAddress.email,
'name': toAddress.name,
'type': 'to'
}],
};
return send(message);
}
server.expose('sendEmail', sendEmail);
next();
};
exports.register.attributes = {
name: 'email',
};
At the top of the service we need to include and initialize the Mandrill API. Notice that we are pulling in our API key from the config file I mentioned earlier and passing it as an argument.
var mandrill = require('mandrill-api/mandrill');
var mandrill_client = new mandrill.Mandrill(server.plugins.config.mandrill_api_key);
If you take a look at the var send = function (message){}
function you will notice that we need to do a little extra work here because the Mandrill API does not automatically return a promise when calling the send function. In this situation we can use Bluebird to wrap the Mandrill API callback in a promise.
Now we are ready to write the sendEmail()
function, which will be called once the user has successfully registered. All we need to do is build the message JSON as specified by the Mandrill Message Docs and then return our promisified send()
function.
var message = {
'html': buildEmailMessage(toAddress),
'subject': 'Welcome to the Club!',
'from_email': fromAddress.email,
'from_name': fromAddress.name,
'to': [{
'email': toAddress.email,
'name': toAddress.name,
'type': 'to'
}],
};
return send(message);
The last thing we need to do is expose our sendEmail()
function so that we can call it from inside our plugin.
server.expose('sendEmail', sendEmail);
Configure postcard sending via Lob
As with the email service, the main purpose of the lob.js
service will be to expose the necessary API endpoints for use in our plugin. The lob API natively returns promises for each call, which means we won’t need to wrap anything using Bluebird.
Here is the complete code for the service, which I’ll break out for explanation below:
var randomstring = require("randomstring");
exports.register = function (server, options, next) {
var Lob = require('lob')(server.plugins.config.lob_api_key);
var verifyAddress = function (payload) {
return Lob.verification.verify({
address_line1: payload.address,
address_city: payload.city,
address_state: payload.state,
address_zip: payload.zip,
address_country: 'US',
});
}
var createAddress = function (payload , verifiedAddress) {
return Lob.addresses.create({
description: 'User ' + payload.name + '\'s Address',
name: payload.name,
email: payload.email,
address_line1: verifiedAddress.address_line1,
address_city: verifiedAddress.address_city,
address_state: verifiedAddress.address_state,
address_zip: verifiedAddress.address_zip,
address_country: verifiedAddress.address_country
});
}
var createPostcard = function (toAddress, postcardFront) {
return Lob.postcards.create({
description: 'Registration Postcard for ' + toAddress.name,
to: toAddress.id,
from: server.plugins.config.fromAddress,
front: postcardFront,
message: 'Welcome to the club!',
data: {
activate_code: randomstring.generate(5)
}
});
}
server.expose('createPostcard', createPostcard);
server.expose('createAddress', createAddress);
server.expose('verifyAddress', verifyAddress);
next();
};
exports.register.attributes = {
name: 'lob',
};
The first thing we need to do is load the Lob API. As with the email.js
service we are including our API key from the config file.
var Lob = require('lob')(server.plugins.config.lob_api_key);
The first Lob functionality we want to expose is the address verification API. When a user registers and provides a mailing address we want to make sure it’s a valid address before sending them a postcard, otherwise we should prompt them with an error message.
var verifyAddress = function (payload) {
return Lob.verification.verify({
address_line1: payload.address,
address_city: payload.city,
address_state: payload.state,
address_zip: payload.zip,
address_country: 'US',
});
}
The payload
parameter is just the result of the user submitted form that we will go over in a minute. Make sure to check out the address verification docs for a full explanation of the address verification endpoint.
Note: I’m assuming mailing addresses are domestic by hardcoding the country as US. Make sure to update this field if you provide a country option in your registration form.
Once we know a user submitted mailing address is valid, we will need to create the address using the Lob.addresses.create
endpoint. Take a look at the address create docs for a full description of the fields.
var createAddress = function (payload , verifiedAddress) {
return Lob.addresses.create({
description: 'User ' + payload.name + '\'s Address',
name: payload.name,
email: payload.email,
address_line1: verifiedAddress.address_line1,
address_city: verifiedAddress.address_city,
address_state: verifiedAddress.address_state,
address_zip: verifiedAddress.address_zip,
address_country: verifiedAddress.address_country
});
}
Finally, in order to print and mail postcards, we need to expose the postcard create endpoint.
var createPostcard = function (toAddress, postcardFront) {
return Lob.postcards.create({
description: 'Registration Postcard for ' + toAddress.name,
to: toAddress.id,
from: server.plugins.config.fromAddress,
front: postcardFront,
message: 'Welcome to the club!',
data: {
activate_code: randomstring.generate(5)
}
});
}
This is the core of the tutorial so lets break down each field for a closer look. Make sure to check out the postcard api documentation for full descriptions and additional options:
- description: a meta field to help find and organize postcard requests.
- to: accepts the ID of the address created with our createAddress()function.
- from: we are just passing the default FROM address from our config file.
- front: HTML template design for the front of the postcard.
- message: text that will be displayed on the back of the postcard.
- data: variables to pass to our postcard template file.
Notice that we are passing an activation code variable in the data field. For the purposes of this tutorial I’m just generating a random string. In a real world example you will need to store each activation code so that the user can confirm it later.
And last but not least, we need to expose these three functions.
server.expose('createPostcard', createPostcard);
server.expose('createAddress', createAddress);
server.expose('verifyAddress', verifyAddress);
Wire up registration form and sending with Hapi
Now that our services are in place we turn our attention to the plugin. Here is the hapi definition of a plugin:
hapi has an extensive and powerful plugin system that allows you to very easily break your application up into isolated pieces of business logic, and reusable utilities.
We will use the lob-registration-postcard
plugin to define our routes and business logic for when a user submits the registration form. The first thing we need to do is include the services that we just wrote so that we have access to the Lob and Mandrill APIs.
var Lob = server.plugins.lob;
var Email = server.plugins.email;
Next, lets take a look at the registration form. The route configuration is pretty simple for this one. We are just letting Hapi know that when someone does a GET request on the root url, that we need to render the the home
view.
server.route([{
method: 'GET',
path: '/',
config: {
handler: function (request, reply) {
reply.view('lob-registration-postcard/home');
}
}
Here's what the form looks like:
If you open up the /src/views/lob-registration-postcard/home.hbs
file you will see the HTML used to generate the registration form. This is just basic HTML, but take note that we are posting the form back to the root url.
<form action="/" method="POST" class="form">
Now we are ready to pull all our hard work together and write the logic for when a user submits the registration form. Here is the code in full, I’ll walk you through each step below:
method: 'POST',
path: '/',
config: {
handler: function (request, reply) {
readFile( __dirname + '/postcard_template.html', 'utf8')
.bind({})
.then(function (templateFile) {
this.postcardFront = templateFile;
return Lob.verifyAddress(request.payload)
})
.then(function (verifiedAddress) {
return Lob.createAddress(request.payload, verifiedAddress.address);
})
.then(function (toAddress) {
this.toAddress = toAddress;
return Lob.createPostcard(this.toAddress, this.postcardFront);
})
.then(function (postcard) {
this.postcard = postcard;
return Email.sendEmail(
server.plugins.config.fromAddress,
this.toAddress
);
})
.then(function (mail) {
reply.view('lob-registration-postcard/success');
})
.catch(function (error) {
reply(error);
});
}
The first step in our promise chain is to read in the postcard template file.
readFile( __dirname + '/postcard_template.html', 'utf8')
Here is a screenshot of the postcard we will be sending out to users as they sign up:
If you open up the /postcard_template.html
you will find the basic HTML and CSS for our postcard design. I’ve omitted the CSS, but take a look at the HTML and note the template variable used for the activation code, {{activate_code}}
.
<body>
<div id="safe-area">
<div class="text">
<h1>Welcome to the Club!</h1>
<p>To verify your address, visit www.example.com/verify and use the activation code below.</p>
</div>
<div class="activation-code">
{{activate_code}}
</div>
</div>
</body>
The Lob Postcard API can also accept PDF, JPEG, and PNG files for postcard designs, but by using HTML we have the ability to define variables in the template file that can be replaced with unique values. This is how we will dynamically assign an activation code to each user as they register. The syntax for template variables look like this: {{variable_name}}
The next step in the promise chain is to verify the mailing address submitted by the user. All we need to do is pass the data from our form submission (request.payload)
to the verifyAddress()
function we built earlier.
.then(function (templateFile) {
this.postcardFront = templateFile;
return Lob.verifyAddress(request.payload)
})
If the address passes validation, we create it and then pass it to the Lob.createPostcard()
function along with the HTML file for the front of the postcard.
.then(function (verifiedAddress) {
return Lob.createAddress(request.payload, verifiedAddress.address);
})
.then(function (toAddress) {
this.toAddress = toAddress;
return Lob.createPostcard(this.toAddress, this.postcardFront);
})
And finally, once the postcard has been successfully created, we send the user an email and then reply with a success message.
.then(function (postcard) {
this.postcard = postcard;
return Email.sendEmail(
server.plugins.config.fromAddress,
this.toAddress
);
})
.then(function (mail) {
reply.view('lob-registration-postcard/success');
})
Testing
So, by this point you should have all the pieces in place and be ready to test. Go ahead and submit your registration form with some test data, making sure to use an email you have access to. If everything works as expected you should be redirected to the success page after submitting the form. If not, you will probably see some errors printed to the screen.
Now, two things should happen: you should receive an email and you should be able to see your postcard in the Lob Dashboard. If you are logged into the Lob Dashboard click the Postcards
tab to see recent activity. If your postcard is there click it and you should see a preview/details page like this:
Final Thoughts
Hopefully you are at a point where you can start extending this example to fit your specific needs. If you have any questions about the tutorial or Lob services, don't hesitate to drop us a line.