Create an activity type

Version: 9.0

This topic describes how to create and configure a custom Marketing Automation activity type named SymposiumReminder. The SymposiumReminder is responsible for moving a contact along a “true” or “false” path depending on whether they have opted out of receiving marketing e-mails.

Important

Activity types must define a single default path or true/false paths. You cannot define additional custom paths.

Note

If you use custom facets in your activity type, you must deploy the model to the automation engine. 

The SymposiumReminder activity type also:

  • Uses an external service to determine a contact’s role based on their job title.

  • Uses an external service to send an e-mail to the contact’s preferred e-mail address. The ‘from’ e-mail address is configurable via the NoReplyAddress parameter.

Create a class that implements IActivity 

To implement a custom SymposiumReminder activity and two custom services:

  1. Create a class named SymposiumReminder that implements IActivity:

    RequestResponse
    using System;
    using Sitecore.XConnect.Collection.Model;
    using Sitecore.Xdb.MarketingAutomation.Core.Processing.Plan;
    using Sitecore.Framework.Conditions;
    using System.Collections.Generic;
    using Documentation.Examples.Services;
    using Sitecore.Xdb.MarketingAutomation.Core.Activity;
    
    namespace Documentation.Examples
    {
        public class SymposiumReminder : IActivity
        {
            // Parameters
            public string NoReplyAddress { get; set; }
    
            public IJobService JobService { get; set; }
    
            public IEmailService EmailService { get; set; }
    
            public IActivityServices Services { get; set; }
    
            // Custom service
    
            public SymposiumReminder(IJobService jobService, IEmailService emailService)
            {
                EmailService = emailService;
                JobService = jobService;
            }
    
            public ActivityResult Invoke(IContactProcessingContext context)
            {
                Condition.Requires(context.Contact).IsNotNull();
                string preferredMail = String.Empty;
    
                if (context.Contact.Emails() != null && !context.Contact.ConsentInformation().DoNotMarket)
                {
                    preferredMail = context.Contact.Emails().PreferredEmail.SmtpAddress;
    
                    string subject = "Join us at Symposium!";
    
                    // Change e-mail subject depending on job title
                    if (context.Contact.Personal() != null)
                    {
                        if (JobService.IsJobInCategory(context.Contact.Personal().JobTitle, JobService.DeveloperCategory))
                        {
                            subject = "Geek out with us at Symposium!";
                        }
                        else if (JobService.IsJobInCategory(context.Contact.Personal().JobTitle, JobService.ExecutiveCategory))
                        {
                            subject = "Magnify your marketing with Sitecore Experience Cloud";
                        }
                    }
    
                    EmailService.SendMail(preferredMail, NoReplyAddress, subject);
    
                    // Move to "true" path
                    return new SuccessMove("true");
                }
    
                // Move to "false" path
                return new SuccessMove("false");
            }
        }
    }
    
  2. Create the custom services that the SymposiumReminder activity type relies on - IJobService and IEmailService. You can skip this step if your activity type does not rely on custom services.

    RequestResponse
    using System.Collections.Generic;
    
    namespace Documentation.Examples.Services
    {
        public interface IEmailService
        {
            void SendMail(string to, string from, string subject);
        }
    
        public class EmailService : IEmailService
        {
            public void SendMail(string to, string from, string subject)
            {
                // E-mail sending logic here
            }
        }
    
        public interface IJobService
        {
            string DeveloperCategory { get; }
            string MarketerCategory { get; }
            string ExecutiveCategory { get; }
    
            bool IsJobInCategory(string job, string category);
        }
    
        public class JobService : IJobService
        {
            public string DeveloperCategory { get { return "developer"; } }
            public string MarketerCategory { get { return "marketer"; } }
            public string ExecutiveCategory { get { return "executive"; } }
    
            private List<string> DeveloperJobTitles { get; set; }
            private List<string> MarketerJobTitles { get; set; }
            private List<string> ExecutiveJobTitles { get; set; }
    
            public JobService()
            {
                DeveloperJobTitles = new List<string>()
                    {
                        "developer",
                        "software developer",
                        "software engineer"
                    };
    
                MarketerJobTitles = new List<string>()
                    {
                        "marketer",
                        "digital strategist",
                        "marketing manager"
                    };
    
                ExecutiveJobTitles = new List<string>()
                    {
                        "ceo",
                        "coo",
                        "cdo"
                    };
            }
    
            public bool IsJobInCategory(string job, string category)
            {
                if (category == DeveloperCategory)
                {
                    return DeveloperJobTitles.Contains(job.ToLowerInvariant());
                }
    
                if (category == MarketerCategory)
                {
                    return MarketerJobTitles.Contains(job.ToLowerInvariant());
                }
    
                if (category == ExecutiveCategory)
                {
                    return ExecutiveJobTitles.Contains(job.ToLowerInvariant());
                }
    
                return false;
            }
        }
    }
    

SymposiumReminder paths

The SymposiumReminder defines two paths:

  • true

  • false

Each path has a matching path item under the activity type’s descriptor in Sitecore. See also:

SymposiumReminder services

The SymposiumReminder relies on two custom services:

  • IJobService is responsible for matching a contact’s job title to entries in a list.

  • IEmailService is responsible for sending e-mails - for example, if your brand is not using the Email Experience Manager.

Both services are injected via the constructor, and must be part of the activity type’s configuration in the Automation Engine. See also:

SymposiumReminder parameters

The SymposiumReminder defines a single custom parameter:

  • NoReplyAddress

This parameter has a matching parameter item in the activity type’s descriptor, and is set by the Automation Plan Defintion Manager when an activity with that uses the SymposiumReminder type is added to a plan. See also:

SymposiumReminder results

The SymposiumReminder returns SuccessMove("true") or SuccessMove("false") depending on whether the contact has opted out of receiving marketing e-mails.

See also:

Create an activity descriptor in Sitecore

You must create an activity descriptor in Sitecore for each activity type. Activity descriptors are used by the Marketing Automation UI, and are accessed using the Activity Type Descriptor Locator API.

  1. Open the Content Editor and navigate to /sitecore/system/Settings/Analytics/Marketing Automation/Activity Types.

  2. Right-click on Activity Types item and Insert > Activity Type.

  3. Give the new activity type a name that corresponds to the activity type class, such as Symposium Reminder:

  4. Specify the Implementation Type (the value of this field should match the value of the implementationType parameter in the automation engine configuration):

  5. Right-click on the Parameters sub-item and insert  a parameter item named No Reply Address. In our case, the parameter will fall back to a default and is not required.

  6. Right-click on the Paths sub-item and insert two path items. Each path item must define the same Key that is used in the activity type:

Add an activity type to the Marketing Automation Engine

Activities must be registered in configuration in the Marketing Automation engine.

  1. Navigate to the following folder in the Automation Engine root: \App_Data\Config\sitecore\MarketingAutomation

    Tip

    In a local instance, the Automation Engine is at C:\path\to\xconnect\App_data\jobs\continuous\AutomationEngine

  2. Create a new XML file that extends sc.MarketingAutomation.ActivityTypes.xml and registers your custom activity:

    RequestResponse
    <Settings>
      <Sitecore>
        <XConnect>
            <Services>
                <MarketingAutomation.Activity.SymposiumReminder>
                    <Type>Sitecore.Xdb.MarketingAutomation.Locator.ActivityTypeRegistration, Sitecore.Xdb.MarketingAutomation</Type>
                    <LifeTime>Singleton</LifeTime>
                    <Options>
                        <Id>{A21EA3B7-6CE4-4C5D-AFE4-50F2D0ECE197}</Id>
                        <ImplementationType>Documentation.Examples.SymposiumReminder, Documentation.Examples</ImplementationType>
                    </Options>
                </MarketingAutomation.Activity.SymposiumReminder>
            </Services>
        </XConnect>
        </Sitecore>
    </Settings>
    
    Note

    The Id node is the ID of the activity descriptor item in Sitecore.

  3. Deploy the activity DLL (in this case, Documentation.Examples.dll) to the Marketing Automation Engine root.

Add activity type services to the Marketing Automation Engine

The SymposiumReminder activity relies on two external services. These services must be registered in the automation engine.

  1. Navigate to the following folder in the Automation Engine root: \App_Data\Config\sitecore\MarketingAutomation

    Tip

    In a local instance, the Automation Engine is located under C:\path\to\xconnect\App_data\jobs\continuous\AutomationEngine

  2. Create a new XML file that extends sc.MarketingAutomation.ActivityServices.xml and registers your custom services. If you are not using custom services, you can skip this step.

    RequestResponse
    <Settings>
    <!--
        Marketing Automation Activity Services configuration
    -->
    <Sitecore>
        <XConnect>
        <MarketingAutomation>
            <Engine>
            <Services>
                <Documentation.EmailService>
                    <Type>Documentation.Examples.IEmailService, Documentation.Examples</Type>
                    <As>Documentation.Examples.EmailService, Documentation.Examples</As>
                    <LifeTime>Singleton</LifeTime>
                </Documentation.EmailService>
                <Documentation.JobService>
                    <Type>Documentation.Examples.IJobService, Documentation.Examples</Type>
                    <As>Documentation.Examples.JobService, Documentation.Examples</As>
                    <LifeTime>Singleton</LifeTime>
                </Documentation.JobService>
            </Services>
            </Engine>
        </MarketingAutomation>
        </XConnect>
    </Sitecore>
    </Settings>
    
    Note

    Node names must be unique. For example, there can only be one Documentation.EmailService node. The node name is up to you - it does not need to be the full namespace of the service.

  3. Deploy the activity service DLL (in this case, Documentation.Examples.dll) to the Marketing Automation Engine root.

Ensure facets are loaded

The following facets must be available when the contact is evaluated within the activity. Patch facet keys into the IncludeFacetNames section of the C:\path\to\xconnect\App_data\jobs\continuous\AutomationEngine\App_Data\Config\sitecore\MarketingAutomation\sc.MarketingAutomation.ContactLoader.xml configuration file:

RequestResponse
<Settings>
<!--
    Marketing Automation contact loader configuration
-->
<Sitecore>
    <XConnect>
    <MarketingAutomation>
        <Engine>
        <Services>
            <!-- Include or exclude contact facets for the contact during loading -->
            <!--
            <MarketingAutomation.Loading.ContactFacetsConfigurator>
            <Options>
                <IncludeFacetNames>
                <Facet1>PersonalInformation</Facet1>
                <Facet2>EmailAddressList</Facet2>
                <Facet3>ConsentInformation</Facet3>
                </IncludeFacetNames>
            </Options>
            </MarketingAutomation.Loading.ContactFacetsConfigurator>
            -->
        </Services>
        </Engine>
    </MarketingAutomation>
    </XConnect>
</Sitecore>
</Settings>

Do you have some feedback for us?

If you have suggestions for improving this article,