Sitecore Email Experience Manager (EXM), Importing Contacts and Custom Facets – Part 4

In Sitecore Email Experience Manager (EXM), Importing Contacts and Custom Facets – Part 1, I showed you how you can import contacts from a CSV file into a list in Sitecore. In Sitecore Email Experience Manager (EXM), Importing Contacts and Custom Facets – Part 2, I showed you how you can add to the list of out of the box supported fields when importing contacts into Sitecore. In Sitecore Email Experience Manager (EXM), Importing Contacts and Custom Facets – Part 3, I showed you how you can create your own custom facets and populate them for your contacts as you import them. If you haven’t already read them, head over and read them first.

In Sitecore Email Experience Manager (EXM), Importing Contacts and Custom Facets – Part 4, I’m now going to demonstrate how you can update the Experience Profile for a Contact by Add a new Tab into the User Interface and displaying your Custom Facet information.

Experience Profile Express Tab

Instead of developing all of this code from scratch, we’re going to use a package available in NuGet specifically written for this purpose. No point reinventing the wheel when someone else has already done all the hard work for you.

Experience Profile Express Tab is a package developed to streamline the creation of new tabs in the Experience Profile.

The first step we’ll take is to add the EPExpressTab to our project using NuGet. This will install two packages. EPExpressTab.Core and EXExpressTab. At the time of writing, version 2.0.2 was the latest released version.

To use EP Express Tab, we need to do the following:

  • Create a custom ViewModel that will represent the custom data we wish to display in the Experience Profile Tab
  • Create a custom EPExpressViewModel that will act as a Controller of sorts that will be called by EPExpressTab to populate our custom View Model and pass it to our view
  • Create a View to render the content for out custom tab in Experience Profile

First, let’s create our custom view model. In this example, this will contain just the new Employee fields the same as out custom Facet. Nothing special here. It’s just a standard class to hold our view model.

using System;

namespace Aceik.Feature.EXM.Models
{
    public class EmployeeViewModel
    {
        public string EmployeeId { get; set; }
        public string Department { get; set; }
        public DateTime? StartDate { get; set; }
        public string EmployeeType { get; set; }
    }
}

Next we need to create our EPExpressTab “Controller” class. This class is called by EPExpressTab and is used to generate the instance of our view model and pass it to the view.

using EPExpressTab.Data;
using EPExpressTab.Repositories;
using System;

namespace Aceik.Feature.EXM.Models
{
    public class EPCustomModel : EpExpressViewModel
    {
        public override string TabLabel => "Employee";
        public override string Heading => "Employee Details";

        public override object GetModel(Guid contactId)
        {
            Sitecore.XConnect.Contact model = EPRepository.GetContact(contactId, new string[] { EmployeeInfo.DefaultFacetKey });

            var employeeInfo = model.GetFacet<EmployeeInfo>();

            return new EmployeeViewModel
            {
                EmployeeId = employeeInfo?.EmployeeId,
                Department = employeeInfo?.Department,
                StartDate = employeeInfo?.StartDate,
                EmployeeType = employeeInfo?.EmployeeType
            };
        }

        public override string GetFullViewPath(object model)
        {
            return "/views/Aceik/Feature/EXM/Employee.cshtml";
        }
    }
}

The GetModel method is the action that is called to create the view model instance that will be passed to the view.

The GetFullViewPath method is as described. The method to get the path to the view.

The view itself it pretty straight forward with some inline styles defined, and the html tags etc to render the required custom data.

@model Aceik.Feature.EXM.Models.EmployeeViewModel
<style>
    .employee-border {
        padding-top: 10px !important;
        float: left;
        width: 100%;
    }

    .employee-text {
        display: block;
        float: left;
        width: 150px;
        color: #707070;
        clear: both;
    }

    .employee-value {
        clear: unset;
        padding-left: 95px;
        width: calc(100% - 150px);
        color: #121212;
    }
</style>
<div class="row">
    <div class="col-md-6">
        <span class="sc-text sc-text-value">Employee</span>
        <div class="sc-border employee-border">
            <span class="sc-text employee-text">Employee Id</span>
            <span class="sc-text employee-text employee-value">@Model.EmployeeId</span>
        </div>
        <div class="sc-border employee-border">
            <span class="sc-text employee-text">Department</span>
            <span class="sc-text employee-text employee-value">@Model.Department</span>
        </div>
        <div class="sc-border employee-border">
            <span class="sc-text employee-text">Start Date</span>
            <span class="sc-text employee-text employee-value">
                @if (Model.StartDate.HasValue)
                {
                    @Model.StartDate.Value.ToLocalTime().ToString("dd/MM/yyyy")
                }
            </span>
        </div>
        <div class="sc-border employee-border">
            <span class="sc-text employee-text">Employee Type</span>
            <span class="sc-text employee-text employee-value">@Model.EmployeeType</span>
        </div>
    </div>
</div>

Once this is deployed, along with the added EpExpressTab.config file that is added to the project with the inclusion of the NuGet package, you can now view the “Employee” tab in the Experience Profile that now shows the custom EmployeeInfo Facet data.

So you can examine the solution for yourself, please see below a link to the zip file containing the full Visual Studio solution, CSV files and a Sitecore package for the Import Map configuration items.

AceikEXM.zip

Sitecore Email Experience Manager (EXM), Importing Contacts and Custom Facets – Part 3

In Sitecore Email Experience Manager (EXM), Importing Contacts and Custom Facets – Part 1, I showed you how you can import contacts from a CSV file into a list in Sitecore. In Sitecore Email Experience Manager (EXM), Importing Contacts and Custom Facets – Part 2, I demonstrated how you can add to the list of out of the box supported fields when importing contacts into Sitecore. If you haven’t read these as yet, best to start with them first.

In Sitecore Email Experience Manager (EXM), Importing Contacts and Custom Facets – Part 3, I’m going to share with you how you can create your own custom facets and populate them for your contacts as you import them.

To do this, you are going to need to complete the following tasks:

  • Create a custom facet that will describe the additional data you wish to store for your contacts
  • Build a model for your custom facet that will be used by Xdb to store your custom facet data
  • Serialize your custom model and publish it so that Xdb will recognise your model
  • Create a custom Import mapper class that will be used by the Import process to read your custom fields from the import data and write it to your custom facet
  • Update the Import map configuration so that you can map the fields of your CSV file on import
  • Create the required Sitecore configuration settings for your facet and facet import mapper
  • Deploy the updated/new files to Sitecore and XConnect

Create a custom facet

We are going to store Employee information for each of our contacts. To support that, the first thing we are going to need to do is to create our own custom Facet.

Using Sitecore Helix principles and guidelines, I’ve created a new Feature project in Visual Studio that will contain all the custom code to support our custom EXM requirements. In this project, I’ve started with adding a new Facet class called EmployeeInfo:

using System;
using Sitecore.XConnect;

namespace Aceik.Feature.EXM.Models
{
    public class EmployeeInfo : Facet
    {
        public const string DefaultFacetKey = "EmployeeInfo";
        public string EmployeeId { get; set; }
        public string Department { get; set; }
        public DateTime? StartDate { get; set; }
        public string EmployeeType { get; set; }
    }
}

My EmployeeInfo facet, contains 4 properties that I want to be able to populate for my contacts:

  • EmployeeId
  • Department
  • StartDate
  • EmployeeType

Build a model for your custom Facet

The next thing I need to do is to create an XdbModel for my custom Facet. This is required to be deployed into our XConnect instance and will allow XConnect to know about our custom Facet and be able to store the Facet details for each contact.

using Sitecore.XConnect;
using Sitecore.XConnect.Schema;

namespace Aceik.Feature.EXM.Models
{
    public class EmployeeModel
    {
        public static XdbModel Model { get; } = EmployeeModel.BuildModel();

        private static XdbModel BuildModel()
        {
            XdbModelBuilder modelBuilder = new XdbModelBuilder("EmployeeModel", new XdbModelVersion(1, 0));

            modelBuilder.ReferenceModel(Sitecore.XConnect.Collection.Model.CollectionModel.Model);
            modelBuilder.DefineFacet<Contact, EmployeeInfo>(EmployeeInfo.DefaultFacetKey);

            return modelBuilder.BuildModel();
        }
    }
}

Note: Pay attention to the XdbModelBuilder parameters. This instructs the model with our custom Facet details.

We now need to run a build on our new project in Visual Studio so that the assembly can be generated with our classes.

Serlialize your custom model

XConnect requires a JSON representation of your XdbModel. We will now create a console application that can be used to generated the required JSON file.

First, Add a new project to your solution in Visual Studio, selecting to use the Console App template.

You will need to add a reference to your Feature project into the Console application as well as Nuget reference to the Sitecore.XConnect package.

Update the program.cs file to look like below:

using Sitecore.XConnect.Serialization;
using System.IO;

namespace Aceik.Feature.EXM.Serialize
{
    class Program
    {
        static void Main(string[] args)
        {
            // File name will be "Aceik.Feature.Mail.Models.EmployeeModel, 1.0.json
            var json = XdbModelWriter.Serialize(Models.EmployeeModel.Model);
            File.WriteAllText("Aceik.Feature.EXM.Models." + Models.EmployeeModel.Model.FullName + ".json", json);
        }
    }
}

Build and execute the console application.

As per the code comments, this will generate a file called “Aceik.Feature.Mail.Models.EmployeeModel, 1.0.json”. This will vary based on your custom model name and versioning you assigned in your XdbModel.

Note: If after deploying your model to XConnect, you need to update it, you will need to update the XdbModel version and deploy the updated JSON file before XConnect will recognise the new properties of your custom facet.

Create a custom import mapper

When a contact is imported via CSV, various ImportMapper classes are executed to process the contact and to populate the various Facets with the data from the CSV.

To populate our custom Facet, we need to create our own custom ImportMapper class to do this.

To process the contacts employee fields, I created my custom import mapper class called EmployeeInfoFacetMapper.

using System;
using System.Globalization;
using Sitecore.Diagnostics;
using Sitecore.ListManagement.Import;
using Sitecore.ListManagement.XConnect.Web.Import;
using Sitecore.XConnect;
using Aceik.Feature.EXM.Models;

namespace Aceik.Feature.EXM.Import
{
    public class EmployeeInfoFacetMapper : IFacetMapper
    {
        public EmployeeInfoFacetMapper() : this(EmployeeInfo.DefaultFacetKey)
        {
        }

        public EmployeeInfoFacetMapper(string facetName)
        {
            Assert.ArgumentNotNull(facetName, nameof(facetName));
            this.FacetName = facetName;
        }

        public string FacetName { get; }

        public MappingResult Map(
          string facetKey,
          Facet source,
          ContactMappingInfo mappings,
          string[] data)
        {
            if (facetKey != this.FacetName)
                return new NoMatch(facetKey);

            var facet = source as EmployeeInfo ?? new EmployeeInfo();

            // EmployeeInfo Properties
            facet.EmployeeId = SetTextField(FacetName, mappings, data, "EmployeeId");
            facet.Department = SetTextField(FacetName, mappings, data, "Department");
            facet.StartDate = SetDateTimeField(FacetName, mappings, data, "StartDate", "dd/MM/yyyy");
            facet.EmployeeType = SetTextField(FacetName, mappings, data, "EmployeeType");

            return new FacetMapped(facetKey, facet);
        }

        private string SetTextField(string facetName, ContactMappingInfo mappings, string[] data, string fieldName) => mappings.GetValue($"{facetName}_{fieldName}", data);

        private DateTime? SetDateTimeField(string facetName, ContactMappingInfo mappings, string[] data, string fieldName, string dateFormat)
        {
            DateTime? fieldValue = null;
            var fieldText = mappings.GetValue($"{facetName}_{fieldName}", data);
            DateTime fieldDate;

            if (DateTime.TryParseExact(fieldText, dateFormat, new CultureInfo("en-AU"), DateTimeStyles.None, out fieldDate))
                fieldValue = fieldDate.ToUniversalTime();

            return fieldValue;
        }
    }
}

This class is instantiated for each contact. First, it verifies that the data being passed to it is for the EmployeeInfo facet. Once that is confirmed, it populates the EmployeeInfo facet properties from the CSV data that is passed into it.

As you can see, I’ve used a couple of private methods to extract and set the string and DateTime values passed in.

Notice that when extracting the values from the mappings data passed in, it uses a pattern to extract the data for the correct field: “{facetName}_{fieldName}”. This pattern matches the Import mappings that we will setup in the next step.

Import Mapping Fields

As per Part 2, we need to configure the custom Import Mapping fields. Once again, switch to the Core database in Sitecore and navigate to this path: “/sitecore/client/Applications/List Manager/Dialogs/ImportWizardDialog/PageSettings/TabControl Parameters/Map/ImportModel”.

Select one of the existing mapping fields and duplicate it giving it a name of “Employee Info – Employee Id”. Populate the FieldName and DataField fields as per below. Note that the DataField value is the value used in the Import Mapper classes to identify the field so these need to be carefully assigned to match your custom Import Mapper class.

Do the same 3 more times to create the custom import mapping fields for:

  • Employee Info – Department
  • Employee Info – Start Date
  • Employee Info – Employee Type

Create the Sitecore configuration

In your project, you will need to create configuration files for the following purposes:

  • Patch the ListManagement.Import.FacetsToMap setting so that it includes your custom Facet name
  • Add your custom FacetMapper to the list of Import Facet Mappers defined in Sitecore
  • Add your schema to the list of schemas defined for XConnect
  • Add your projects path to the Layer configuration so that your configuration files are recognized

In my EXM Helix project, I’ve added the following configuration files:

  • ListManagement.config
  • sc.Aceik.Feature.EXM.Models.EmployeeModel.xml
  • Layers.config
ListManagement.config
<configuration xmlns:patch="http://www.sitecore.net/xmlconfig/" xmlns:set="http://www.sitecore.net/xmlconfig/set/">
  <sitecore>
    <settings>
      <setting name="ListManagement.Import.FacetsToMap" set:value="Emails|Personal|Addresses|EmployeeInfo" />
    </settings>

    <import>
      <facetMapper type="Sitecore.ListManagement.XConnect.Web.Import.CompositeFacetMapperCollection, Sitecore.ListManagement.XConnect.Web">
        <param resolve="true" type="Sitecore.Abstractions.BaseLog, Sitecore.Kernel"/>
        <facetMappers hint="list:Add">
          <facetMapper type="Aceik.Feature.EXM.Import.EmployeeInfoFacetMapper, Aceik.Feature.EXM" />
        </facetMappers>
      </facetMapper>
    </import>

    <xconnect>
      <runtime type="Sitecore.XConnect.Client.Configuration.RuntimeModelConfiguration,Sitecore.XConnect.Client.Configuration">
        <schemas hint="list:AddModelConfiguration">
          <!-- value of 'name' property must be unique -->
          <schema name="employeemodel" type="Sitecore.XConnect.Client.Configuration.StaticModelConfiguration,Sitecore.XConnect.Client.Configuration" patch:after="schema[@name='collectionmodel']">
            <param desc="modeltype">Aceik.Feature.EXM.Models.EmployeeModel, Aceik.Feature.EXM</param>
          </schema>
        </schemas>
      </runtime>
    </xconnect>

  </sitecore>
</configuration>
sc.Aceik.Feature.EXM.Models.EmployeeModel.xml
<?xml version="1.0" encoding="utf-8"?>
<Settings>
  <Sitecore>
    <XConnect>
      <Services>
        <XConnect.Client.Configuration>
          <Options>
            <Models>
              <EmployeeModel>
                <TypeName>Aceik.Feature.EXM.Models.EmployeeModel, Aceik.Feature.EXM</TypeName>
                <PropertyName>Model</PropertyName>
              </EmployeeModel>
            </Models>
          </Options>
        </XConnect.Client.Configuration>
      </Services>
    </XConnect>
  </Sitecore>
</Settings>
Layers.config
<?xml version="1.0" encoding="utf-8"?>
<layers>
  <layer name="Sitecore" includeFolder="/App_Config/Sitecore/">
    <loadOrder>
      <add path="ContentSearch.Azure" type="Folder" />
      <add path="Reporting" type="Folder" />
      <add path="Marketing.Xdb.Sql.Common" type="Folder" />
      <add path="CMS.Core" type="Folder" />
      <add path="AntiCSRFModule" type="Folder" />
      <add path="Contact.Enrichment.Services.Client" type="Folder" />
      <add path="ContentSearch" type="Folder" />
      <add path="Buckets" type="Folder" />
      <add path="DeviceDetection.Client" type="Folder" />
      <add path="DetectionServices.Location" type="Folder" />
      <add path="ItemWebApi" type="Folder" />
      <add path="Owin.Authentication" type="Folder" />
      <add path="Owin.Authentication.IdentityServer" type="Folder" />
      <add path="TransientFaultHandling" type="Folder" />
      <add path="Messaging" type="Folder" />
      <add path="Processing.Tasks.Messaging.Xmgmt" type="Folder" />
      <add path="Update" type="Folder" />
      <add path="XConnect.Client.Configuration" type="Folder" />
      <add path="Marketing.Xdb.MarketingAutomation.Operations" type="Folder" />
      <add path="Marketing.Xdb.MarketingAutomation.Reporting" type="Folder" />
      <add path="Marketing.Xdb.ReferenceData.Core" type="Folder" />
      <add path="Marketing.Xdb.ReferenceData.Client" type="Folder" />
      <add path="Marketing.Operations.xMgmt" type="Folder" />
      <add path="Marketing.Segmentation.xMgmt" type="Folder" />
      <add path="Marketing.Xdb.MarketingAutomation.Locators" type="Folder" />
      <add path="Marketing.Xdb.ReferenceData.Service" type="Folder" />
      <add path="Marketing.Xdb.ReferenceData.SqlServer" type="Folder" />
      <add path="Marketing.Operations.Xdb.ReferenceData" type="Folder" />
      <add path="Marketing.xDB" type="Folder" />
      <add path="Mvc" type="Folder" />
      <add path="Services.Client" type="Folder" />
      <add path="ExperienceContentManagement.Administration" type="Folder" />
      <add path="Speak.Integration" type="Folder" />
      <add path="Marketing.Tracking" type="Folder" />
      <add path="Tracking.Web.MVC" type="Folder" />
      <add path="Tracking.Web.RobotDetection" type="Folder" />
      <add path="Marketing.Assets" type="Folder" />
      <add path="Marketing.Xdb.MarketingAutomation.Tracking" type="Folder" />
      <add path="SPEAK" type="Folder" />
      <add path="Speak.Applications" type="Folder" />
      <add path="LaunchPad" type="Folder" />
      <add path="Experience Editor" type="Folder" />
      <add path="ContentTagging" type="Folder" />
      <add path="ListManagement" type="Folder" />
      <add path="Marketing.Client" type="Folder" />
      <add path="MVC.ExperienceEditor" type="Folder" />
      <add path="MVC.DeviceSimulator" type="Folder" />
      <add path="Personalization" type="Folder" />
      <add path="ContentTesting" type="Folder" />
      <add path="ExperienceProfile" type="Folder" />
      <add path="ExperienceExplorer" type="Folder" />
      <add path="SPEAK.Components" type="Folder" />
      <add path="ExperienceAnalytics" type="Folder" />
      <add path="CampaignCreator" type="Folder" />
      <add path="ExperienceForms" type="Folder" />
      <add path="ExperienceForms" type="Folder" />
      <add path="FederatedExperienceManager" type="Folder" />
      <add path="Marketing.Automation.Client" type="Folder" />
      <add path="Marketing.Automation.ActivityDescriptors.Client" type="Folder" />
      <add path="EmailExperience" type="Folder" />
      <add path="PathAnalyzer" type="Folder" />
      <add path="UpdateCenter" type="Folder" />
    </loadOrder>
  </layer>
  <layer name="Modules" includeFolder="/App_Config/Modules/" />
  <layer name="Custom" includeFolder="/App_Config/Include/">
    <loadOrder>
      <add path="Foundation" type="Folder" />
      <add path="Feature" type="Folder" />
      <add path="Project" type="Folder" />
    </loadOrder>
  </layer>

  <layer name="Aceik" includeFolder="/App_Config/Aceik/">
    <loadOrder>
      <add path="Foundation" type="Folder" />
      <add path="Feature" type="Folder" />
      <add path="Project" type="Folder" />
    </loadOrder>
  </layer>

  <layer name="Environment" includeFolder="/App_Config/Environment/" />
</layers>

Deploy to Sitecore and XConnect

Deploy the EXM helix project to Sitecore using your usual method. In my case, I used the publish option in Visual Studio and deployed the files to the website folder for my Sitecore instance.

To deploy the files to XConnect, this was not so simple. I manually deployed the following files to these locations in my XConnect instance:

  • sc.Aceik.Feature.EXM.Models.EmployeeModel.xml => \App_Data\jobs\continuous\AutomationEngine\App_Data\Config\sitecore
  • Aceik.Feature.EXM.dll => \App_Data\jobs\continuous\AutomationEngine
  • Aceik.Feature.EXM.Models.EmployeeModel, 1.0.json => \App_Data\Models

After deploying the files to XConnect, you will need to go and restart the XConnect services:

  • Marketing Automation Service
  • Processing Engine Service
  • Index Worker

Test the Import

Now that you have deployed the code and configuration changes to both Sitecore and XConnect, applied the Import Mapper configuration changes, you can now import your “Employees” from a CSV file. I have amended the CSV used in the Part 2 adding in the additional Employee specific columns:

email, firstname, middlename, lastname, gender, jobtitle, address1, address2, city, postcode, state, country,Employee ID,Department,Start Date,Employee Type
alberte@gmail.com,Albert,Basil,Einstein,Male,Scientist,Level 12,100 New York Lane, New York,25438, NY, US,FT0195,Science,23/01/1869,Fulltime
blaise@gmail.com,Blaise,Patricia,Pascal,Male,Mathematician,125 The Pond,,Paris,7321AE,PA, FR,CA0125,Mathematics,08/10/1915,Casual
cherschel@yahoo.com,Caroline,Jenny,Herschel,Female,Astronomer,34 The Strait,,Hanover,123BCF,Lower Saxony, DE,PT4567,Astronomy,05/05/1979,Permament Part-time
dorothyhodgkin@live.com,Dorothy,Anne,Hodgkin,Female,Chemist,87 Downing Street,,Westminister,SW1A,London,UK,FT0099,Science,13/08/1940,Fulltime
edmond145@facebook.com,Edmond,William,Halley,Male,Astronomer,114 ChittingHam Way,,Greenwich,SW1A,Kent,UK,CA0087,Astronomy,01/10/1985,Casual

I then imported these “Employees” using the same process as previously, with the only difference being that I now mapped the additional Employee fields.

Import from CSV file
Imported Employees

As you can see the Employees imported in the same manner as previously. Now, when I open the details of one of the Employees, I see no difference to before.

Contact Details

In the last and final part of this series, I’ll show you how to update the Experience Profile with a new Tab that you can use to display your custom Facet details. Click here for Part 4.

Sitecore Email Experience Manager (EXM), Importing Contacts and Custom Facets – Part 2

In Sitecore Email Experience Manager (EXM), Importing Contacts and Custom Facets – Part 1, I showed you how you can import contacts from a CSV file into a list in Sitecore EXM. Head over to Part 1 if you haven’t read that one as yet.

The properties of a contact that we are able to populate out-of-the-box are configured to the following fields:

  • Email
  • First name
  • Last name

Sitecore can be configured to support importing additional properties. In this article, I will show you how to update the configuration to support importing additional contact properties such as:

  • Middle name
  • Gender
  • Job Title
  • Address

Configure the Import Model

We need to first update the configuration of the import model. The import model is used to define the list of mapping fields that are displayed in the Contact Import dialog.

Start by launching the Sitecore Desktop from the Sitecore Launchpad. From there click on the master database in the lower right hand corner and select “core”. This switches the context to the core database. You can now launch the Content Editor by clicking on the Sitecore start button and selecting “Content Editor”.

Launch Sitecore Desktop
Switch to the Core database
Launch the Content Editor

In the Content Editor, navigate to the following path:

/sitecore/client/Applications/List Manager/Dialogs/ImportWizardDialog/PageSettings/TabControl Parameters/Map/ImportModel

Here you will see the list of configured field mappings. Will we now add to the list of field mappings by using the predefined available list of additional fields. Rich-Click on the “Import Model” node and using the Insert submenu, choose to add the following additional fields:

  • Personal – Middle name
  • Personal – Gender
  • Personal – Job title
  • Preferred Address – Address Line 1
  • Preferred Address – Address Line 2
  • Preferred Address – City
  • Preferred Address – Postal code
  • Preferred Address – State or Province
  • Preferred Address – Country code

The ordering of the fields is not mandatory but it’s worth putting into a logical order as this will be the order they are displayed in, in the contact import dialog.

Updated Import Model configuration

Now, go through the same process to create a new list and import the contacts from a CSV file. This time, when you reach the step of mapping the fields, you will notice there is additional fields to map. They are the new fields we just added to the Import Model is the previous step. Complete the mapping and the import as you did in the previous article.

Updated list of mapping fields
Updated list of mapping fields
Updated list of mapping fields

Now, when you open one of the imported contacts in Experience Profile, you will see the additional properties that have been imported:

Newly populated fields from the updated Import Model

In the Sitecore Email Experience Manager (EXM), Importing Contacts and Custom Facets – Part 3, I will show you how to add custom properties to a Contact and have those properties populated via the Contact Import process.

Sitecore Email Experience Manager (EXM), Importing Contacts and Custom Facets – Part 1

Are you a Sitecore developer looking to import contacts into Sitecore? Do you need to store properties for your contacts that are not supported out of the box by Sitecore?

In this multi-part series of posts, I will show you how you can import your contacts from a text file. I’ll show you how you can update the out of the box configuration to include importing other standard properties for your contacts. I’ll also show you how you can add your own custom properties for your contacts. And lastly, I’ll show you how you can update the Experience Profile UI so that your custom properties can be displayed for your contacts.

Contacts and Lists

Sitecore EXM supports the concept of both Contacts and Lists.

A contact itself is pretty self-explanatory and contains all the properties for the contact. Here are some of examples of the properties stored for a contact:

  • Email addresses
  • First, middle and last names
  • Gender
  • Birthday
  • Addresses
  • Job title

A list is simply a collection of contacts. A contact can be a member or a subscriber to multiple lists. Lists can be either static (a contact has been added to the list) or a list can be dynamic. Dynamic lists are populated based on a set of rules that uses the contact properties to determine if they should be a member of the list.

Importing Contacts

Out-of-the-box, Sitecore supports importing contacts from a CSV file. Your list of contacts to be imported need to have a minimum of the following fields:

  • Email address
  • First name
  • Last name

Sample CSV file

email, firstname, lastname
alberte@gmail.com,Albert,Einstein
blaise@gmail.com,Blaise,Pascal
cherschel@yahoo.com,Caroline,Herschel
dorothyhodgkin@live.com,Dorothy,Hodgkin
edmond145@facebook.com,Edmond,Halley

To import the contacts, go to the Sitecore Launchpad and click List Manager.

Once you are in the List Manager, follow these steps to import your contact list:

  • Click on the “Create” button
  • Select “Create list from file”
  • Click on the “Browse for a CSV file” button and select your csv file containing your contacts. Note: Make sure your file is named with a .csv extension
  • Enter a name for your list
  • Click on the “Upload file” button
Create a new list
Create the new list from a CSV file
Give your new list a name and upload the CSV file

Once the file has been uploaded, the process will prompt you to choose the mappings between the predefined Contact properties and the columns in your CSV file. If your CSV file contains columns you would like to use for the contact identifier and/or the identifier source, you can optionally check those and then be able to select the column mappings for those Contact properties.

Click “Next” to being the import process.

Nominate the field mappings

Once the import process has been completed, you will be shown a summary of what has been imported. When you click on the finish button, you will then be taken to your list that you have just imported. Here you can see the contacts that have been added to your new list.

Import Summary
Newly created list

You can also view the contact details by navigating back to the Sitecore Launchpad and launching the Experience Profile. There you can see the entire list of contacts. You can click into any of the contacts to see the details of the contact.

Experience Profile showing all your contacts
Contact details

There are additional properties that are shown in the experience profile that we can also populate via the CSV import process. To do that, we will need to customise the list of available properties that the importer allows to be mapped to.

In Sitecore Email Experience Manager (EXM), Importing Contacts and Custom Facets – Part 2, I will show you how you can customise that list of fields and import additional standard properties for each contact.