List Manager: Creating a Contact List from an external source programmatically

Version

Sitecore 8 Update 2 (150223)

    EXM 3 rev 150223

Task

Create a list manager contact list programmatically from an external data source which can be used as a recipient list for an EXM email message.

Details

First we’ll create a recipient list.

The using statements needed:

using Sitecore.Analytics.Data;
using Sitecore.Analytics.DataAccess;
using Sitecore.Analytics.Model;
using Sitecore.Analytics.Model.Entities;
using Sitecore.Analytics.Tracking;
using Sitecore.Configuration;
using Sitecore.Data;
using Sitecore.ListManagement.ContentSearch;
using Sitecore.ListManagement.ContentSearch.Model;
using ContactData = Sitecore.ListManagement.ContentSearch.Model.ContactData;
Create the list and associate contacts with the list
var listManager = Sitecore.Configuration.Factory.CreateObject("contactListManager", false) as ContactListManager;
var list = new ContactList(ListName);
try {
     //Create list if necessary
     listManager.Create(list);
     var listId = list.Id; //is assigned after creation.
     listManager.AssociateContacts(list, GetContactDatas());
}
...

Get the contacts for the list

protected List<ContactData> GetContactDatas()
{
     List<ContactData> returnList = new List<ContactData>();

     // ... Read the external datasource into Identifier, FirstName,LastName,EmailAddress ...
     // ... Loop through each contact read
           // Add or update the contact
           ContactData contact = CreateContact(Identifier, FirstName,LastName,EmailAddress);
           if (contact != null) returnList.Add(contact);

     return returnList;
}

Create or update the contact to associate with the list

// Add contact if the Identifier is not found, otherwise, update the existing contact
protected ContactData CreateContact(string identifier, string firstName, string lastName, string emailAddress)
{
     if (String.IsNullOrEmpty(identifier)) return null;
     var contactRepo = Factory.CreateObject("contactRepository", true) as ContactRepository;
     LeaseOwner leaseOwner = new LeaseOwner(identifier, LeaseOwnerType.OutOfRequestWorker);

     Contact newContact = null;

     LockAttemptResult<Contact> result = contactRepo.TryLoadContact(identifier, leaseOwner, TimeSpan.FromMinutes(1.0));
     switch (result.Status)
     {
          case LockAttemptStatus.Success:
               // Existing Contact
               newContact = result.Object as Contact;

               // Email Facet
               var emailFacet = newContact.GetFacet&lt;IContactEmailAddresses&gt;(_facetEmails); //_facetEmails = "Emails";
               if (!string.IsNullOrEmpty(emailFacet.Preferred))
               {
                    IEmailAddress address = emailFacet.Entries[emailFacet.Preferred];
                    address.SmtpAddress = emailAddress;
                }
                emailFacet.Preferred = _facetEmailPreferred; //_facetEmailPreferred = "Preferred";
                break;
           case LockAttemptStatus.NotFound:
                // New Contact
                ID guid = Sitecore.Data.ID.NewID;
                newContact = contactRepo.CreateContact(guid);
                newContact.Identifiers.Identifier = identifier;

                // Email Facet
                var emailFacetNew = newContact.GetFacet&lt;IContactEmailAddresses&gt;(_facetEmails); //_facetEmails = "Emails";
                emailFacetNew.Entries.Create(_facetEmailPreferred).SmtpAddress = emailAddress;
                emailFacetNew.Preferred = _facetEmailPreferred;

                break;
            default:
                throw new NotImplementedException("Handling of collection database locking failures is not yet implemented.");
     }

     if (newContact != null)
     {
         // Create and Update same once we have the contact
         var personalInfoNew = newContact.GetFacet&lt;IContactPersonalInfo&gt;("Personal");
         personalInfoNew.FirstName = firstName;
         personalInfoNew.Surname = lastName;
     }
     newContact.ContactSaveMode = ContactSaveMode.AlwaysSave;
     try
     {
         contactRepo.SaveContact(newContact,new ContactSaveOptions(true, leaseOwner));
     }
     catch (Exception ExContactNotSaved)
     {
          //if (ExContactNotSaved Error is exists and not testing for existence)
          string message = ExContactNotSaved.Message.ToString();
     }

     return new ContactData()
     {
          Identifier = identifier
     };
}</pre>
<pre>

Here’s an example of an imported contact in Mongo Db with the Contact List associated as a Tag:

SitecoreContactInMongoDbWithContactListTag

The list in Sitecore List Manager:

ListManagerContactListImportFromODS

13 thoughts on “List Manager: Creating a Contact List from an external source programmatically

Add yours

  1. Hi there.
    Great post – I have iimplemented something similar – one question though, when returning back to sitecore and viewing the LIst Manager, the new list is “locked” and stalling at indexing contacts. If I unlock the list and then rebuild “sitecore_list_index” from the control panel/IndexManager I can then view the contacts on an unlocked list.

    Is there any readon why the list is left in a LOCKED state and why the contacts are NOT being indexed autmatically?

    1. I recall having issues with Locked lists. One of the reasons in my case was having more than one Sitecore instance using the same Mongo Db indexes (the standard install from Sitecore with many instances my developer pc will have that unless you change the database names (like adding the Sitecore instance name ahead of the name) in the ConnectionString.config for MongoDb indexes. Once I had instances all with their own Mongo Db indexes, my locking issues cleared up.

      Here’s something Sitecore had me try to find out if more than one process was accessing the index.
      The dump file indicates that some files of the ‘sitecore_list_index’ are used by more than one process which leads to IO Exception and can be related to the issue you reported.
      Please perform the following steps and let me know about the results:
      1. Check that Sitecore has enough rights to create/modify the files in the {dataFolder}/indexes/sitecore_list_index folder.
      2. Ensure that there is no other programs (e.g. antivirus) that may lock the file.
      • Use the Process Explorer tool to find out who locked the file (Ctrl + F -> .lock). 
      • Ensure that only one Sitecore instance points to the physical folder where the ‘sitecore_list_index’ index is stored.

  2. Hi and thanks for this valuable piece of code I was looking for last couple of days. I can understand implement the code but maybe I’m not getting it or you can help me telling, that why I am not able to find a property ‘Identifier’ in the Sitecore.ListManagement.ContactSearch.Model.ContactData object ?
    Maybe some reference is missing? I’m using Sitecore 8.1.

    Lot of thanks and regards,
    Haris

  3. Nice post, but I am facing one issue for the first time listManager.AssociateContacts(list,xxx) works fine and I can see contact added in my list but when I am sending second request contact is not added and no exception.

    After the above scenario, I have read the contact and added to returnList
    if (listManager.GetContacts(list).Count() > 0)
    {
    returnList.AddRange(listManager.GetContacts(list));
    }
    Then I deleted the old list and created new list with same name my list was showing 2 contacts. but I don’t want this approach.

    Can you please help me to figure it out.

    1. Hi Deepen i am having a very peculiar scenario. I wanted to show up all the contacts added to the list. But every time the new list is getting created
      It will b ea great help if you can share the code to restric the creation of duplicate List

  4. HI
    I have “The type or namespace name could not be found”
    for
    LockAttemptResult
    and
    ContactSaveOptions()

    Can You please help me

  5. I have an issue with locked list too and I have more than one Sitecore instance using the same MongoDB but I do not understand how exactly resolve this issue. Should I rename analytics database in MongoDB? What do I need to change in ConnectionString.config file?

  6. hello All, I’m having issue in adding the email to the contacts. The first name and the last name is getting added to the list. but the email is not getting added.

    Also, i need to ope the existing list in the listmanager instead of creating a new list

  7. It is really a great post but i am facing some issues with its implementation. I am not able to restrict the creation of the Cuatom List in the List Manager every time i add a new contact. Can anybody help me please with the actual code to stop the creation of multiple Contact list . The below code is the problem.
    //Create list if necessary
    listManager.Create(list);
    var listId = list.Id; //is assigned after creation.
    listManager.AssociateContacts(list, GetContactDatas());
    The List should be created only once if created shouldn’t recreate.

  8. Is there a way to add contacts to an existing Contact List ?? If not what is the correct code to restrict the creation of duplicate Contact List each time a new Contact is posted. Please help ..

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

Up ↑

%d bloggers like this: