Resolution Reminder App: Achieve Your Goals with Ember

Resolutions are hard. No matter what your goal is, there’s always a brighter, shinier… SQUIRREL!! Oh, sorry! Like I was saying, there’s always something to be distracted by.

Even if you can successfully eliminate the distractions, keeping yourself on task with a new habit can be difficult without accountability. On the other hand, everyone knows that sharing your resolution can leave you open to judgement and ridicule.

I have the perfect solution… a trustworthy source to reveal your resolutions to, who promises to not judge you. Worst case scenario, he’ll send you cute pictures to soften the blow when you’re reminded you have yet to accomplish everything you set out to do. This is our Resolution App Reminder.

Step 1: Find a Dog

No one ever feels judged by a dog! Ok, maybe we do… however I promise this dog will only send helpful, friendly messages to encourage you along your road to successful resolution keeping. If you haven’t heard about Ember before, get to know him (and me) here. Then circle back, secure in the knowledge that he’s not only a good protector of me, but an awesome secret-keeper as well.

resolution app reminder dog ember resolution reminder app

So here’s the deal. You put your resolution and a few other details in Ember’s secret hiding spot (aka fill out this Google Form) and he’ll send you a handful of emails throughout the year. They’ll range from encouraging to motivational to congratulatory, but they’ll always include a picture of him along his own 2017 resolution path. Easy peasy. What do you have to lose? Pick your best resolution (or two), and give them to Ember for safe keeping.

Behind the Curtain

For those of you curious about how we built all of this, It turned out to be a bit more convoluted than I anticipated (turns out there’s no “easy button”). But roll up your sleeves — I’ll walk you through it.

First of all, we (Ember, myself, and Ember’s Dad/my partner Jeremy) decided to go with Python as our language of choice. It’s Jeremy’s strong suit, and given that he was the primary brains behind the app functionality, that made the most sense. He also has experience using the SparkPost Python client library, which is a bonus for this project!

My first task was to set up a sending domain for Ember, since he doesn’t have the opposable thumbs to do it himself.

meme dog computer resolution reminder app

This part is easy for us humans:

  • If you don’t already have a SparkPost account, sign up for one.
  • Next, you’ll want to create an API key with “Transmissions Read/Write” permission
  • Lastly, you’ll need to set up and verify your sending domain, if you don’t already have one on hand

Next, I wrote out all of the steps that we needed the app to take. There are a lot of moving pieces in this process — personalizing data, remote logging into Google Sheets, verifying that emails were sent, etc. I’m a big proponent of knowing the big picture before you tackle a problem, especially one that seems complicated and involves technology that you aren’t particularly familiar with.

First Up: Integrating with Google

First things first, we had to set up a service account to access our spreadsheet for us in the background. Lucky for me (and you), my colleague Cole did the legwork on that for me already in a previous blogpost. Follow along with his directions on how to set up a service account and then come on back here. We promise to be patient.

Google Apps has an extensive API that lets you integrate with everything from Gmail to Calendar, and in our case, Forms and Sheets. There are a lot of moving pieces if you’re not already accustomed to working with this API. However, with the help of Anton Burnashev’s Github repo for interfacing with Google Sheets using Python, we got up and running quickly with the basics.

Once we knew the scope of what we could do, it was time to start applying it to our use case. First up: organizing the data.

Just for You

We set up three separate tabs in the Google Sheet that holds the data from the resolution form you filled out above (you did fill out the form, right?). The first tab is “resolutions” and (unsurprisingly) contains the details for each user who signed up.

The second tab, “messages”, organizes our resolution topics and allows us to personalize the emails. This way, Ember can address your needs directly. After all, not all of you are dedicated to working on your career or improving your love life in 2017. As such, for each resolution topic, Ember will include a picture of him engaging in a related activity to show solidarity. We also wanted to include a phrase that pertained to the resolution topic that you committed to.

Substituting the text and photos is easy enough with SparkPost (you can see how I did it in the welcome email). However, figuring out which of the 30 total photos to programmatically use on each of the emails took a little more thought.

table phrases resolution reminder app


For each topic, we created a dictionary with the appropriate topic phrase and photo prefix details. Each of these topic dictionaries then lives within a container dictionary so that we can reference it later on.

{'Love': {'Phrase': 'Improving your love life', 'Photoprefix': 'love'},
 'Career': {'Phrase': 'Making changes to your career',
 'Photoprefix': 'career'},
 'Travel': {'Phrase': 'Traveling more', 'Photoprefix': 'travel'},
 'Giving': {'Phrase': 'Giving back', 'Photoprefix': 'giving'},
 'Relaxation': {'Phrase': 'Relaxing more', 'Photoprefix': 'relaxation'},
 'Self-Care': {'Phrase': 'Taking care of yourself better', 'Photoprefix': 'selfcare'}

In retrospect, this might have been more easily accomplished with a class, but we didn’t do that… so we created a convoluted web of nested dictionaries for your enjoyment.

meme yo dawg resolution reminder app

Scheduled Sends (and why we didn’t use them)

SparkPost has an amazing feature which allows you to schedule your emails to be sent up to 31 days in advance. ? Fantastic, isn’t it? The only problem we ran into is that with the exception of the first reminder email, we were looking to schedule things more than 31 days out. Sad trombone.

So, back to square one… time to build date functionality into the app itself. We were basically looking for something similar to a Drip Campaign or a Welcome Series. We wanted you, the user, to get an automated welcome email, as well as periodic emails reminding you that we’re still rooting for you. (Speaking of which, if you’re looking to set up a welcome series for your company, check out our code for a starting place. With a few more calls to the get_dates function, you could set up a fully functioning welcome series based on when your new users sign up.)

Back to our sending mechanism… Remember the third tab that we haven’t talked about yet? This is where we drew the parameters for which email templates get sent when, how we determine which picture to send, and how to mark an email as sent in the “resolutions” tab.

table information resolution reminder app


Most of these columns are fairly self-explanatory:

  • Start and End dates indicates the time period in which each email should be sent
  • TemplateID corresponds with the SparkPost template to send at that time
  • The subject column is just for visual reference and isn’t used programmatically. These are all defined in the templates
  • send_id is a little more complicated… we’ll dig into that in a moment

The app steps through the following code, starting by figuring out what the current time is. It then checks the date ranges in the “dates” tab to see which one we’re currently in. Lastly, it returns the template and send_id that correspond with the proper timeframe.

def get_date_specifics(service, now):
    dates = get_dates(service)
    for date in dates:
        start = decypher_date(date['start'])
        end = decypher_date(date['end'])
        if start <= now:
            if end > now:
                return date['templateID'], int(date['send_id'])
  "We haven't started yet!")

Verify, Verify, Verify

In my opinion, send_id  is where it gets fun. It has two functions:

  1. Determining which picture to send by appending the corresponding number (1-5) to the end of the photo prefix we mentioned earlier
  2. Logging emails as “sent” in the “resolutions” tab

The latter makes it easy for us to verify that you’re getting your emails from Ember on a regular basis. It also keeps us from re-triggering emails accidentally.

As the app steps through the “resolutions” tab, it first checks to see if the cell says Sent. If it doesn’t, it sends the appropriate email based on our calculations above.

if row['Sent'] != "Sent":'Sending to %s, with %s' % (row['Email'], templateID))

Then, if the email send is successful, it updates the sent flag for the appropriate column. It calculates which column to post in using the send_id number as well as the standard column offset of 8 that we established early on in the code.

success = response.get('total_accepted_recipients', 0)
   if success > 0:
update_sent_flag_for_row(resolution_sheet, row, send_id + STATUS_COL_OFFSET)"Success")

Sweet, verifiable success.

To ensure said success going forward, we deployed this on a small Amazon instance that runs the script every 5 minutes. You could set up something similar on Heroku, or even a spare Raspberry Pi. Basically… anything that runs Python and has a consistent internet connection.

Lessons Learned

The “Just make it do this thing” phrase is the bane of most developer’s existence, and when you find a developer who doesn’t run away screaming upon hearing these words, you should keep them close by your side and reward them greatly. (Thanks again, Jeremy!)

In addition, we could have used a database for organizing some of this data, but we opted to use Google Spreadsheets in the interest of KISS. Since we were already using Google Forms to gather the data and had already set up the Google Sheets API to talk to Google Sheets, it seemed easier to add the few extra fields that we needed into the same Google Doc instead of creating a separate database. Fewer moving parts makes it a little harder to code, but a lot easier to deploy.

Let’s Do This

So… what do you think? Are you with us? We’d love to have you join all three of us as we attempt to make 2017 our best year yet. Sign up here and keep Ember up to date on how you do throughout the year.

-Mary, Jeremy and Ember ?

p.s. Care to take a look at the Resolution Reminder App code? Feel free to check it out on Github.