﻿![]()

#### 

#### About

Welcome emails are great example of transactional emails (check my [article](https://www.brimit.com/blog/sitecore-send-7-campaigns) about different email campaigns in Sitecore Send). In this article I'll show how to configure Welcome email (with multi-language support) in OrderCloud [Headstart](https://github.com/ordercloud-api/headstart) solution using Sitecore Send.

#### Architecture

The architecture of the solution is shown on this diagram:

![Sitecore Send + OrderCloud: welcome email architecture](https://www.brimit.com/-/media/images/blog/sitecore-send-order-cloud-welcome-email/scheme.png)

*Explanation:* 

1. Webhook configuration on endpoint `PUT v1/me/register` - the endpoint, which is called to register a new user. See [documentation](https://ordercloud.io/api-reference/me-and-my-stuff/me/register) for more details.
2. In the `Headstart` solution we can implement webhook handler.
3. Inside webhook we will map payload from request to a new subscriber request in Sitecore Send.
4. Sitecore Send marketing automation will handle message send, as soon, as the subscriber appears in the list.

#### Webhook implementation

##### Controller

```
[Route("api/webhook")]
public class CustomerNotificationsController : CatalystController
{
    private readonly ICustomerNotificationsCommand customerNotificationsCommand;

    public CustomerNotificationsController(ICustomerNotificationsCommand customerNotificationsCommand)
    {
        this.customerNotificationsCommand = customerNotificationsCommand;
    }

    [HttpPost, Route("sendcustomerwelcomenotification")]
    [OrderCloudWebhookAuth]
    public async Task SendCustomerWelcomeNotification([FromBody] WebhookPayloads.Me.Register payload)
    {
        await customerNotificationsCommand.SendCustomerWelcomeNotification(payload?.Request?.Body);
    }
}
```

##### Command

In the command we map the data from payload to request body to add subscriber to the list.

```
public class CustomerNotificationsCommand : ICustomerNotificationsCommand
{
    private readonly IMailingListService _mailingListService;
    private readonly ILogger _logger;

    public CustomerNotificationsCommand(IMailingListService mailingListService,
        ILogger<CustomerNotificationsCommand> logger)
    {
        _mailingListService = mailingListService;
        _logger = logger;
    }

    public async Task SendCustomerWelcomeNotification(MeUser? meUser)
    {
        try
        {
            if (string.IsNullOrEmpty(meUser?.Email)
                || string.IsNullOrEmpty(meUser?.FirstName)
                || string.IsNullOrEmpty(meUser?.LastName))
            {
                _logger.LogWarning(
                    $"SendCustomerWelcomeNotification: Some of the request parameters is null or empty");
                return;
            }

            var customFields = BuildCustomFields(meUser);
            var tags = BuildTags(meUser);

            var listId = _mailingListService.DefaultListId;

            var succeed = await _mailingListService.AddToMailingList(listId,
                new AddingSubscribersRequest()
                {
                    Email = meUser.Email,
                    Name = $"{meUser.FirstName} {meUser.LastName}",
                    CustomFields = customFields,
                    Tags = tags,
                });
            _logger.LogInformation(
                $"SendCustomerWelcomeNotification: User {meUser.Username} ({meUser.Email}) subscribes to the list {listId}, succeess: {succeed}");
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "SendCustomerWelcomeNotification: Error");
        }

        return;
    }

    private static IEnumerable<string> BuildCustomFields(MeUser user)
    {
        var list = new List<string>();

        AddKeyValueIfNotNull(list, Constants.CustomFields.BuyerGroupName, user.CompanyID);
        AddKeyValueIfNotNull(list, Constants.CustomFields.FirstName, user.FirstName);
        AddKeyValueIfNotNull(list, Constants.CustomFields.LastName, user.LastName);
        AddKeyValueIfNotNull(list, Constants.CustomFields.PhoneNumber, user.Phone);
        AddKeyValueIfNotNull(list, Constants.CustomFields.CountryCode, user.xp?.CountryCode);
        AddKeyValueIfNotNull(list, Constants.CustomFields.StorefrontClientID, user.xp?.StorefrontClientId);
        AddKeyValueIfNotNull(list, Constants.CustomFields.PreferredLanguage, user.xp?.Language);
        AddKeyValueIfNotNull(list, Constants.CustomFields.StorefrontName, user.xp?.StorefrontName);

        return list;
    }

    private static IEnumerable<string> BuildTags(MeUser? user)
    {
        var tags = new List<string>();

        if (user?.xp == null)
        {
            return tags;
        }

        const string separator = Constants.Separators.Tag;
        AddKeyValueIfNotNull(tags, Constants.Tags.Country, user.xp.CountryCode, separator);
        AddKeyValueIfNotNull(tags, Constants.Tags.Lang, user.xp.Language, separator);
        AddKeyValueIfNotNull(tags, Constants.Tags.Shop, user.xp.StorefrontName, separator);

        return tags;
    }

    private static void AddKeyValueIfNotNull(ICollection<string> list, string key, string value,
        string separator = Constants.Separators.Field)
    {
        if (!string.IsNullOrEmpty(key) && !string.IsNullOrEmpty(value))
        {
            list.Add($"{key}{separator}{value}");
        }
    }
}
```

##### `MailingListService.cs` implementation

```
public class MailingListService : IMailingListService
{
    private readonly IFlurlClientFactory _flurlFactory;
    private readonly SitecoreSendSettings _sitecoreSendSettings;
    private IFlurlClient ApiClient => _flurlFactory.Get($"{_sitecoreSendSettings.BaseUrl}/v3/");

    public MailingListService(SitecoreSendSettings sitecoreSendSettings, IFlurlClientFactory flurlFactory)
    {
        _sitecoreSendSettings = sitecoreSendSettings;
        _flurlFactory = flurlFactory;
    }

    public string DefaultListId => _sitecoreSendSettings.EmailListId;

    public async Task<bool> AddToMailingList(string emailListId, AddingSubscribersRequest request)
    {
        var url = AddSubscriberUrl(emailListId);
        var response = await ApiClient.Request(url)
            .PostJsonAsync(request)
            .ConfigureAwait(false);

        return response != null && response.ResponseMessage.IsSuccessStatusCode;
    }

    private string AddSubscriberUrl(string mailingList)
    {
        return
            $"subscribers/{mailingList}/subscribe.{_sitecoreSendSettings.Format}?apikey={_sitecoreSendSettings.ApiKey}";
    }
}
```

##### Settings

```
public class SitecoreSendSettings
{
    public string Format { get; set; } = "json";
    public string ApiKey { get; set; }
    public string BaseUrl { get; set; }
    public string EmailListId { get; set; }   
}
```

- `ApiKey` - get it from Sitecore Send account settings
- `BaseUrl` - set it to `https://api.sitecoresend.io`
- `EmailListId` - email list, where your users will be added

Settings can be included in Headstart solution in [Azure App Configuration](https://github.com/ordercloud-api/headstart/blob/development/docs/AZURE_APP_CONFIGURATION.md).

##### Constants

```
public static class Constants
{
    public static class CustomFields
    {
        public const string BuyerGroupName = "BuyerGroup Name";
        public const string FirstName = "First Name";
        public const string LastName = "Last Name";
        public const string PhoneNumber = "Phone Number";
        public const string CountryCode = "Country Code";
        public const string StorefrontClientID = "Storefront Client ID";
        public const string PreferredLanguage = "Preferred Language";
        public const string StorefrontName = "Storefront Name";
    }

    public static class Tags
    {
        public const string Country = "country";
        public const string Lang = "lang";
        public const string Shop = "shop";
    }

    public static class Separators
    {
        public const string Field = "=";
        public const string Tag = ":";
    }
}
```

#### Sitecore Send

##### Mailing list

In the mailing list need to setup all custom fields we are populating from Headstart solution:

![email list with custom fields](https://www.brimit.com/-/media/images/blog/sitecore-send-order-cloud-welcome-email/email-list-custom-fields.png)

##### Subscriber

In Sitecore Send subscribers will appear as on example:

![example subscriber](https://www.brimit.com/-/media/images/blog/sitecore-send-order-cloud-welcome-email/susbcriber-example.png)

Also the subscriber contains some tags:

![subscriber tags](https://www.brimit.com/-/media/images/blog/sitecore-send-order-cloud-welcome-email/subscriber-tags.png)

In red I highlighted the tags, which were added by our webhook, in blue - tags, which are set by AI in Sitecore Send via [Audience Discovery](https://doc.sitecore.com/send/en/users/sitecore-send/work-with-audience-discovery.html).

##### Welcome Email Automation

The 'Welcome email' automation in Sitecore Send looks like this:

![marketing automation scheme](https://www.brimit.com/-/media/images/blog/sitecore-send-order-cloud-welcome-email/automation.png)

- Automation **triggers** when the subscriber is added to the mailing list.
- After that we can add some conditions to send different emails for different target groups (e.g. based on language - for **multilanguage** support).

##### Email template

Email template is configured using default Sitecore Send email editor. Inside it we use **personalization tags** to show personalized content for each user:

![email template with personalization tags](https://www.brimit.com/-/media/images/blog/sitecore-send-order-cloud-welcome-email/email-template.png)

In the template the following tags are used (highlighted in blue):

- `#recipient:name#`
- `#recipient:email#`

*Reminder.* You can use any custom field in the email template in the format `#recipient:[CUSTOM FIELD NAME]#`.

#### Conclusion

With Sitecore DXP products (like Send and OrderCloud) you can setup a distributed solution, which fully satisfy all commerce requirements. Stay tuned for more examples of configuring various transactional emails in Sitecore DXP solutions.

###### More From Author

[##### Sitecore Marketplace SDK Integration with Vercel AI SDK
February 25, 2026](https://www.brimit.com/blog/sitecore-marketplace-sdl-integration-with-vercel-ai-sdk)[##### Sitecore Marketplace Updates (December 2025)
December 16, 2025](https://www.brimit.com/blog/sitecoreai-marketplace-december-updates)[##### SitecoreAI, Marketer MCP, Agents API, Marketplace — Sitecore Symposium 2025 Recap
November 11, 2025](https://www.brimit.com/blog/sitecoreai-mcp-marketplace-symposium2025-recap)

###### Author

[!\[Igor Zharikov - Senior Sitecore Developer, Sitecore MVP\](https://www.brimit.com/-/jssmedia/feature/blogs/authors/igor-zharikov-2.jpg?h=700&amp;iar=0&amp;w=700&amp;hash=292A84E8CB3E5CE57CA743385CFB1464)
Igor Zharikov
Sitecore MVP / Senior Sitecore Developer](https://www.brimit.com/blog/author?authors=Igor%20Zharikov)

#### More on Sitecore

[!\[How Vercel Will Help You Save Effort When Deploying Sophisticated Sitecore Projects\](https://www.brimit.com/-/jssmedia/project/brimit/blog/2024/vercel_cover-image.png)
#Guides#How-toDXPE-commerce
##### How Vercel Will Help You Save Effort When Deploying Sophisticated Sitecore Projects
Optimize and accelerate the development and deployment of complex multisite Sitecore projects.
Alexei Vershalovich on July 17, 2024](https://www.brimit.com/blog/how-vercel-will-help-you-save-effort-when-deploying-sophisticated-sitecore-projects)

[!\[Training Up Tomorrow's Sitecore MVPs: a Mentoring Success Story\](https://www.brimit.com/-/jssmedia/project/brimit/blog/2023/sitecore-mentoring---cover-image.png)
#How-toDXP
##### Training Up Tomorrow's Sitecore MVPs: a Mentoring Success Story
How to participate in the Sitecore Mentor program and help younger colleagues jump-start a career in Sitecore development.
Sergey Baranov on October 2, 2023](https://www.brimit.com/blog/training-up-tomorrows-sitecore-mvps)

[!\[Going Headless. Part 2: When a Headless CMS Is Your Best Bet (if you have Sitecore)\](https://www.brimit.com/-/jssmedia/project/brimit/blog/2022/headless/adobestock_456986731.jpg)
#How-toDXPE-commerce
##### Going Headless. Part 2: When a Headless CMS Is Your Best Bet (if you have Sitecore)
Discover how a headless CMS can benefit organizations that use Sitecore.
Daniil Raschupkin, Palina Trokhautsava on September 15, 2022](https://www.brimit.com/blog/going-headless-part-2-when-a-headless-cms-is-your-best-bet-if-you-have-sitecore)

![](https://bat.bing.net/action/0?ti=187017043&amp;tm=gtm002&amp;Ver=2&amp;mid=045e6519-5491-47a5-82fe-471467f45e3a&amp;bo=2&amp;gtm_tag_source=1&amp;pi=0&amp;lg=en-US&amp;sw=800&amp;sh=600&amp;sc=24&amp;nwd=1&amp;tl=Sitecore%20Send%20%2B%20OrderCloud%20%3A%20Welcome%20email%20setup&amp;kw=sitecore%20send,ordercloud,comemrce,,transactional,emails&amp;p=https%3A%2F%2Fwww.brimit.com%2Fblog%2Fsitecore-send-order-cloud-welcome-email&amp;r=&amp;lt=359&amp;evt=pageLoad&amp;sv=2&amp;asc=D&amp;cdb=AQAY&amp;rn=924394)