Blogroll: Postmark

I read blogs, as well as write one. The 'blogroll' on this site reproduces some posts from some of the people I enjoy reading. There are currently 5 posts from the blog 'Postmark.'

Disclaimer: Reproducing an article here need not necessarily imply agreement or endorsement!

Subscribe to Postmark feed
Updated: 38 min 29 sec ago

Making high quality HTML email templates easy for everyone: behind the scenes at

Tue, 08/05/2018 - 15:35

We're excited to bring you an interview with Lee Munroe about his experiences building and growing the popular email template site Enjoy!

Tell us a little bit about the history of How did the idea come about? Why did you decide to start working on it?

A couple of years ago I created a simple responsive email template which I open sourced and put on GitHub. When I shared it with the community it got some traction and I realized that while just a simple template, this solved a big pain for developers. Over the next couple of years I open sourced a few more templates as well as my (Grunt) workflow for creating them.

Simple responsive email template

Then I started writing about what I had learned. I published blog posts about sending email, building email and responsive email (which I later accumulated in one long post for Smashing Magazine). These posts received positive feedback and I started getting requests to talk about email development at conferences. I had the opportunity to speak at several developer conferences including O’Reilly Fluent Conference in San Francisco and Litmus Email Design Conference in Boston.

Smashing Magazine post on building and sending email

I got to this point where I had shared a bunch of knowledge and open sourced a bunch of code. Thanks to the feedback (and website traffic) I felt I had a good amount of validation to “productize” a pack of email templates that would solve 80% of use cases for startups and developers. I invested some time in getting the templates up to a quality standard and testing them across the major email clients then launched HTML Email.

HTML Email templates for startups and developers What has the response been like from the email community?

Fantastic. In 18 months we have over 800 customers. On launch day we were the most hunted website on ProductHunt. Honestly I wasn’t expecting it to be as successful as that. Earlier in the process I had plans to make video tutorials, write a book, offer some more advanced tooling etc. and in the end I decided just to ship what I had, the email templates. Turns out all that stuff, while it would be nice to still offer these at some point, they weren't necessarily needed for launch.

HTML Email on Product Hunt

I think having the shared knowledge out there in blog posts as well as free templates has worked well as a channel. A lot of our referrals come from these blog posts and GitHub. Many developers will read the articles, try the free templates, and have faith that buying the more “polished” pack of templates are worth it. If they’d rather not spend the money or don’t have a budget they can invest a bit of time in looking at the open source workflow and figuring out how to make the templates themselves.

What has the project taught you about email development? Anything surprising or particularly challenging that stands out?

Over the years I’ve learned that 99.99% of developers do not like dealing with email. Cross client support. Inlining CSS. Using tables. Not something a typical developer has desire to deal with.

Of course all companies, apps, services send emails. So at some point someone has to set them up. Usually that someone wants to get in and out as quickly as possible. Sure there are companies that see the full potential and ROI of email and invest in a team. But most teams, especially early on, have a long list of other priorities and for email they want a quick solution that works.

So they’re not going to set up their own email infrastructure. They’re going to use an easy to use plug and play API solution like Postmark. Similarly they don’t want to spend weeks trying to learn how each email client renders HTML, what works and what doesn’t work.

That’s where HTML Email comes in, 10 high quality email templates that will get you up and running very quickly. Most customers say they’ll have their email templates live in less that 24 hours. It saves their developers days or weeks of pain staking agony trying to get their emails working and tested across the major email clients.

What’s next for you? What are your plans for the site and the templates?

The templates are doing great. I follow up with every customer to make sure they’re able to get the templates up and running and to listen to their feedback. One thing I realized early on is the website lacked a way to retain users so I’ve tried a couple of things to address this.

We started writing more content aimed at developers, in particular email service provider integrations. As well as a super post about integrating with Postmark you’ll notice we now have how-to tutorials for several other ESPs.

ESP integration guides for email developers

I also created a CSS inliner tool. I was never really satisfied with the standard of inliners out there so I made one to better suit the needs of email developers. It inlines in real time, offers a desktop and mobile preview and has some export options. This has seen returning users grow as email developers use it daily for their inlining needs.

CSS inliner for emails

In the future I plan to build out more developer and design tooling for email. It’s a niche area with a great community that I think most developers and designers would rather not have to deal with. It feels good being able to provide tools and content that enable these makers to produce emails of high quality quickly with minimal effort.

Categories: Technology

Sending transactional emails via Firebase and Cloud Functions

Mon, 23/04/2018 - 11:00

In this tutorial, we’ll walk through how you can start sending transactional emails through Firebase utilizing Google Cloud Functions.

Quick intro to Firebase and Cloud Functions Firebase

Google Firebase offers a number of products that help speed up the development of both mobile and web applications. The cornerstone product is their real-time database which offers a No-SQL style JSON store. It’s pretty magical to work with. Combine it with their free authentication service, and you can build entire applications with just front-end code (HTML, CSS, JS).

Cloud Functions

Google Cloud Functions takes all of this a step further by providing a way to queue up code to run behind the scenes, completely removing the need for a backend server. Functions are written in Node so that you can import any existing node modules out of the box.

Code inside a Cloud Function just sits there until it’s triggered. You can trigger Cloud Functions a few different ways:

  • Realtime Database Triggers - by adding/editing/removing items from the DB
  • Firebase Authentication Triggers - by adding/removing users
  • Cloud Storage Triggers - by uploading/updating/deleting files & folders
  • HTTP Triggers - on GET, POST, PUT, DELETE, and OPTIONS HTTP calls

The code you write inside a Cloud Function has admin access to everything within your Firebase account. Based on a trigger you can do lots of things, like get/set data from the database, or update a file in cloud storage. With HTTP triggers, once the function runs, you can even return data to the browser client.

For this tutorial, we’ll set up a simple Firebase database via JavaScript and use the real-time database trigger to fire off a transactional email via Postmark.

File structure

Here’s a structural overview of how we’ll be organizing the code for this project.

- functions - db - users - onUpdate.f.js - public - admin - index.html - google-signin.png - index.html Setting up authentication

First, If you’ve not done so already, you’ll need to head into the authentication section within your Firebase project and activate Google as a sign-in provider:

Next, let’s write some code to log in via Google OAuth. We’ll place this file at the root of the public folder.


<html> <head> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta charset="utf-8"> <title>Postmark + Firebase Sample App</title> <style> body { font-family: sans-serif; text-align: center; } .conatiner { margin: 80px auto; width: 300px; } </style> </head> <body> <div class="container"> <h2>Sign Up/In with Google</h2> <a href="#" class="form--google-signin"><img src="/img/google-signin.png" /></a> </div> <!-- 1. Include jQuery --> <script src=""></script> <!-- 2. Initialize Firebase --> <script src=""></script> <script> // TODO: Replace with your project's customized code snippet var config = { apiKey: "<API_KEY>", authDomain: "<PROJECT_ID>", databaseURL: "https://<DATABASE_NAME>" }; firebase.initializeApp(config); </script> <!-- 3. Sample authentication code --> <script type="text/javascript"> (function($){ 'use strict'; // ---------------------------------------------------------- // VARIABLES // ---------------------------------------------------------- var auth = firebase.auth(); // ---------------------------------------------------------- // READY // ---------------------------------------------------------- $(window).load(function(){ // Kick off events initEvents(); }); // ---------------------------------------------------------- // EVENTS // ---------------------------------------------------------- function loginEvents() { // Log in or Sign up $('.form--google-signin').on('click', function() { authFirebaseInit(); return false; }); } // ---------------------------------------------------------- // AUTHENTICATION // ---------------------------------------------------------- function authFirebaseInit() { // Attempt to authenticate via Google var provider = new firebase.auth.GoogleAuthProvider(); // We'll use a popup, but you can also auth in a new tab auth.signInWithPopup(provider).then(function(result) { // Redirect to admin window.location = '/admin'; }).catch(function(error) { // TODO: Error handling code here console.log(error); }); } })(jQuery); </script> </body> </html>

A few notes about this code:

  1. I’ve included jQuery here to simplify things, but it’s by no means mandatory. 
  2. You’ll want to update the code in this section with the code that you received after setting up your Firebase project.
  3. The authFirebaseInit() function does the heavy lifting here. Upon success, it redirects the user to /admin. Failures are logged in the console. If this is for a real-world project, you could add some error handling within the error catch section.

In a browser, you should see:

Sign up/in with Google

Once you click the blue sign in button, you’ll be prompted with the Google OAuth login popup.

Admin section

Once you’ve logged in, you should be redirected to /admin:


<html> <head> <meta name="viewport" content="width=device-width, initial-scale=1"> <meta charset="utf-8"> <title>Postmark + Firebase Sample App</title> </head> <body> <!-- Include jQuery --> <script src=""></script> <!-- Initialize Firebase --> <script src=""></script> <script> // TODO: Replace with your project's customized code snippet var config = { apiKey: "<API_KEY>", authDomain: "<PROJECT_ID>", databaseURL: "https://<DATABASE_NAME>" }; firebase.initializeApp(config); </script> <!-- Quick example of real-time database code --> <script type="text/javascript"> (function($){ 'use strict'; // ---------------------------------------------------------- // VARS // ---------------------------------------------------------- var auth = firebase.auth(), fbdb = firebase.database(); // ---------------------------------------------------------- // READY // ---------------------------------------------------------- $(window).load(function(){ // Check for user, else redirect to marketing site init(); }); // ---------------------------------------------------------- // INIT // ---------------------------------------------------------- function init() { auth.onAuthStateChanged(function(user) { // 1. Check to make sure the user is logged in // If they're not, redirect them to the homepage if (user) { userInit(user); } else { // User is signed out. // Redirect to homepage window.location = '../'; } }, function(error) { console.log(error); }); } // ---------------------------------------------------------- // User // ---------------------------------------------------------- function userInit(user) { var userData; // Check for user fbdb.ref('/users/' + user.uid).once('value').then(function(snapshot) { // 2. Add new user to DB if they don't already exist if (snapshot.val() === null) { // This data is automatically pulled from Google when you auth userData = { displayName: user.displayName, email:, photoURL: user.photoURL }; // 3. Save user data fbdb.ref('users/' + user.uid).set(userData).then(function() { console.log('User data saved!'); }).catch(function(error) { console.log(error); }); } else { console.log('User details already added!'); } }).catch(function(error) { console.log(error); }); } })(jQuery); </script> </body> </html> Organizing Cloud Functions

Cloud functions are developed locally and deployed via the command line. There are a number of different ways that you can organize them. Here’s the approach I take—which I picked up from Tarik Huber:


'use strict'; /** EXPORT ALL FUNCTIONS * * Loads all `.f.js` files * Exports a cloud function matching the file name * Author: David King * Edited: Tarik Huber * Based on this thread: * */ const glob = require("glob"); const camelCase = require("camelcase"); const files = glob.sync('./**/*.f.js', { cwd: __dirname, ignore: './node_modules/**'}); for(let f=0,fl=files.length; f<fl; f++){ const file = files[f]; const functionName = camelCase(file.slice(0, -5).split('/').join('_')); // Strip off '.f.js' if (!process.env.FUNCTION_NAME || process.env.FUNCTION_NAME === functionName) { exports[functionName] = require(file); } }

Nothing needs to change in this file. Props to David King for coming up with this approach. It uses globbing to search the functions folder for files ending with .f.js and auto-includes them keeping everything nice and tidy.

Watching for database changes & sending a transactional email via Postmark

The last step is to write the code for the Cloud Function itself:


// 1. Deploys as dbUsersOnUpdate const functions = require('firebase-functions') const nodemailer = require('nodemailer') const postmarkTransport = require('nodemailer-postmark-transport') const admin = require('firebase-admin') // 2. Admin SDK can only be initialized once try {admin.initializeApp(functions.config().firebase)} catch(e) { console.log('dbCompaniesOnUpdate initializeApp failure') } // 3. Google Cloud environment variable used: // firebase functions:config:set postmark.key="API-KEY-HERE" const postmarkKey = functions.config().postmark.key const mailTransport = nodemailer.createTransport(postmarkTransport({ auth: { apiKey: postmarkKey } })) // 4. Watch for new users exports = module.exports = functions.database.ref('/users/{uid}').onCreate((event) => { const snapshot = const user = snapshot.val() // Use nodemailer to send email return sendEmail(user); }) function sendEmail(user, company) { // 5. Send welcome email to new users const mailOptions = { from: '"Dave" <>', to: '${}', subject: 'Welcome!', html: `<YOUR-WELCOME-MESSAGE-HERE>` } // 6. Process the sending of this email via nodemailer return mailTransport.sendMail(mailOptions) .then(() => console.log('dbCompaniesOnUpdate:Welcome confirmation email')) .catch((error) => console.error('There was an error while sending the email:', error)) }

A few notes about this code:

  1. This is the code that actually sends the email. We use the nodemailer node module in addition to the nodemailer-postmark-transport node module which extends nodemailer with a custom transport.
  2. I’ve wrapped the  admin.initializeApp() function in a try statement so that it only get’s instantiated once (else you might see errors in the cloud functions log).
  3. Always use environmental variables for sensitive data that is needed in Cloud Functions.
  4. We’re watching for any new users that are added to /users/{uid}.
  5. Whenever a new user is added, we send off an email.
  6. The nodemailer module does its thing. The console.log() function can be used anywhere within Cloud Functions to output data to the Firebase Cloud Functions event log.
Download the source code

You can download/fork the source from this quick tutorial from this GitHub repo.

Enjoy! &#x1f91f;

Categories: Technology

What is transactional email and how is it used?

Tue, 17/04/2018 - 21:56

Transactional email is a type of automated email between a sender and a recipient. It differs from promotional email in that transactional email is triggered by events, interactions, or preferences within a service or application rather than by a company’s marketing campaign. While transactional emails can help fulfill marketing needs by recovering abandoned carts or re-activating inactive users, these emails are primarily functional and provide an anticipated response to an (in)action or a request made by the recipient. Unlike promotional emails which are bulk distributions of the same marketing message to many recipients simultaneously, transactional emails are personalized and typically sent to individuals one at a time.

Receipts and confirmations

The most well-known types of all transactional emails are receipts and confirmations. These occur after a transaction has taken place, which is why these types of emails are called transactional in the first place. When customers receive an email containing information about a purchase they’ve made online, it's usually an order confirmation or a receipt. Things like e-books, PDFs, or any other downloadable goods are typically sent as part of an email receipt as well, as are product keys for software purchases. However, confirmation emails don’t necessarily have to be related to a monetary transaction. New account sign-ups and event RSVPs also trigger confirmation emails which verify for the user that their sign-up or registration was successful.

Explicit requests

These types of transactional emails contain information explicitly requested by users of an application or service. The requests are typically urgent, meaning users expect these emails to arrive immediately. One of the most common examples of an explicit request is a password reset. Because users cannot access their accounts without a password, a password reset request comes with an expectation of an immediate response. Another example of an explicit request is a verification code used in two-factor authorization, where users are required to enter a temporary password in addition to their primary password to gain access to their accounts. As with password resets, users expect verification codes to arrive without delay. Retrieval of lost product keys and any scenario where missing account-related information is preventing users from gaining access to or activating their accounts usually fall into this category as well.

Account-related alerts

Emails that aren’t explicitly requested by users but are triggered based on changes to their accounts are considered account-related alerts. Dunning emails, which remind customers of overdue invoices or failed payment attempts, are an example of account-related alerts. These types of transactional emails keep customers informed of billing issues and also help reduce churn. Without them, customers may not be aware there were problems with payment processing. Dunning emails give customers a gentle nudge to update their billing information if their accounts are at risk of being deactivated. Other examples of account-related alerts include changes to passwords or email addresses, log-in attempt notifications, trial expiration notices, or other account issues.

Behavioral triggers

Behavioral emails are some of the more marketing-focused of the various transactional email types because they can be used to increase customer loyalty. Based on their interaction with a service or application, users will receive emails after they have achieved milestones or met certain conditions. One example of behavioral emails is an onboarding email. After creating new accounts, users receive welcome emails to help them get familiar with an application. After a length of time, a second email can educate about features or check in to make sure they’re happy with the service. Then a third sometime later, and so on. Abandoned cart emails and reactivations are also examples of behavioral emails. When customers have filled their carts but haven't finished checking out, they can receive an automated email reminding them of the items they've left behind. Abandoned cart emails can be sent anywhere from a few hours to a day or two later, and they sometimes include special offers to encourage customers to complete their purchase. Reactivation emails serve a similar purpose. When users haven’t interacted with an application for a length of time, or when they’ve signed up for a service but never used their account, they can receive emails to encourage them to log in again or to complete the onboarding process.

Event-driven notifications

These types of emails are similar to mobile phone push notifications, but they happen via email instead. Event-driven notifications can be used to alert users of a wide-range of activities, including comment notifications, event reminders, and shipping updates. Unlike account-related alerts, event-driven notifications don’t typically include actions taken by the recipients themselves, but rather by other people as in the case of social networks, or by the service itself such as with reminders or status updates. Event-driven notifications can let users know when they have a new message or that they have a tag in a social media post. They can also alert users that a package has been shipped or delivered, or that they have a meeting to attend soon.

Summaries and digests

Instead of receiving individual emails for every notification, some users prefer an option to combine them into groups. Summary or digest emails typically include a log of all the events that have occurred during a specific time frame, such as account activity or comments, and are sent to users at specified intervals, whether daily, weekly, or monthly. Summaries and digests are useful options for users who don’t want to miss notifications about activities that are important to them but don’t want to clutter their inbox with individual emails for every occurrence. Also, digest emails aren't limited to activities that have occurred in the past. They can include summaries of events that are planned to happen in the future as well. An example of this would be a weekly summary of appointments scheduled for the following week.

Referrals and invitations

Many services provide a way for users to invite their friends or colleagues to create an account by sending referral and invitation emails. Instead of using their email application to send an invite, users can enter their friends’ email addresses into a form, and the service will send the invitation emails on their behalf. Referral emails work the same way, but the difference between referral emails and invitations is that referrals are usually incentivized with a benefit for the sender and sometimes the recipient as well. Examples of rewards include account credits and gift cards.

Support and feedback requests

Communication is essential to a positive customer experience. If a customer submits a support request but does not get a confirmation that it was received, it can be frustrating. Additionally, if a support team does not receive the request promptly, the response time can be delayed, which would not only frustrate the customer but the support team as well. Support-based transactional emails help both sides by aiding the communication process and notifying each party of status updates. As with support requests, feedback can also help keep the customer experience positive. Similar to how onboarding emails are triggered, feedback requests can also be set up to solicit reviews from customers sometime after they’ve made a purchase or signed up for an account. If poor feedback is received, businesses can contact customers and attempt to turn negative experiences into positive ones.

Whether it’s a small team with a mobile application or a robust e-commerce company with thousands of products, transactional email can greatly benefit any business and its customers as well. It can increase revenue and engagement through behavioral triggers, lessen the load placed on support teams by automating many requests that would otherwise require manual fulfillment, and it can build customer trust and loyalty through personalization and exceptional communication. While it involves discretion to not overload users, transactional email can ultimately help companies provide an excellent experience, which is not only great for its customers, but for its bottom line as well.

Categories: Technology

Take a sneak peek at the upcoming Postmark iOS app

Tue, 10/04/2018 - 13:00

Postmark for iOS is designed to be your investigative sidekick. It’s a tool to help you quickly debug and resolve email issues when you’re away from your computer.

We know from running our products (and talking to customers) that having a great set of tools for troubleshooting email issues is vital. Our web app does a fantastic job of providing these tools on the desktop, but we wanted to offer an experience optimized for mobile.

A full-featured troubleshooting tool

Focusing our attention on troubleshooting tools helped us develop a core set of features that will make resolving email issues on-the-go much easier.

Search messages

Before you can solve a problem, you first need to find it. The search feature makes it easy to track down an outbound or inbound message so you can start investigating.

Message Search in Postmark for iOS Message search Inspect a message

Access message details, HTML and plain text previews, and recipient events from within the app. You have complete visibility into exactly what happens to every email you send.

You also get access to inbound message data and can retry messages that failed to process or got caught by your server's inbound rules.

Full message content in Postmark for iOS Full message content & recipient events Investigate bounced emails

Find out why an email bounced and what you can do to solve the problem. If an email address is deactivated due to a hard bounce, you can reactivate it from within the app once you have resolved the issue.

Bounce details in Postmark for iOS Bounce details Monitor server stats

Keep an eye on your sending volume and identify any spikes in bounces or spam complaints.

Server stats in Postmark for iOS Server stats Manage multiple Postmark accounts

We know that many of our customers (especially our agency friends) manage multiple Postmark accounts for their clients. Postmark for iOS allows you to connect all your accounts and effortlessly switch between them as needed.

What’s more, all of your connected Postmark accounts will be automatically synced via iCloud so you can access them on whichever device you have with you.

Account switching in Postmark for iOS Account switching Stay secure

Having access to all your Postmark data in your pocket is super convenient, but how do you keep that data safe?

Secure the app using Touch ID or Face ID to ensure that only you can access your Postmark account.

TouchID auth in Postmark for iOS Secure the app with Touch/Face ID How do I get access?

The Postmark iOS app is currently in beta, and we expect to make it available as a free download on the App Store later this year.

The app currently requires access to your Account API Token and is therefore only available to Postmark users with admin or owner permissions.

If you’d like to test out the app, sign up for our beta program. We’d love to get your feedback.

Sign up to the beta program

Categories: Technology

Notify your customers about email delivery issues with Rebound

Thu, 05/04/2018 - 18:46

Today, we launched Rebound for Postmark. A nifty integration that lets your customers know about delivery issues straight from your web app!

Dealing with hard bounces can be a pain in the butt. An email sent to your customer hard bounces and they’re stuck waiting for it to show up in their inbox. It may not be your fault, but most customers won’t see it that way. To them, the email is just missing.

Hard bounces are inevitable. They can happen for a bunch of reasons, and you usually don't have any control over them. Building features that notify your customers about delivery issues is a step in the right direction but require a significant amount of design and development time. So, features like this often get put on the back burner. And, as a result, the burden gets shifted to your support team.

This is why we built Rebound. Rebound is an embeddable javascript snippet that prompts customers to update their email address if there was a hard bounce. This way your customers aren't left in the dark about delivery issues. We even provide a notification builder so you can customize the appearance and messaging without having to write a bunch of code.

Getting started with Rebound Step 1

Before you get started, make sure you have a Postmark account. If you don’t have one, you can sign up here.

Step 2

Head over to the Rebound page and click the big blue “Set up Rebound” button.

Step 3

If you’re already logged in, Postmark will ask if you want to integrate with your current account or if you want to change users.

Step 4

Next, you’ll authorize Rebound to access your Postmark account.

Step 5

Once you've authorized your account, you’ll need to choose which server to connect.

Step 6

Now here’s the fun part! From here you can edit the notification appearance and messaging. We've provided some default copy to get you started, but we suggest that you add a button so your customers can update their email address. Click the “See Rebound in Action button” to see how the notification will look.

Step 7

Once you’re happy with how everything looks, scroll down to the “Install Rebound” section. We've generated a custom javascript snippet based on your configuration. Copy the snippet and paste it near your web app's closing </body> tag.

Step 8

Replace user_email with your logged-in user’s email address. This is typically inserted using your server-side templating language.

You’re all set! If you have any questions or issues, send us an email at

A few things to remember
  • Rebound’s notification will only appear if the recipient’s email address was deactivated due to a hard bounce. As of now, spam complaints will not trigger the notification.
  • Our javascript API has a callback function so that you can do whatever you want with the bounce data. You can hook into this function from the settings object -window.ReboundSettings.complete(). Check out the API Docs for more details.
  • If the notification is dismissed, a cookie named is added to the user’s browser. This prevents the notification from showing up again for this email address. If for whatever reason the email address gets reactivated and then deactivated again due to a hard bounce, then the notification will not appear again until this cookie gets deleted. We’ll work on making this better.
  • Your public token in the javascript snippet is tied to the server you selected during the setup process. If you need to switch servers, you’ll need to generate a new public token by going through the setup process again.
Stay tuned for future improvements

We have big plans for improving Rebound like letting your customers reactivate their email address and allowing alternative messaging and actions around spam complaints.

We’d love to know what you think about Rebound. Email us at and let us know.

Categories: Technology
Additional Terms