diff --git a/Gemfile.lock b/Gemfile.lock index 4315467..b52f080 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ PATH remote: . specs: - effective_mailchimp (0.13.0) + effective_mailchimp (0.13.2) MailchimpMarketing effective_bootstrap effective_datatables (>= 4.0.0) @@ -391,7 +391,6 @@ DEPENDENCIES effective_test_bot haml-rails pry-byebug - psych sqlite3 wicked diff --git a/app/models/effective/mailchimp_api.rb b/app/models/effective/mailchimp_api.rb index 8476ba1..e128fec 100644 --- a/app/models/effective/mailchimp_api.rb +++ b/app/models/effective/mailchimp_api.rb @@ -3,6 +3,7 @@ # https://mailchimp.com/developer/marketing/api/ require 'MailchimpMarketing' +require 'digest' module Effective class MailchimpApi @@ -75,14 +76,14 @@ def list(id) def categories(list_id) Rails.logger.info "[effective_mailchimp] Index Interest Categories" if debug? - response = client.lists.get_list_interest_categories(list_id.try(:mailchimp_id) || list_id) + response = client.lists.get_list_interest_categories(list_id.try(:mailchimp_id) || list_id, count: 1000) Array(response['categories']) - [nil, '', {}] end def interests(list_id, category_id) Rails.logger.info "[effective_mailchimp] Index Interest Category Interests" if debug? - response = client.lists.list_interest_category_interests(list_id, category_id) + response = client.lists.list_interest_category_interests(list_id, category_id, count: 1000) Array(response['interests']) - [nil, '', {}] end @@ -92,7 +93,7 @@ def list_member(id, email) Rails.logger.info "[effective_mailchimp] Get List Member" if debug? begin - client.lists.get_list_member(id.try(:mailchimp_id) || id, email) + client.lists.get_list_member(id.try(:mailchimp_id) || id, subscriber_hash(email)) rescue MailchimpMarketing::ApiError => e {} end @@ -127,9 +128,9 @@ def list_member_add(member) Rails.logger.info "[effective_mailchimp] Add List Member" if debug? return if sandbox_mode? - # Actually add or update - payload = list_member_payload(member) - client.lists.set_list_member(member.mailchimp_list.mailchimp_id, member.email, payload) + # Actually add or update. set_list_member applies status_if_new when the contact is new + payload = list_member_payload(member).merge(status_if_new: list_member_status(member)) + client.lists.set_list_member(member.mailchimp_list.mailchimp_id, subscriber_hash(member.user.email), payload) end def list_member_update(member) @@ -139,7 +140,8 @@ def list_member_update(member) return if sandbox_mode? payload = list_member_payload(member) - client.lists.update_list_member(member.mailchimp_list.mailchimp_id, member.email, payload) + hash = member.mailchimp_id.presence || subscriber_hash(member.email) + client.lists.update_list_member(member.mailchimp_list.mailchimp_id, hash, payload) end def list_member_payload(member) @@ -150,11 +152,22 @@ def list_member_payload(member) payload = { email_address: member.user.email, - status: (member.subscribed ? 'subscribed' : 'unsubscribed'), + status: list_member_status(member), merge_fields: merge_fields.transform_values { |value| value || '' }, interests: member.interests_hash.presence }.compact end + # Mailchimp identifies a list member by the MD5 hash of their lowercase email address + def subscriber_hash(email) + raise('expected an email') unless email.to_s.include?('@') + + Digest::MD5.hexdigest(email.to_s.downcase.strip) + end + + def list_member_status(member) + member.subscribed ? 'subscribed' : 'unsubscribed' + end + end end diff --git a/test/models/mailchimp_api_test.rb b/test/models/mailchimp_api_test.rb new file mode 100644 index 0000000..3572bc8 --- /dev/null +++ b/test/models/mailchimp_api_test.rb @@ -0,0 +1,24 @@ +require 'test_helper' + +class MailchimpApiTest < ActiveSupport::TestCase + def api + @api ||= Effective::MailchimpApi.new(api_key: 'test-us1') + end + + test 'subscriber_hash is the md5 of the lowercase email' do + expected = Digest::MD5.hexdigest('brenda.barrera@quadreal.com') + + assert_equal expected, api.subscriber_hash('brenda.barrera@quadreal.com') + end + + test 'subscriber_hash lowercases and strips before hashing' do + expected = Digest::MD5.hexdigest('brenda.barrera@quadreal.com') + + assert_equal expected, api.subscriber_hash(' Brenda.Barrera@QuadReal.com ') + end + + test 'subscriber_hash raises without an email' do + assert_raises(RuntimeError) { api.subscriber_hash('not-an-email') } + end + +end