A blog about Salesforce CRM Configuration and development

Friday, 21 September 2018

Integrate Salesforce using MailChimp webhook

Real-time record updates (Contact/Lead) based on MailChimp Unsubscribe, Subscribe, email change event.

MailChimp is a marketing automation platform, which provides a good REST API (MailChimp API 3.0) to communicate with other systems. MailChimp provides 'MailChimp for Salesforce' Appexchange app to integrate Salesforce to Mailchimp. Through this app, we can sync the Contact, Lead, Campaign from Salesforce to MailChimp and vise versa.

In this blog, I am going to demonstrate how can we listen to the change made on the MailChimp side and update the record in the Salesforce based on the change event.

MailChimp webhook allow us to collect the changed information based on the events (like Unsubscribe, Subscribe, Email Change, etc). To get the changed data we have to provide the URL for webhook, that URL going to be our Salesforce public site URL.

Below are the steps we need to follow to implement the functionality.

  • Create a Visulforce page that will listen to the changes from MailChimp.

  •  <apex:page controller="MCUnsubscribeCntrl" sidebar="false" showHeader="false" action="{! UpdateUnsubscribeMembers}" >  
       MailChimp Webhooks...

  • Create an Apex controller for the Visualforce page, this Apex class will get the changed data from MailChimp and update the record in the Salesforce.
    public without sharing class MCWebhookCntrl {
        public PageReference UpdateUnsubscribeMembers() {
            String sCode = fetchSecrateCode();
            System.debug('***Secrate Code: ### ' + sCode );
            String MCrequestCode = ApexPages.currentPage().getParameters().get('code');
            if (MCrequestCode == null || !sCode.equals(MCrequestCode )) {
                System.debug('Code is not valid: Please use valid code: ' + MCrequestCode );
                return null;
            String eventType= ApexPages.currentPage().getParameters().get('type');
            system.debug('Type of event: '+ eventType);
            if(eventType == 'upemail'){ //Email Changed event
                // Getting New Email
                String newEmail = ApexPages.currentPage().getParameters().get('data[new_email]');
                system.debug('Changed Email: ' +newEmail);
                // Getting Old Email
                String oldEmail = ApexPages.currentPage().getParameters().get('data[old_email]');
                system.debug('Old Email: ' +oldEmail );
                if (oldEmail == null || oldEmail.length() <= 0) {
                    System.debug('Email Id is null or blank');
                    return null;
                else {
                    System.debug('Email for Email Opt Out: ' + oldEmail );
                String safeEmail = String.escapeSingleQuotes(oldEmail);
                safeEmail.replace('*', '\\*');
                safeEmail.replace('?', '\\?');
                // SOSL search for records (Contact)
                List<List<SObject>> searchList = [FIND :oldEmail IN EMAIL FIELDS RETURNING Contact(id) limit 1]; 
                //Contact List  
                List<Contact> contacts = ((List<Contact>)searchList[0]);
                // Getting first record. you can iterate the list to get all records.
                List<Contact> conListForUpdate = [select id,Email,MailChimpActivity__c from Contact where id =: contacts[0].id ];
                for (Contact c : conListForUpdate ) {
                    if( c.MailChimpActivity__c ==null)
                         c.MailChimpActivity__c ='';
                    c.MailChimpActivity__c += 'Email chnaged from '+c.Email+ ' to '+newEmail+'  \r\n' ;
                    c.Email = newEmail;
                // Update Lists
                if (conListForUpdate.size() > 0) {
                    update conListForUpdate;
            // Unsubscribe/ Subscribe
            else if(eventType != 'profile'){
                String emailAddr = ApexPages.currentPage().getParameters().get('data[email]');
                if (emailAddr == null || emailAddr .length() <= 0) {
                    System.debug('Email Id is null or blank');
                    return null;
                else {
                    System.debug('Email for Email Opt Out: ' + emailAddr );
                String safeEmail = String.escapeSingleQuotes(emailAddr);
                safeEmail.replace('*', '\\*');
                safeEmail.replace('?', '\\?');
                // SOSL search for records (Contact/Lead)
                List<List<SObject>> searchList = [FIND :emailAddr IN EMAIL FIELDS RETURNING Contact(id), Lead(id) ]; 
                //Contact List  
                List<Contact> contacts = ((List<Contact>)searchList[0]);
                //Lead List
                List<Lead> leads = ((List<Lead>)searchList[1]);
                for (Contact c : contacts) {
                    if(eventType =='subscribe'){
                        c.HasOptedOutOfEmail = false;
                    }else if(eventType =='unsubscribe'){
                        c.HasOptedOutOfEmail = true;
                for (Lead l : leads) {
                    if(eventType =='subscribe'){
                        l.HasOptedOutOfEmail = false;
                    }else if(eventType =='unsubscribe'){
                        l.HasOptedOutOfEmail = true;
                // Update Lists
                if (contacts.size() > 0) {
                    update contacts;
                if (leads.size() > 0) {
                    update leads;
            return null;
        public String fetchSecrateCode() {
            try {
                StaticResource sr = [ SELECT Body, Name FROM StaticResource WHERE Name = 'WebHooksConfig' LIMIT 1 ];
                String xml = sr.Body.toString();
                System.debug('XML data: ' + xml);
                //XML parsing
                Dom.Document doc = new Dom.Document();
                Dom.XMLNode webhooks = doc.getRootElement();
                for (Dom.XMLNode node : webhooks.getChildElements()) {
                    String id = node.getAttribute('id', '');
                    if (id.equalsIgnoreCase('unsubscribe')) {
                        return node.getAttribute('code', '');
            catch (Exception e) {
                System.debug('*** Something went wrong: Error Occured! : ' + e.getMessage());
            return null;

  • Create an XML file. Upload this file in the static resource, static resource Name will be 'WebHooksConfig'.
  •  <webhooks>  
     <webhook id="unsubscribe" code="YOUR_SECRETE_CODE"/>  
  • Create the public site (force.com site) in Salesforce.
  • Go to quick search and type - Site -> click Sites -> Create a domain if it is not created. Otherwise, click on the 'New' button to create a new site. 
  • Click on 'Public Access Settings' and give the view/edit access Contact/Lead for fields. e.g- (HasOptedOutOfEmail, MailChimpActivity__c )
    Also, give the access for Apex class and Visualforce page.

  • Create Webhook for MailChimp List. Login into your MailChimp account and click on 'List' tab.

    • Enter Webhook URL:( https://YourOrgDomain-developer-              edition.ap5.force.com/webhooks/MCUnsubscribe?code=YOUR_SECRETE_CODE). Select the types of updates to be sent (Subscribe, Unsubscribe, email changed) and click on Save.


    Now, If you made an update on the MailChimp side like if you Unsubscribe the member from MailChimp then that record Contact/Lead (with the same email) inside salesforce will be updated with 'Email Opt Out' checkbox checked. If the user again Subscribe that member then 'Email Opt Out' field will be Unchecked.
    If the Email of member changed from MailChimp side then the Field on Contact (MailChimpActivity__c) will be updated.

    Hope this blog post helps many.


    1 comment:

    Trailhead Profile

    Follow by Email

    Total Pageviews


    Popular Posts

    Powered by Blogger.

    Contact form


    Email *

    Message *