Skip to content

Madmimi Email Integration

Eli Courtwright edited this page Jun 13, 2014 · 10 revisions

Create from the discussion around issue #296

Current status

Draft only, do not code yet without signoff from Dom+Eli

User story

As an administrator, I want people to be automatically subscribed to our mailing list provider, Madmimi, when people click the checkbox for 'send me updates about EventName'

Requirements

  • Support multiple mailing list providers with a base class for mailing list providers
  • Support multiple mailing lists (i.e. main promo list, staff newsletter, etc)
  • Daemonized support

note: we should only write Madmimi support, but other people might want to drop in their own mailing list providers later.

note2: Dom: I think we should change the wording on the email checkbox to something like the following: I would like to subscribe to the newsletter. This implies that when a user checks the box they are getting subscribed, and when they leave it blank, no action is taken. More importantly, it implies that when they leave it blank it does NOT imply that uber will unsubscribe them. I'd prefer to let our mailing list provider deal with the unsubscription process, which is easy enough. On forms where attendees can edit/transfer their registrations, if the box was previously checked, we just don't display it. (Vicki: Perhaps to make it more user-friendly we can display the user's "unsubscribe" link at the bottom?)

Implementation thoughts:

New table/model called MailingList

Holds the following columns:

  • ident (string uniquely identifying this mailing list, see description below)
  • provider (string identifying the mailing list provider, like "MadMimi")

New table/model called MailingListSubscription

Holds the following columns:

  • Attendee ID (foreign key)
  • Mailing List ID (foreign key)

Previously there was mention of using an array type to store which mailing lists the person is subscribed to, which is almost always less good than a many-to-many relationship.

The idea is that we can put checker methods on the mailing list class that say for a given attendee whether they should be subscribed to the list (assuming they checked the checkbox, if they didn't then we assume they shouldn't be without even running the code). The idea is that we define in our code a method for each mailing list which defines whether someone should be subscribed to it, BUT we only run that checker for mailing lists which actually appear in the code. So we can write code that looks like this:

class MailingList(MagModel):
    ident    = CharField(max_length=50)
    provider = CharField(max_length=50)

    @staticmethod
    def general(attendee):
        return True  # anyone with the checkbox checked gets subscribed to the general list

    @staticmethod
    def volunteer(attendee):
        return attendee.staffing

    @staticmethod
    def department_heads(attendee):
        return attendee.is_dept_head

So then we can write code that looks vaguely like this:

mailing_lists = list(MailingList.objects.all())
attendees_to_check = ...
for attendee in attendees_to_check:
    for mailing_list in mailing_lists:
        if getattr(MailingList, mailing_list.ident)(attendee):
            # subscribe the attendee to that mailing list
            MailingListSubscription.objects.create(mailing_list=mailing_list, attendee=attendee)

Hopefully that makes sense. The idea is that different events could enable/disable subscriptions simply by having the correct rows in their tables. So there's code to define what people should go in the "volunteer" mailing list, but if there's not a row with the ident "volunteer" then no one will be subscribed to it. So MAGFest might have that list, but MAGStock might not.

Email list provider base class. Something like:

class EmailMailingListProvider:
  def subscribe(email_addr):
  def unsubscribe(email_addr):

And then we have our specific provider, MadMimi:

class MadMimi(EmailMailingListProvider):
  def subscribe(email_addr):
     ... actually do stuff ...
  def unsubscribe(email_addr):
     ... actually do stuff ...

Email Subscriber Daemon

This wakes up and compares the requested subscription state (i.e. attendee checked the checkbox) with our known state (i.e. database says we don't think they are currently subscribed).

If they requested to be subscribed and they aren't currently subscribed, we subscribe them and mark them as subscribed.

Bonus points if this daemon instead of subscribing people right here instead kicks off a bunch of queued actions in the database which can have some sanity checks on them (i.e. uber sends an email to ask for confirmation that we want to subscribe 10,000 test email addresses to our production mailing list service from our Vagrant install) (this is an entire different feature request)