Mailchimp’s Subscriber Hash

I learned something today. In sitting down to finish up my mailchimp functions, I wanted to create a mailchimp_remove_teacher_from_list(listname) function and a mailchimp_blanket_unsubscibe_teacher() function. I thought that, after my previous success, it would go quickly.

I was wrong.

Over here, in the docs, there’s reference to how to delete list members, which is what I basically want to do:

client.lists.members.delete(list_id=”, subscriber_hash=”)

I knew what a list_id was, but wasn’t sure what the subscriber_hash was. After a bit of Googleing (I thought I’d have to ask mailchimp for the hash) I found this page and was able to piece it together:

In previous versions of the API, we exposed internal database IDs eid and leid for emails and list/email combinations. In API 3.0, we no longer use or expose either of these IDs. Instead, we identify your subscribers by the MD5 hash of the lowercase version of their email address so you can easily predict the API URL of a subscriber’s data.

For example, to get the MD5 hash of the email address Urist.McVankab@freddiesjokes.com, first convert the address to its lowercase version: urist.mcvankab@freddiesjokes.com. The MD5 hash of urist.mcvankab@freddiesjokes.com is 62eeb292278cc15f5817cb78f7790b08.

In short, the subscriber_hash argument is something you produce at your end and use to look a subscriber up. There’s something elegant about it — you have no business accessing the subscriber if you don’t know the email address, already — but I needed some time to get it done.

Here’s how I did it:

import hashlib # A standard library that does hashes

# The following is in .lower() case because mailchimp forms
# hashes from lowercase strings.
# The .encode() method tagged on the end encodes it as a byte literal
email = request.user.email.lower().encode(encoding='utf-8)

# This uses the hashlib library to make the hash. The .hexdigest()
# seems to be about equivalent to str() [forgive me internet!]
hash = hashlib.md5(email).hexdigest()

client.lists.members.delete(list_id=list_id, subscriber_hash=hash)

This is not a complete solution. It basically tags onto my last post. At some point, I want to compend everything I do into something more universally applicable. When I do, I have no plans to keep it secret.

Advertisements

Adding Mailchimp actions to a Django model

As I get ready to try a second time to attract users, I decided to use MailChimp mailing lists to keep in touch with these users, as well as setting up some ‘tutorial’ emails at regular intervals. (I’m imagining something like “You’ve been using dynamic-efl.com for a week now, did you know you can do this to get more out of it?”)

To do this, I’d have to have code in Django that automatically signed members up. That means that this is my first attempt to work with an API, even by way of a library.

I decided to go with the mailchimp3 library and installed it in my virtualenv according to the instructions and set up some variables in my settings.py file.

# Mailchimp stuff
# Authentication
MAILCHIMP_LOGIN = 'login'
MAILCHIMP_KEY = '===>SECRET<==='

# The lists
MAILCHIMP_LISTS = {'welcome': 'listID',
                   'germany': 'listID',
                   'beta-testers': 'listID'}<span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>

The idea here is that I’ll be able to iterate over the keys in the lists, if I ever need to check that the user is in all the lists (for example, removing a user should include removing him from all lists).

To that end, I added a function at the beginning of my models.py file. (This probably isn’t good form).

def mailchimp_get():
    """ Returns a logged-in mailchimp client """
    return MailChimp(settings.MAILCHIMP_LOGIN, settings.MAILCHIMP_KEY)<span 				data-mce-type="bookmark" 				id="mce_SELREST_start" 				data-mce-style="overflow:hidden;line-height:0" 				style="overflow:hidden;line-height:0" 			></span>

It seemed like the easiest way to only write the login once.

Finally, I had to create a few methods in the Model in question (in my case, this is my teacher model, as my users are called ‘Teachers’ in this bit.

def mailchimp_add_teacher_to_list(self, listname):
    """ Takes a listname, checks that the teacher is not a member of the list, then adds it. """
    client = mailchimp_get()
    listid = settings.MAILCHIMP_LISTS[listname]
    if not self.mailchimp_teacher_in_list(listname):
        data = {
            'email_address': self.user.email,
            'status': 'subscribed',
            'merge_fields': {
                'FNAME': self.user.first_name
            }
        }
        client.lists.members.create(listid, data)

def mailchimp_lists_get(self):
    """ TEMPORARY - Returns a list of all mailchimp lists """
    client = mailchimp_get()
    return client.lists.all(get_all=True, fields="lists.name,lists.id")

def mailchimp_teacher_in_list(self, listname):
    """ Returns a bool indicating if this teacher's email address is in the list """
    email = self.user.email
    client = mailchimp_get()
    results = client.lists.members.all(settings.MAILCHIMP_LISTS[listname], get_all=True, fields="members.email_address")
    members = results['members']
    addresses = []
    for m in members:
        addresses.append(m['email_address'])

    return email in addresses

I think the names should be pretty self-explanatory. The mailchimp_lists_get() method was just an experiment based on following the instructions in the documents.

Lastly, I created a view and a URL just to test these functions by printing to the console and looking at the (currently empty) lists in mailchimp.

Summary

It was my first time sitting down and thinking critically about what I wanted and how to do it and I have to say that mailchimp and the library basically made it painless. I have other project ideas that will require more API integration, and it’s made me hopeful.