The rich text element allows you to create and format headings, paragraphs, blockquotes, images, and video all in one place instead of having to add and format them individually. Just double-click and easily create content.

NOTE: This example was created on an outdated version of the Lob API. Please see the latest Lob documentation for the most up-to-date information on integrating with Lob.

Traditionally, tracing mail is a difficult and time consuming process. However, recent tech innovations are changing the landscape. At Lob, most of our customers would like to keep track of their mail pieces in real time as they move through the USPS mail stream.

With Lob, you can now set up webhooks to receive real-time tracking events to show you exactly where your mail is in the delivery process. This tutorial will show you how to build a Rails web app that is ready to receive Lob's webhooks.

Hate to read instructions? We've got all the source code for this example available in a public repository.

What are we building?

This tutorial will show you how to build a website to verify your personal address by sending a postcard with a unique verification code. Once you build the site and add an intake form, you can use Lob's webhooks to set up automated emails as the postcard moves through transit and delivery.

Who is this tutorial for?

This tutorial is geared towards web developers that have at least some experience with Ruby on Rails. You don't need to be an expert, but it will help to have played around with Rails and APIs before.

The Toolkit

Ruby on Rails – Rails is a popular web application framework running on the Ruby programming language.

– Rails is a popular web application framework running on the Ruby programming language. Lob's Postcard API – Lob has a whole suite of RESTful APIs for printing and mailing. We will be using the Postcard API in this tutorial.

– Lob has a whole suite of RESTful APIs for printing and mailing. We will be using the Postcard API in this tutorial. Lob's Webhook API - We'll also be using Lob's Webhook functionality.

- We'll also be using Lob's Webhook functionality. SendGrid API - We'll be using SendGrid's Ruby Gem to send out email notifications.

Prerequisites

Before diving into the code, we will need to register for a Lob and SendGrid API key.

Lob

Visit the registration page and sign up for an account. You will be given a Test API Key which will give you full access to the API in a sandbox environment. All of Lob's Printing APIs are free to try. When in Test mode, you can create postcards and view them in the dashboard, but nothing will actually be mailed until you use a Live API Key.

SendGrid

Sign up for a SendGrid account and create an API Key.

Create the Project

$ rails new webhooks-demo

$ cd webhooks-demo



Install Dependencies

Place all the Ruby gems we will be using to create our app in the Gemfile. The versions we will be using in this tutorial are as follows:

gem 'sendgrid-ruby', '~> 4.0.8'

gem 'lob', '~> 3.0.0'

gem 'devise', '~> 4.2.1'

gem 'sidekiq', '~> 4.2.10'

$ bundle install



Set Up the User Model

We're going to be using Devise, a popular, flexible authentication solution for Rails.

$ rails generate devise:install



After this, we'll create a User table and model by utilizing another one of Devise's generators.

$ rails generate devise User



Now that we have Devise set up, we'll need to add a few fields to the User table.

verification_code - store unique verification code that will be printed on the postcard

verified - store verified state

verification_postcard_id - store the id of the postcard returned by Lob's API

first_name, last_name, ... address_country - store postcard delivery address

$ rails generate migration AddVerificationToUser



/db/migrate/xxxxx_add_verification_to_user.rb

class AddVerificationToUser < ActiveRecord::Migration[5.0]

def change

add_column :users, :verification_code, :string

add_column :users, :verified, :boolean, :default => false

add_column :users, :verification_postcard_id, :string

add_column :users, :first_name, :string

add_column :users, :last_name, :string

add_column :users, :address_line1, :string

add_column :users, :address_line2, :string

add_column :users, :address_city, :string

add_column :users, :address_state, :string

add_column :users, :address_zip, :string

add_column :users, :address_country, :string

end

end



Now we can run the migrations.

$ rake db:migrate



In the model, you will see that Devise has added in some code to handle authentication automatically. We'll use a before_create hook in the model to generate a unique code before saving the user to the database. To do this, we can use the SecureRandom library.

We'll use an after_create hook to trigger a Sidekiq worker that will receive the user_id and send the verification postcard. We'll be creating this worker later.

/models/user.rb

class User < ApplicationRecord

before_create :generate_verification_code

after_create :send_verification_postcard

devise :database_authenticatable, :registerable,

:recoverable, :rememberable, :trackable, :validatable



private



def generate_verification_code

self.verification_code = SecureRandom.hex(6)

end



def send_verification_postcard

PostcardWorker.perform_async(self.id)

end

end



Create the Sign Up Page

We'll need to modify the registrations controller and views created by Devise to accept these relevant fields upon sign up.

$ rails generate controller registrations



/controllers/registrations_controller.rb

class RegistrationsController < Devise::RegistrationsController



private



def sign_up_params

params.require(:user).permit(:first_name, :last_name, :address_line1, :address_line2, :address_city, :address_state,

:address_zip, :address_country, :email, :password, :password_confirmation)

end



def account_update_params

params.require(:user).permit(:first_name, :last_name, :address_line1, :address_line2, :address_city, :address_state,

:address_zip, :address_country, :email, :password, :password_confirmation, :current_password)

end

end



/views/devise/registrations/new.html.erb

<div class="field">

<%= f.label :first_name %><br />

<%= f.text_field :first_name %>

</div>



<div class="field">

<%= f.label :last_name %><br />

<%= f.text_field :last_name %>

</div>



<div class="field">

<%= f.label :address_line1 %><br />

<%= f.text_field :address_line1 %>

</div>



<div class="field">

<%= f.label :address_line2 %><br />

<%= f.text_field :address_line2 %>

</div>



<div class="field">

<%= f.label :address_city %><br />

<%= f.text_field :address_city %>

</div>



<div class="field">

<%= f.label :address_state %><br />

<%= f.text_field :address_state, maxlength: 2, size: 4 %>

</div>



<div class="field">

<%= f.label :address_zip %><br />

<%= f.text_field :address_zip, maxlength: 11, size: 15 %>

</div>



<div class="field">

<%= f.label :address_country %><br />

<%= f.text_field :address_country, maxlength: 2, size: 4 %>

</div>



Generate Postcard Worker

Next, we'll need to create the Sidekiq PostcardWorker we called in the User model earlier.

$ rails generate sidekiq:worker Postcard



In our worker, we're going to initialize the Lob client and lookup the user_id passed in, so we can determine the verification code we need to print on the postcard. We're going to use the postcard template found in the templates gallery. We'll pass in the first_name and verification_code as data parameters.

Once we successfully complete the request, we'll store the postcard_id Lob returns so that we can associate which user should be receiving the tracking notifications.

/workers/postcard_worker.rb

class PostcardWorker

include Sidekiq::Worker



def perform(user_id)

lob = Lob::Client.new(api_key: ENV['LOB_API_KEY'])

user = User.find(user_id)



postcard = lob.postcards.create({

description: "Verification Postcard - #{user.id}",

to: {

name: user.first_name + " " + user.last_name,

address_line1: user.address_line1,

address_line2: user.address_line2,

address_city: user.address_city,

address_state: user.address_state,

address_country: user.address_country,

address_zip: user.address_zip

},

from: {

name: "Larry Lobster",

address_line1: "185 Berry St, Suite 6600",

address_city: "San Francisco",

address_state: "CA",

address_country: "US",

address_zip: "94110"

},

front: %Q(

<html>

<head>

<meta charset="UTF-8">

<link href='https://fonts.googleapis.com/css?family=Source+Sans+Pro:700' rel='stylesheet' type='text/css'>

<title>Lob.com Address Verification 4x6 Postcard Template Front</title>

<style>

*, *:before, *:after {

-webkit-box-sizing: border-box;

-moz-box-sizing: border-box;

box-sizing: border-box;

}

body {

width: 6.25in;

height: 4.25in;

margin: 0;

padding: 0;

/* your background image should have dimensions of 1875x1275 pixels. */

background-image: url('https://s3-us-west-2.amazonaws.com/lob-assets/homelove-pc-bg.jpg');

background-size: 6.25in 4.25in;

background-repeat: no-repeat;

}

/* do not put text outside of the safe area */

#safe-area {

position: absolute;

width: 5.875in;

height: 3.875in;

left: 0.1875in;

top: 0.1875in;

text-align: center;

}

#logo {

height: 1in;

position: relative;

top: .9in;

}

#tagline {

position: relative;

top: 1in;

font-family: 'Source Sans Pro';

font-weight: 700;

font-size: .16in;

text-transform: uppercase;

letter-spacing: .03in;

color: white;

border-top: 1px solid white;

padding-top: .15in;

width: 4in;

margin: auto;

}

</style>

</head>



<body>

<!-- do not put text outside of the safe area -->

<div id="safe-area">



<!-- your logo here! -->

<img src="https://s3-us-west-2.amazonaws.com/lob-assets/homelove-logo.png" id="logo">



<div id="tagline">

Get verified and start selling!

</div>



</div>

</body>



</html>

),

back: %Q(

<html>

<head>

<meta charset="UTF-8">

<link href='https://fonts.googleapis.com/css?family=Source+Sans+Pro:400,700' rel='stylesheet' type='text/css'>

<title>Lob.com Address Verification 4x6 Postcard Template Back</title>

<style>



*, *:before, *:after {

-webkit-box-sizing: border-box;

-moz-box-sizing: border-box;

box-sizing: border-box;

}



body {

width: 6.25in;

height: 4.25in;

margin: 0;

padding: 0;

background-color: white;

}



#banner {

height: 1in;

background-color: #9b2a62;

font-family: 'Source Sans Pro';

font-weight: 700;

font-size: .16in;

text-transform: uppercase;

letter-spacing: .03in;

color: white;

text-align: center;

padding-top: .5in;

}



/* do not put text outside of the safe area */

#safe-area {

position: absolute;

width: 5.875in;

height: 3.875in;

left: 0.1875in;

top: 0.1875in;

}



#message {

position: absolute;

width: 2.2in;

height: 2in;

top: 1.1in;

left: .25in;

font-family: 'Source Sans Pro';

font-weight: 400;

font-size: .13in;

}



#code-banner {

text-align: center;

font-size: .13in;

}



#code {

font-family: 'Source Sans Pro';

font-weight: 700;

font-size: .13in;

text-transform: uppercase;

letter-spacing: .02in;

color: #9b2a62;

border: 2px solid #9b2a62;

width: 2in;

padding: .1in;

margin: .1in auto;

}



.accent {

color: #9b2a62;

}



</style>

</head>



<body>

<div id="banner">

{{first_name}} - Verify Your Address

</div>



<!-- do not put text outside of the safe area -->

<div id="safe-area">

<div id="message">

<span class="accent">{{first_name}},</span>

<br><br>

This postcard serves as verification of your address.

<br><br>

<div id="code-banner">

Visit <span class="accent">https://www.acme.com/verify</span> and enter:

<div id="code">

{{verification_code}}

</div>

</div>

<br>

</div>

</div>

</body>



</html>

),

data: {

first_name: user.first_name,

verification_code: user.verification_code

},

metadata: {

user_id: user.id

}

)



user.update(verification_postcard_id: postcard['id'])

end

end



Sanity Check

Let's add a home page and some quick routing logic so we can see a preview of what we have so far. Running the command below, we'll have a empty controller and view generated for us.

$ rails generate controller home index



We're going to mount Sidekiq's web interface at /sidekiq and add some authentication logic. If a user is authenticated, they'll be able to see the home page. If not, they'll be directed to the registration form.

/config/routes.rb

require 'sidekiq/web'



Rails.application.routes.draw do

mount Sidekiq::Web => '/sidekiq'



devise_for :users, :controllers => { registrations: 'registrations' }



devise_scope :user do

authenticated :user do

root :to => 'home#index', as: :authenticated_root

end

unauthenticated :user do

root :to => 'devise/registrations#new', as: :unauthenticated_root

end

end



end



Now if we start up Rails and Sidekiq...

$ rails s

$ bundle exec sidekiq

We should get something like the image below. Signing up will now generate a user and trigger a postcard with a verification code.

Register the Webhook

Now we want to receive Webhooks that Lob sends us, so we'll create a controller and Sidekiq worker to manage this. If you are writing this application in a development environment, we highly recommend using ngrok to test your webhooks. This way, you don't have to continuously deploy your application to view any changes that you make.

$ rails generate sidekiq:worker Tracking

$ rails generate controller webhooks receive



Let's add 2 additional routes, one to accept webhooks, /lob/webhooks and the other /verify to build a form to verify the unique code. We'll set up the latter in a bit.

/config/routes.rb

post '/lob/webhooks' => 'webhooks#receive'

post '/verify' => 'home#verify'



Now let's setup Webhooks in Lob's dashboard. We'll want to input the URL (whether it's a deployed URL or one generated from ngrok) and select all of the postcard tracking events (postcard.in_transit, postcard.in_local_area, postcard.processed_for_delivery, postcard.re-routed, and postcard.returned_to_sender).

We'll read in the request body and parse the JSON returned by Lob. We'll call the Sidekiq Worker, TrackingWorker, to send the actual email.

/controllers/webhooks_controller.rb

class WebhooksController < ApplicationController

skip_before_action :verify_authenticity_token



def receive

raw = request.body.read

data = JSON.parse(raw)



last_tracking_event = data['body']['tracking_events'][-1]

postcard_id = data['body']['id']



TrackingWorker.perform_async(postcard_id, last_tracking_event['name'], last_tracking_event['location'], last_tracking_event['time'])



render status: 200, json: {}.to_json

end

end



In the worker, we perform a user lookup so that we to whom we are sending the email. Then we trigger a call to SendGrid with the information provided in the webhook.

/workers/tracking_worker.rb

require 'sendgrid-ruby'



class TrackingWorker

include Sidekiq::Worker



def perform(postcard_id, event_name, event_location, event_time)

sg = SendGrid::API.new(api_key: ENV['SENDGRID_API_KEY'])

user = User.where(verification_postcard_id: postcard_id).first



from = Email.new(email: 'test@acme.com')

subject = 'Lob Webhooks Demo - Notification'

to = Email.new(email: user.email)

email_content = "Your postcard is on it's way!



Tracking Event: #{event_name}

Location: #{event_location}

Time: #{event_time}"

content = Content.new(type: 'text/plain', value: email_content)

mail = Mail.new(from, subject, to, content)



sg.client.mail._('send').post(request_body: mail.to_json)

end

end



Now we just need to verify that this is the correct verification code! Let's go back to the HomeController we created earlier. We'll add some simple logic to determine if the verification code entered is the same as the one we generated for the user.

/controllers/home_controller.rb

class HomeController < ApplicationController

def index

end



def verify

if params['verification_code'].eql? current_user.verification_code

current_user.update(verified: true)

redirect_to '/', alert: "You are verified!"

else

redirect_to '/', alert: "That is not your verification code!"

end

end

end



And a really simple view.

/views/home/index.html.erb

<h1>Verify Your Address</h1>



<p>Verification Status: <%= current_user.verified %></p>



<hr>



<% if !current_user.verified? %>



<h1>Submit Your Verification Code</h1>



<%= form_tag("/verify", method: "post") do %>

<%= text_field_tag("verification_code", nil, required: true) %>

<%= submit_tag("Verify") %>

<% end %>



<% end %>



Wrapping Up

Now you have a fully functional address verification system using Lob's postcard and webhook functionality!

You can see the full source code for this example here.

You can check out Lob's documentation and webhooks guide for more information. If you have any additional questions, don't hesitate to leave a comment below or contact us directly. We're always happy to help!

‍