Video Assets for Mailchimp + Salesforce: Part 6 - Sync Campaign Member from Mailchimp

This page contains the assets for the video on Blu Tiger academy that walks you through how to create the apex classes and apex trigger to automate the creation of campaign members from the MC Subscriber Activity records. Copy and paste the code below into your org per the instructions in the video.

Apex Classes & Apex Trigger Code

Apex Class - MCSubscriberActivityTriggerHandler

public class MCSubscriberActivityTriggerHandler{

  public void afterInsert(List<MC4SF__MC_Subscriber_Activity__c> newRecords) {

    Map<String,String> CampaignMemberStatusMap = new Map<String,String>();
    Map<String,CampaignMember> cmMCSAMap = new Map<String,CampaignMember>();
    Map<String,Id> ldctSubscriberMap = new Map<String,Id>();
    List<Id> contactIdsList = new List<Id>();
    List<Id> leadIdsList = new List<Id>();
    List<Id> campaignIdsList = new List<Id>();
    List<String> contactSubscriberList = new List<String>();
    Set<String> newCampaignMembersSet = new Set<String>();
    Set<String> existingCampaignMembersSet = new Set<String>();
    List<CampaignMember> CampaignMembersToUpdate = new List<CampaignMember>();
    List<CampaignMember> CampaignMembersToInsert = new List<CampaignMember>();

    //set up all the member status mappings
    CampaignMemberStatusMap.Put('open','Opened');
    CampaignMemberStatusMap.Put('click','Clicked');
    CampaignMemberStatusMap.Put('bounce','Bounced');
    CampaignMemberStatusMap.Put('unsub','Unsubscribed');
    CampaignMemberStatusMap.Put('sent','Sent');

    //Make a list of the subscribers and campaigns
    List<MC4SF__MC_Subscriber_Activity__c> subscriberActivityList = [Select Id,MC4SF__MC_Subscriber__c,MC4SF__MC_Campaign__c,MC4SF__MC_Campaign__r.Campaign__c,MC4SF__Action__c FROM MC4SF__MC_Subscriber_Activity__c WHERE Id IN :newRecords];
    for(MC4SF__MC_Subscriber_Activity__c mcsa:subscriberActivityList){
      if(mcsa.MC4SF__MC_Subscriber__c != NULL)
          contactSubscriberList.Add(mcsa.MC4SF__MC_Subscriber__c);
      if(mcsa.MC4SF__MC_Campaign__r.Campaign__c != NULL)
          campaignIdsList.Add(mcsa.MC4SF__MC_Campaign__r.Campaign__c);
    }

    //Create a contact list and map to the subscriber
    for(Contact ct: [Select Id,MC4SF__MC_Subscriber__c FROM Contact WHERE MC4SF__MC_Subscriber__c IN :contactSubscriberList]){
      ldctSubscriberMap.Put(ct.MC4SF__MC_Subscriber__c,ct.Id);
      contactIdsList.Add(ct.Id);
    }
    
    //Create a lead list and map to the subscriber
    for(Lead ld: [Select Id,MC4SF__MC_Subscriber__c FROM Lead WHERE MC4SF__MC_Subscriber__c IN :contactSubscriberList]){
      ldctSubscriberMap.Put(ld.MC4SF__MC_Subscriber__c,ld.Id);
      leadIdsList.Add(ld.Id);
    }

    //Create a map of campaignId and lead/contact Id combination to the campaign member
    for(CampaignMember cm: [Select Id,ContactId,LeadId,CampaignId,Status FROM CampaignMember WHERE (ContactId IN :contactIdsList OR LeadId IN :leadIdsList) AND CampaignId IN :campaignIdsList]){
        if(cm.ContactId != NULL)
            cmMCSAMap.Put(cm.CampaignId + '_' + cm.ContactId, cm);
        else if(cm.LeadId != NULL)
            cmMCSAMap.Put(cm.CampaignId + '_' + cm.LeadId, cm);
    }
    
    //Loop through each subscriber activity
    for(MC4SF__MC_Subscriber_Activity__c mcsa:subscriberActivityList){

      //Get the associated contact/lead
      if(ldctSubscriberMap.ContainsKey(mcsa.MC4SF__MC_Subscriber__c) && ldctSubscriberMap.Get(mcsa.MC4SF__MC_Subscriber__c) != NULL && mcsa.MC4SF__MC_Campaign__c != NULL && mcsa.MC4SF__MC_Campaign__r.Campaign__c != NULL){
        Id contactOrLeadId = ldctSubscriberMap.Get(mcsa.MC4SF__MC_Subscriber__c);

        //Check if contact belongs to campaign already, if so, update it's status
        if(cmMCSAMap.ContainsKey(mcsa.MC4SF__MC_Campaign__r.Campaign__c + '_' + contactOrLeadId) && cmMCSAMap.get(mcsa.MC4SF__MC_Campaign__r.Campaign__c + '_' + contactOrLeadId) != NULL){
          CampaignMember existingCM = cmMCSAMap.get(mcsa.MC4SF__MC_Campaign__r.Campaign__c + '_' + contactOrLeadId);
          //Update the campaign member only if the status conditions are met and this particular record is not being updated in the same transaction
          if((!(existingCM.Status == 'Clicked' && (mcsa.MC4SF__Action__c=='sent' || mcsa.MC4SF__Action__c=='open'))) &&
            (!existingCampaignMembersSet.Contains(mcsa.MC4SF__MC_Campaign__r.Campaign__c + '_' + contactOrLeadId))
          ){
            if(CampaignMemberStatusMap.ContainsKey(mcsa.MC4SF__Action__c) && CampaignMemberStatusMap.Get(mcsa.MC4SF__Action__c) != NULL)
            existingCM.Status = CampaignMemberStatusMap.Get(mcsa.MC4SF__Action__c);
            CampaignMembersToUpdate.Add(existingCM);
            existingCampaignMembersSet.Add(mcsa.MC4SF__MC_Campaign__r.Campaign__c + '_' + contactOrLeadId);
          }
        }
        //Else, add it to the campaign
        else{
          //Check if the record is already part of the current transaction
          if(!newCampaignMembersSet.Contains(mcsa.MC4SF__MC_Campaign__r.Campaign__c + '_' + contactOrLeadId)){
            CampaignMember newCM = new CampaignMember(CampaignId=mcsa.MC4SF__MC_Campaign__r.Campaign__c);
            if(contactOrLeadId != NULL && String.ValueOf(contactOrLeadId).startsWith('00Q'))
                newCM.LeadId=contactOrLeadId;
            else
                newCM.ContactId=contactOrLeadId;
            if(CampaignMemberStatusMap.ContainsKey(mcsa.MC4SF__Action__c) && CampaignMemberStatusMap.Get(mcsa.MC4SF__Action__c) != NULL)
              newCM.Status=CampaignMemberStatusMap.Get(mcsa.MC4SF__Action__c);
            CampaignMembersToInsert.Add(newCM);
            newCampaignMembersSet.Add(mcsa.MC4SF__MC_Campaign__r.Campaign__c + '_' + contactOrLeadId);
          }
        }
      }
    }

    if(CampaignMembersToUpdate.size() > 0)
      update CampaignMembersToUpdate;

    if(CampaignMembersToInsert.size() > 0)
      insert CampaignMembersToInsert;
  }
}

Apex Class - MCSubscriberActivityTriggerHandler_Test

@isTest
public class MCSubscriberActivityTriggerHandler_Test{

  private static testMethod void testCreateSubscriberActivity() {

    Account newAccount = new Account(Name='Test Account');
    insert newAccount;
    
    Lead newLead = new Lead(FirstName='Test', LastName='Lead', Company='Test Company');
    insert newLead;

    Contact newContact = new Contact(FirstName='Test',LastName='Contact',AccountId=newAccount.Id);
    insert newContact;

    /*Campaign newCampaign = new Campaign(Name='Test Campaign');
    insert newCampaign;*/

    MC4SF__MC_Campaign__c mcCampaign = new MC4SF__MC_Campaign__c(MC4SF__MailChimp_ID__c='123');
    insert mcCampaign;

    MC4SF__MC_Campaign__c cp = [Select Id,Campaign__c FROM MC4SF__MC_Campaign__c WHERE Id=:mcCampaign.Id];

    
    CampaignMember newLeadCM = new CampaignMember(CampaignId=cp.Campaign__c,LeadId=newLead.Id,Status='Not Clicked');
    insert newLeadCM;

    MC4SF__MC_List__c mcAudience = new MC4SF__MC_List__c(MC4SF__MailChimp_ID__c='123');
    insert mcAudience;

    MC4SF__MC_Subscriber__c newLdSubscriber = new MC4SF__MC_Subscriber__c(MC4SF__Email2__c='test1@test.com',MC4SF__MC_List__c=mcAudience.Id);
   insert newLdSubscriber;
    MC4SF__MC_Subscriber__c newCtSubscriber = new MC4SF__MC_Subscriber__c(MC4SF__Email2__c='test2@test.com',MC4SF__MC_List__c=mcAudience.Id);
    insert newCtSubscriber;

    newLead.MC4SF__MC_Subscriber__c=newLdSubscriber.Id;
    update newLead;
    newContact.MC4SF__MC_Subscriber__c=newCtSubscriber.Id;
    update newContact;

    MC4SF__MC_Subscriber_Activity__c subLdActivity = new MC4SF__MC_Subscriber_Activity__c(MC4SF__MC_Subscriber__c=newLdSubscriber.Id,MC4SF__MC_Campaign__c=mcCampaign.Id,MC4SF__Action__c='click');
    insert subLdActivity;
    MC4SF__MC_Subscriber_Activity__c subCtActivity = new MC4SF__MC_Subscriber_Activity__c(MC4SF__MC_Subscriber__c=newCtSubscriber.Id,MC4SF__MC_Campaign__c=mcCampaign.Id,MC4SF__Action__c='click');
    insert subCtActivity;

  }

}

Apex Trigger - MCSubscriberActivityTrigger

trigger MCSubscriberActivityTrigger on MC4SF__MC_Subscriber_Activity__c (after insert) {

    MCSubscriberActivityTriggerHandler handler = new MCSubscriberActivityTriggerHandler();

    if(trigger.IsAfter && trigger.IsInsert)
        handler.afterInsert(Trigger.new);
}

Code to Run Mc Subscriber Activity Batch from Developer Console

Database.executeBatch(new MC4SF.ActivityBatch(), 50);

Congratulations! You have just completed creating automation to add campaign members to your Salesforce Campaigns. Now its time to test! If you must test this in production because you are already using Mailchimp, then you must deploy these components via a change set to production. If you are not familiar with how to do this, follow the steps below.

How to Deploy Your Components to Production

In the sandbox: Setup -> Outbound Change Sets -> New

DeploytoProd1

  • Enter Name - this can be whatever you want
DeploytoProd2

 

  • Click Add
DeploytoProd3

  • Select Component Type = Apex Trigger
  • Check the box for Apex Trigger = MCSubscriberActivityTrigger
  • Click Add to Change Set
DeploytoProd4

  • Select Component Type = Apex Classes
  • Check the boxes next to Apex Classes = MCSubscriberActivityTriggerHandler and MCSubscriberTriggerHandlerTest
  • Click Add to Change Set
DeploytoProd5

 

 

  • Click Upload
DeploytoProd6

  • Select Production -> Upload
DeploytoProd7

If you do not see Production in this screen, you will need to update the Deployment Settings in production for this sandbox. Follow these steps:

  • Go to Production -> Setup -> Deployment Settings -> Edit next to the sandbox you are deploying from.
UpdateDeploymentSettings1

  • Select Allow Inbound Changes -> Save
UpdateDeploymentSettings2

  • Go to Production -> Setup -> Inbound Change Sets -> Change Sets Awaiting Deployment -> Deploy
  • It may take anywhere from 30 seconds to 5 minutes to see your change set in production. You will receive an email when it is ready to deploy.
DeploytoProd8

  • Select Default -> Deploy
DeploytoProd9

  • The Deployment Details screen will run all of the apex tests and it will show two green circles when it has successfully deployed. You may have a different number in the second green circle, it just depends on the amount of code you have in your org.
DeploytoProd10

Great job! You have just successfully deployed your code to production and now you are ready to make sure everything is working in production. Yay!

 

How to Test the Automation

Since Mailchimp can only be connected to one environment, this testing is probably being done directly in production. Make sure to send the test email to contacts with your own email address.

Follow these steps to test the automation:

  • Create a campaign in MailChimp and send it to at least three recipients that have email addresses you have access to or get someone to help you test. Make sure they are test contacts.
  • Do different actions on the email for each recipient. Ex: #1 - should open the email, #2 - should open and click the email #3 - should not open the email
  • Go to MC Setup tab in Salesforce -> Campaigns -> Click Refresh MC Campaigns button. You should see your test campaign show up in the list.
Refresh MC Campaigns

  • Click the Gear icon in Salesforce on the top right hand side of the screen -> Developer Console
RunMCBatch

  • Select Debug -> Open Execute Anonymous Window
RunMCBatch1

  • Copy and paste the code below into the screen and click Execute. Thanks for this tip Spencer Widman!
  • This step prevents us from having to wait for the daily sync between Mailchimp and Salesforce. By running this line of code in the developer console, we are making the batch process start that triggers the MC Subscriber Activity records to sync from Mailchimp to Salesforce.
Database.executeBatch(new MC4SF.ActivityBatch(), 50);
RunMCBatch2

Give it a minute or two and check your campaign to see if the people were added to it.

If they weren't in the campaign, check the MC Subscriber Activity tab in Salesforce to see if any records came in after running the batch. If there are no records in the tab, confirm the batch ran successfully by checking the Apex Jobs.

You may run into errors if the Campaign__c field on the MC Campaign record is blank. Refer to this article Part 3: Mailchimp to Salesforce Integration - Campaign Sync on how to get this field updated automatically.

If everything worked, then we recommend running one more test with the real sync and then you should be ready to go.

 

Any comments, questions, concerns - let us know in the comments! We would love to hear from you!

Share This Story, Choose Your Platform!

About the Author

Cheryl Fernandes

Cheryl is a certified Salesforce Application Architect and is the Founder and Lead Salesforce Consultant at Blu Ninjas. She has been working with Salesforce for 12 years and has helped companies in financial services, insurance and beauty industries implement solutions on the platform. Flow is her favorite Salesforce declarative tool, it is a game changer for anyone who does not know how to code.

6 thoughts on “Video Assets for Mailchimp + Salesforce: Part 6 – Sync Campaign Member from Mailchimp”

  1. Hello, Thank you for the tutorial.
    I was trying to add the first Apex Class in when I received this error “Error: Compile Error: Missing ‘<' at 'newRecords' at line 3 column 32" Any ideas on how to fix it? Thanks again!

    1. Hi Cece,

      Thank you sooo much for reaching out to us on this. We had to add additional HTML to the apex code to make it render properly on the website so you can copy and paste it easily without formatting. A portion of line 3 was not rendering at all. This has been fixed, can you try it again for me. Thank you again for letting us know!!!

  2. Hi Cheryl,
    Thanks so much for creating this video series! Everything has gone smoothly for me up until this point, but now when I’m trying to save the first apex class I’m getting a compile error:

    “Error: Compile Error: Unexpected token ‘Map’. at line 5 column 5 ”

    Do you have any idea on why this might be happening/what I can do to fix it?
    Thanks,

    Vince

    1. Hi Vince,

      Thank you for reaching out, it looks like we still had some issues with the HTML rendering the apex code properly. I have updated it and tested in our sandbox, this version should work now. Can you try to save this version and let me know if you are successful? Thank you for making us aware of this issue!

  3. Hi, all your tutorials are great!!!
    I’m trying to follow your instructions and when I save the Apex Class I receive this error message: “Error: Compile Error: Unexpected token ‘Map’. at line 5 column 5”.
    Can you help me fix it? I’m using Nonprofit Success Pack in Lightning environment

    1. Hi Roberto,

      Thank you for letting us know about this! We had an issue with the HTML rendering the apex code and it was removing ‘<' and '>‘ from the code. This has been updated and it should work now. Can you try again for me and let me know if it works for you now.

Leave a Reply

Your email address will not be published. Required fields are marked *

Scroll to Top