Leveraging SendGrid’s Event API

This guest post is from H. Wade Minter at TeamSnap, a SendGrid customer.

TeamSnap is a web/mobile tool to help keep sports teams and social groups organized. With that mission, email deliverability is critical. Our users send a lot of email, most of it important team-related business We need to make sure that the email gets delivered, as well as watch out for bouncing addresses or spam complaints. We don’t want to get blamed when someone shows up at the wrong field because they didn’t get the email that their coach sent out. Keeping our deliverability numbers high is paramount, as well as making sure we’re only send email out to people who should be receiving it.

The Problem

When we ran our own email smtp server, the job of parsing logs looking for bounces was painful, as was trying to parse the varying different types of spam complaint information we’d get from feedback loops. It ended up being a mostly-manual process that didn’t get run very often. When we moved our email to SendGrid, we discovered the SendGrid Event API, and that’s where a tiny development effort up front led to big time savings and much-improved deliverability numbers.

The Solution

We leverage SendGrid’s event API to completely automate responses to bouncing email addresses and spam reports. By writing a couple of simple software tools, we’ve been able to have a full-circle response to those problematic emails, without any direct developer or support interaction. The process goes a little something like this:

Step 1: Set up the SendGrid Event API

In the Apps area of our SendGrid control panel, we enabled notification alerts for when emails are bounced, as well as when emails are marked as spam. For the Post Event Url, we set that to point to a simple web app on our own servers. Our web app just listens for the web pings, and takes action. Two clicks and a URL, and the SendGrid side of things is completely set up.

Step 2: Write a simple web app to respond to Event API pings

On our end, we needed to write a tool to listen for those events and take actions. Since we’re a Ruby shop, we wrote ours in Sinatra. There’s nothing magical about that, though – as long as your app listens and parses HTTP requests and can interact with your database, you can write it in whatever you want.

To capture the events from SendGrid, the data that we care about is sent as an HTTP POST, which Sinatra decodes for us automatically. Our app just grabs any POST to the URL and reacts to it. We then check to see if the event type is “bounce” or “spamreport”, and fire off a particular subroutine depending on what we’re dealing with. Finally, we return an HTTP status code of 200 to the SendGrid API to let them know that we’ve received the POST properly (if SendGrid doesn’t get a 200 back, it retries regularly. So be sure you send that back). Here is the entirety of the HTTP listener:

post '/' do
case params['event']
when "bounce":
process_bounce(params)
when "spamreport":
process_spam(params)
end
return 200
end

Step 3: Look at the data, respond accordingly.

In our app, we have a model for email addresses. Each email address (which belongs to a player, which belongs to a team) has a flag for whether or not it should receive emails. In the vast majority of cases, if that flag isn’t set, no email will go to that address.

In the case of a bounce, we pull the email address, reason, and timestamp values out of the SendGrid POST. We then look for all email addresses in our system that match the bouncing one, disable them from receiving emails, and email the managers on the offending player’s team saying “This player on your team isn’t going to be receiving email, because their address is bouncing.” We also include the actual bounce error data that we get from SendGrid so the manager can see what happened.

When we receive spam report, we follow a very similar pattern – find that address in our system, disable it, and alert the team managers that “This player on your team has reported some of your team mail as spam. Since we don’t want to annoy them, we’ve disabled their address from receiving team mails. If you talk to them and it turns out they do want to get mail again, you can turn it back on.” We don’t want annoyed players wrecking our deliverability rates because they’re getting unwanted emails through us.

Step 4: Close the loop

When SendGrid receives a bounce or a spam complaint, it puts the offending address on a list. Addresses on that list can’t get emailed, because SendGrid doesn’t want to annoy users or deliver to bad addresses either. However, once we disable the address in our system, we want players and managers to be able to turn that mail back on if they so desire. We have a small Ruby script that uses the “sendgrid_toolkit” gem to clear out the list of blocked addresses for spam and bounces every three hours. That way, if the problem is resolved on the user’s end, email will flow again.

The Results

We’ve had this setup in operation since early November. What has it given us? We now have a 99.8% deliverability rate on approximately 2.5 million emails per month, and a sender reputation of 99.5%. How much developer time has been spent on this system since it went into place? Nearly zero. And with the information that we get from the SendGrid Event API, most questions that managers have when they receive the courtesy “Hey, this address is disabled…” messages can be answered up front before they even worry about dealing with support.

By partnering with SendGrid for our email delivery, we not only get access to their easy-to-use platform and outstanding customer service, we’re able to leverage their API tools to save additional time and money, without our development staff having to maintain a large email monitoring infrastructure. Instead, writing 50 lines of Sinatra code back in November has kept us going worry-free.

With enthusiastic customers in 135 countries, and teams representing over 100 different sports and (non-sport groups), TeamSnap has quickly become one of the fastest-growing team and group management solutions on the planet. And we’re just getting started!