Sending Transactional Email from Real-time apps: SendGrid
Transactional email (also known as triggered email, the sending of an email based on a user’s action) is a backbone of business and conversation on the web. It is fundamental in a variety of situations such as customer service, ridehailing trip-end receipts, e-commerce receipts, asynchronous notifications, list processing, conversation archiving, and even identity (via email address verification).
Providing a bridge between real-time activity and customer email is a big step in providing continuity of user experience and engagement. In this article, we dive into a simple example of how to send transactional email with the SendGrid Web API from a real-time AngularJS web application with a 30-line PubNub block and 80 lines of HTML and JavaScript.
Transactional Emails
What exactly are these email web services we speak of? SendGrid offers a number of services for sending, tracking and managing email. In this article, email refers to sending an individual email via the SendGrid REST API (as opposed to SMTP or mass email APIs). There are a few considerations when sending email, such as content encoding, format (HTML and/or plain text), attachments, and of course deliverability (we don’t want emails to bounce and hurt our sender reputation!).
As we prepare to explore our sample AngularJS web application with transactional email features, let’s check out the underlying SendGrid Web API.
SendGrid Email API
Sending and tracking email is a notoriously difficult area, and it requires substantial effort and engineering resources to maintain high deliverability in a dynamic sender reputation landscape, especially given the advanced functionality required to analyze deliverability, email open and conversion rates. In the meantime, the SendGrid Web API makes it easy to enable your applications with easy transactional email and analytics from a variety of languages and programming environments.
Since you’re reading this on the PubNub blog, we’ll presume you have a real-time application use case in mind, such as ride-hailing, messaging, IoT, etc. In the sections below, we’ll dive into the transactional email use case, saving other email analytics use cases for the future.
About the PubNub JavaScript SDK
PubNub plays together really well with JavaScript because the PubNub JavaScript SDK is extremely robust and has been battle-tested over the years across a huge number of mobile and backend installations. The SDK is currently on its 4th major release, which features a number of improvements such as isomorphic JavaScript, new network components, unified message/presence/status notifiers, and much more.
NOTE: for compatibility with the PubNub AngularJS SDK, our UI code will use the PubNub JavaScript v3 API syntax. We expect the AngularJS API to be v4-compatible soon. In the meantime, please stay alert when jumping between different versions of JS code!
Getting Started with SendGrid Web API
The next thing you’ll need to get started with SendGrid Web API is a SendGrid account to take advantage of the email APIs.
- Step 1: go to the SendGrid signup form.
- Step 2: create an account, making note of the username and password. (Alternatively, create a distinct user and password on the credentials page.)
- Step 3: use those credentials in the BLOCK code that follows.
All in all, not too shabby!
Setting up the BLOCK
With PubNub BLOCKS, it’s really easy to create code to run in the network. Here’s how to make it happen:
- Step 1: go to the application instance on the PubNub Admin Portal.
- Step 2: create a new BLOCK.
- Step 3: paste in the BLOCK code from the next section and update the credentials with the SendGrid credentials from the previous steps above.
- Step 4: Start the BLOCK, and test it using the “publish message” button and payload on the left-hand side of the screen.
That’s all it takes to create your serverless code running in the cloud!
Diving into the Code – the block
You’ll want to grab the 30 lines of BLOCK JavaScript and save them to a file, say, pubnub_sendgrid_block.js
. It’s available as a Gist on GitHub for your convenience.
First up, we create a method to handle incoming messages, and declare our dependencies on xhr and query (for HTTP requests), and console (for debugging).
// Be sure to place the following keys in MY SECRETS // sendGridApiUser - User name for the SendGrid account. // sendGridApiPassword - Password for the SendGrid account. // senderAddress - Email address for the email sender. const xhr = require('xhr'); const query = require('codec/query_string'); const vault = require('vault'); export default (request) => {
Next up, we declare variables for the API endpoint, username and password, as well as the “from” address for our transactional emails. Be sure to use the MY SECRETS button to fill in Vault key values to use SendGrid securely.
const apiUrl = 'https://api.sendgrid.com/api/mail.send.json'; let sendGridApiUser, sendGridApiPassword, senderAddress; return vault.get('sendGridApiUser').then((username) => { sendGridApiUser = username; return vault.get('sendGridApiPassword'); }).then((password) => { sendGridApiPassword = password; return vault.get('sendGridSenderAddress'); }).then((address) => { senderAddress = address;
Finally, we call the email send endpoint with the given message data, and catch any errors and log to the BLOCKS console. Pretty easy!
// create a HTTP GET request to the SendGrid API return xhr.fetch(apiUrl + '?' + query.stringify({ api_user: sendGridApiUser, // your sendgrid api username api_key: sendGridApiPassword, // your sendgrid api password from: senderAddress, // sender email address to: request.message.to, // recipient email address toname: request.message.toname, // recipient name subject: request.message.subject, // email subject text: request.message.text + // email text '
Input:
' + JSON.stringify(request.message, null, 2) })).then((res) => { console.log(res); return request.ok(); }).catch((e) => { console.error('SendGrid: ', e); return request.abort(); }); }).catch((e) => { console.error('PubNub Vault: ', e); return request.abort(); }); };
All in all, it doesn’t take a lot of code to add email capabilities to your application. We like that!
OK, that said, let’s move on to the UI!
Diving into the Code – the User Interface
You’ll want to grab these 80 lines of HTML & JavaScript and save them to a file, say, pubnub_sendgrid_ui.html
.
The first thing you should do after saving the code is to replace two values in the JavaScript:
- YOUR_PUB_KEY: with the PubNub publish key mentioned above.
- YOUR_SUB_KEY: with the PubNub subscribe key mentioned above.
If you don’t, the UI will not be able to communicate with anything and probably clutter your console log with entirely too many errors.
For your convenience, this code is also available as a Gist on GitHub, and a Codepen as well. Enjoy!
Dependencies
First up, we have the JavaScript code & CSS dependencies of our application.
<!doctype html> <html> <head> <script src="https://cdn.pubnub.com/pubnub-3.15.1.min.js"></script> <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script> <script src="https://cdn.pubnub.com/sdk/pubnub-angular/pubnub-angular-3.2.1.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script> <link rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.0.2/css/bootstrap.min.css" /> <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css" /> </head> <body>
For folks who have done front-end implementation with AngularJS before, these should be the usual suspects:
- PubNub JavaScript client: to connect to our data stream integration channel.
- AngularJS: were you expecting a niftier front-end framework?
- PubNub Angular JavaScript client: provides PubNub services in AngularJS quite nicely indeed.
- Underscore.js: we could avoid using Underscore.JS, but then our code would be less awesome.
In addition, we bring in 2 CSS features:
- Bootstrap: in this app, we use it just for vanilla UI presentation.
- Font-Awesome: we love Font Awesome because it lets us use truetype font characters instead of image-based icons. Pretty sweet!
Overall, we were pretty pleased that we could build a nifty UI with so few dependencies. And with that… on to the UI!
The User Interface
The UI is pretty straightforward – everything is inside a div
tag that is managed by a single controller that we’ll set up in the AngularJS code.
<div class="container" ng-app="PubNubAngularApp" ng-controller="MyEmailCtrl"> <pre> NOTE: make sure to update the PubNub keys below with your keys, and ensure that the email BLOCK is configured properly! </pre> <h3>MyEmail Email Sender</h3>
We provide a simple text input for a message to send to the PubNub channel as well as a button to perform the publish()
action.
<input ng-model="toSend" /> <input type="button" ng-click="publish()" value="Send!" />
Our UI consists of a simple list of messages. We iterate over the messages in the controller scope using a trusty ng-repeat
. Each message includes the text of the published messages, along with a nifty font-awesome envelope icon.
<ul> <li ng-repeat="message in messages track by $index"> <span class="fa fa-envelope"></span> <br /> to: {{message.toname}} <br /> subject: {{message.subject}} <br /> text: {{message.text}} </li> </ul> </div>
And that’s it – a functioning real-time UI in just a handful of code (thanks, AngularJS)!
The AngularJS Code
Now we’re ready to dive into the AngularJS code. It’s not a ton of JavaScript, so this should hopefully be pretty straightforward.
The first lines we encounter set up our application (with a necessary dependency on the PubNub AngularJS service) and a single controller (which we dub MyEmailCtrl
). Both of these values correspond to the ng-app
and ng-controller
attributes from the preceding UI code.
<script> angular.module('PubNubAngularApp', ["pubnub.angular.service"]) .controller('MyEmailCtrl', function($rootScope, $scope, $sce, Pubnub) {
Next up, we initialize a bunch of values. First is an array of message objects which starts out empty. After that, we set up the channel as the channel name where we will send and receive real-time structured data messages. NOTE: make sure this matches the channel specified by your BLOCK configuration!
$scope.messages = []; $scope.channel = 'email-sendgrid-channel';
We initialize the Pubnub
object with our PubNub publish and subscribe keys mentioned above, and set a scope variable to make sure the initialization only occurs once. NOTE: this uses the v3 API syntax.
if (!$rootScope.initialized) { Pubnub.init({ publish_key: 'YOUR_PUB_KEY', subscribe_key: 'YOUR_SUB_KEY', ssl:true }); $rootScope.initialized = true; }
The next thing we’ll need is a real-time message callback called msgCallback
; it takes care of all the real-time messages we need to handle from PubNub. In our case, we have only one scenario – an incoming message containing text of an email to send. The push()
operation should be in a $scope.$apply()
call so that AngularJS gets the idea that a change came in asynchronously.
var msgCallback = function(payload) { $scope.$apply(function() { $scope.messages.push(payload); }); };
The publish()
function takes the contents of the text input, publishes it as a structured data object to the PubNub channel, and resets the text box to empty. Alternatively, the “to email” and “to name” values could be provided by the BLOCK.
$scope.publish = function() { Pubnub.publish({ channel: $scope.channel, message: { to: "supportemail@supportdomain.com", toname:"support", subject:"support request", text:$scope.toSend } }); $scope.toSend = ""; };
In the main body of the controller, we subscribe()
to the message channel (using the JavaScript v3 API syntax) and bind the events to the callback function we just created.
Pubnub.subscribe({ channel: [$scope.channel], message: msgCallback });
We mustn’t forget close out the HTML tags accordingly.
}); </script> </body> </html>
Not too shabby for about eighty lines of HTML & JavaScript!
Conclusion
Thank you so much for joining us in the SendGrid Web API article of our real-time web application series! Hopefully it’s been a useful experience learning about email-enabled technologies. In future articles, we’ll dive deeper into more web service APIs and use cases for PubNub BLOCKS in real time web applications.
Stay tuned, and please reach out anytime if you feel especially inspired or need any help!