09 June 2015

MailChimp Integration with Elixir

While working on a Backend as a Service entirely built on top of Elixir Lang, I often come across with challenging requirements for such project. In order to share some useful solutions, I am writing a serie of blog posts, in a simple, direct and pragmatic way.

The first requirement I had to meet was a Sign Up Service which, besides persisting user data, sends a confirmation link to user’s e-mail. Rather than implement the whole mailer system, I opted to rely on the MailChimp services. To do so, I have implemented a basic Elixir wrapper for version 3 of the MailChimp API . At the time of writing, that wrapper has a simple set of functionalities, such as Getting Account Details, Getting All Lists and Adding a Member to a List, but it is very easy to implement other integrations.

As expected in Elixir projects, adding a dependency is very simple. Here we are going to use version 0.0.3 of MailChimp API Wrapper:

def deps do
  [{:mailchimp, "~> 0.0.3"}]
end

We also need to update our applications list to include the mailchimp project:

def application do
  [applications: [:mailchimp]]
end

The last configuration step is to include your API key in config.exs file:

config :mailchimp,
  apikey: "your api-us10"

Now we are able to start interacting with MailChimp account, lists and subscriptions. Below is an example of a typical use case:

As a Client App I would like to subscribe each new user to a specific List in a MailChimp account using the user’s e-mail address supplied on signup process.

To meet this requirement one could implement a function as following:

def insert(user) do
  enc_pass = user.password |> Bcrypt.hashpwsalt
  member = Mailchimp.add_member("23321a5522", user.email)
  user = %UserModel{user | password: enc_pass, member_id: member[:id]}
  Mongo.insert([user], @collection)
end

Note at line 3 where I use MailChimp wrapper to subscribe a new user, passing the MailChimp List ID and a valid e-mail address. That function will return a representation of the subscribed member in MailChimp.

Then I have another use case:

As a Client App I would like to verify whether an user trying to authenticate has already confirmed its subscription by clicking on email link sent by MailChimp.

Along with the user authentication, I had to retrieve the user status from MailChimp:

def authenticate(%{"username" => user, "password" => pass, "client_id" => client_id}) do
  user = find(%{"username" => user, "_client" => client_id})
  |> List.first

  case user do
    nil ->
      {:error}
    _ ->
      case Bcrypt.checkpw(pass, user.password) do
        true ->
          member = Mailchimp.get_member("23321a5522", user.member_id)
          case member[:status] do
            "subscribed" ->
              {:ok, user}
            _ ->
              {:inative}
          end
        false ->
          {:error}
      end
  end
end

Retrieve a member of a MailChimp list is as easy as a pie using the API:

member = Mailchimp.get_member("23321a5522", user.member_id)

In this post I presented a basic integration using a wrapper that I have created to meet some requirements of a project I am working on. There is a lot of room for improvement, so I pretend to evolve such implementation as needed or requested by the community.