Sitecore publishing notifications to MS Teams

This time I’m sharing a simple implementation for sending notifications to a MS Teams channel. This can be useful when you want to keep a group of Sitecore users updated on the publishing operations.

It also useful when publishing large amount of items and the editors won’t keep the Sitecore session, so there is no need to go and check the jobs that are running, why not getting a notification on MS Teams?

Also, the idea behind this post is to quickly show how simple is to build a MS Teams Connector and also, how to perform a custom action in the Sitecore publish:end event.

Sitecore publishing notifications to MS Teams

Creating the MS Teams Connector

The first step is to create a Incoming Webhook connector. Click on the three dots next to your Teams channel and choose Connectors:

Give it a name, upload an image and click on create. Save the wehbook url, you will need it later.

The event handler

We just need to create a custom event hanlder to be triggered in the publish:end event.

<events>
  <event name="publish:end">
    <handler type="MSTeamsPublishing.Events.Notification, MSTeamsPublishing" method="SendNotification"/>
  </event>
</events>

Notification.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using MessageCardModel;
using MessageCardModel.Actions;
using MessageCardModel.Actions.OpenUri;
using Microsoft.Extensions.DependencyInjection;
using MSTeamsPublishing.Services;
using Sitecore.DependencyInjection;
using Sitecore.Publishing;
using Sitecore.Sites;

namespace MSTeamsPublishing.Events
{
    public class Notification
    {
        private readonly IItemSiteResolver _siteResolver;
        private readonly IMsTeamsConnectorService _msTeamsConnectorService;

        public Notification()
        {
            _siteResolver = ServiceLocator.ServiceProvider.GetService<IItemSiteResolver>();
            _msTeamsConnectorService = ServiceLocator.ServiceProvider.GetService<IMsTeamsConnectorService>();
        }

        public Notification(IItemSiteResolver siteResolver, IMsTeamsConnectorService msTeamsConnectorService)
        {
            _siteResolver = siteResolver;
            _msTeamsConnectorService = msTeamsConnectorService;
        }

        public void SendNotification(object sender, EventArgs args)
        {
            var sitecoreArgs = args as Sitecore.Events.SitecoreEventArgs;

            if (!(sitecoreArgs?.Parameters[0] is Publisher publisher)) return;

            var rootItem = publisher.Options.RootItem;
            var publishJobs = Sitecore.Jobs.JobManager.GetJobs().Where(x => x.Name.Equals(publisher.GetJobName())).ToList();
            var site = _siteResolver.ResolveSite(rootItem);
            var hostUrl = "https://" + (site != null ? site.HostName : $"{HttpContext.Current?.Request.Url.Scheme}://{HttpContext.Current?.Request.Url.Host}");
            var ItemId = HttpUtility.UrlEncode(rootItem.ID.ToString());

            foreach (var j in publishJobs.Where(p => p.Handle.IsLocal))
            {
                var teamsMessage = new MessageCard();
                var facts = new List<Fact> { new Fact {Name = "User: ", Value = publisher.Options.UserName } };

                foreach (var message in j.Status.Messages)
                {
                    var messageSplit = message.Split(':');
                    var fact = new Fact {Name = $"{messageSplit[0]}: ", Value = messageSplit[1]};
                    facts.Add(fact);
                }

                var section = new Section
                {
                    ActivityTitle = $"{j.Name} Done!",
                    ActivitySubtitle = $"Version: {rootItem.Version}, Language: {rootItem.Language}, Target DB: {publisher.Options.TargetDatabase}. Subitems: {publisher.Options.Deep}",
                    ActivityImage = "https://sitecorecdn.azureedge.net/-/media/sitecoresite/images/global/logo/favicon.png",
                    Facts = facts
                };

                var sitecoreRedirectAction = new OpenUriAction { Type = ActionType.OpenUri, Name = "Go to Sitecore", Targets = new [] { new Target { OS = TargetOs.Default, Uri = $"{hostUrl}/sitecore/shell/sitecore/content/Applications/Content Editor.aspx?id={ItemId}&amp;la={rootItem.Language}&amp;fo={ItemId}" } } };
                var publicRedirectAction = new OpenUriAction { Type = ActionType.OpenUri, Name = "Go to website", Targets = new [] { new Target { OS = TargetOs.Default, Uri = $"{hostUrl}/?sc_itemid={ItemId}&amp;sc_mode=normal&amp;sc_lang={rootItem.Language}" } } };

                teamsMessage.Context = "https://schema.org/extensions";
                teamsMessage.Type = "MessageCard";
                teamsMessage.Summary = "Publish Notification";
                teamsMessage.ThemeColor = "008000";
                teamsMessage.Sections = new [] {section};
                teamsMessage.Actions = new [] {sitecoreRedirectAction, publicRedirectAction};

                _msTeamsConnectorService.ProcessAsync(teamsMessage).ConfigureAwait(false).GetAwaiter().GetResult();
            }
        }
    }
}

The code is very simple, and to avoid creating the models for building the MS Teams Cards, I’m using the MessageCardModel Nuget package. Have a look also at this Message Card Playground tool, you can use to design your cards.

You can find more info about the MS Teams connector wehbook here.

MSTeamsConnectorService.cs

using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using MessageCardModel;
using Sitecore.Configuration;

namespace MSTeamsPublishing.Services
{
    public class MsTeamsConnectorService : IMsTeamsConnectorService
    {
        public async Task ProcessAsync(MessageCard card)
        {
            var requestUri = Settings.GetSetting("MSTeamsPublishing.TeamsWebhookUrl", string.Empty);
            var converted = card.ToJson();

            using (var client = new HttpClient())
            using (var content = new StringContent(converted, Encoding.UTF8, "application/json"))
            using (var response = await client.PostAsync(requestUri, content).ConfigureAwait(false))
            {
                response.EnsureSuccessStatusCode();
            }
        }
    }
}

Config patch

<settings>
    <setting name="MSTeamsPublishing.TeamsWebhookUrl" value="your webhook URL here" />
 </settings>

The only config needed is to put the webhook URL you get in the first step, after creating the connector in Teams.

Let’s test it!

If everything went well, you should be able to get a notification after the publishing is completed.

You can find the whole implementation in GitHub.

Thanks!