Send non-campaign emails with sitecore ECM

How do I send non-campaign emails with sitecore’s ECM ?! That would be so cool! Hold on… the ECM is used for campaigns, for newsletter sending, for sending emails to multiple users. I should use a different email server for every-day emails… Yeah, then I’ll just check on this for fun I guess…

For sending campaign emails, Sitecore ECM makes use of two pipelines: DispatchNewsletter and SendEmail.

I am not interested in the first one, just by its name I think I can safely assume it’s irrelevant to what I’m trying to do, I don’t have a newsletter.

Going forward, it looks like SendEmail consists of two processors: FillEmail and SendEmail. After some mild testing and debugging, I’m pretty sure FillEmail will replace email tokens and SendEmail will use SendingManager to send the email.

Sitecore.Modules.EmailCampaign.SendingManager looks to already offer a couple of methods for sending emails.

SendingManager.SendMessage(), will pass through the DispatchNewsletter pipeline and that doesn’t help me because that will try to send the email through the same process as sending a newsletter. Hence, Sitecore will move my email to the processing folder.

SendingManager.SendStandardMessage(Contact), does not move the email from drafts to processing but it still calls some processors in the DispatchNewsletter pipeline. It will call DeployAnalytics, try to create Campaigns, Engagement plans, Subject MVTs. There’s a lot of overhead with SendStandardMessage so I don’t like this one either. Additionally I came across the following jewel: The UPDATE statement conflicted with the FOREIGN KEY constraint “FK_Automation_Campaign”. The conflict occurred in database “Sitecore_Analytics”, table “dbo.Campaigns”, column ‘CampaignId’..

That leaves me having to write my own.

    public class SendingManager : Sitecore.Modules.EmailCampaign.SendingManager
    {
        protected bool DedicatedInstance { get; set; }
        protected SMTPSettings MailSettings { get; set; }
        private SendingProcessData processData;
        protected SendingProcessData ProcessData
        {
            get
            {
                if (this.processData == null)
                {
                    this.processData = new SendingProcessData();
                }
                return this.processData;
            }
        }
        protected MessageItem Message { get; set; }

        public SendingManager(MessageItem message) : base(message)
        {
            this.Message = message;
            string smptSetingsError = "";
            this.MailSettings = Sitecore.Modules.EmailCampaign.SendingManager.GetSmtpSettings(out smptSetingsError);
        }

        public SendingManager(MessageItem message, bool isService):base(message,isService)
        {
            this.Message = message;
            string smptSetingsError = "";
            this.MailSettings = Sitecore.Modules.EmailCampaign.SendingManager.GetSmtpSettings(out smptSetingsError);
            this.DedicatedInstance = isService;
        }


        protected string SendNonCampaignMessageCore(Contact receiver)
        {
            Assert.ArgumentNotNull(receiver, "receiver");
            
            if (this.Message is INonCampaignEmail)
            {
                INonCampaignEmail message = this.Message as INonCampaignEmail;
                if (message != null)
                {
                    if (!message.SendAsCampaign)
                    {
                        this.Message.To = Util.GetCorrectContactAddress(this.Message, receiver);
                        this.Message.PersonalizationContact = receiver;

                        if (this.Message.Body == null)
                            this.Message.Body = this.Message.GetMessageBody();

                        SendMessageArgs paramz = new SendMessageArgs(this.Message, new FakeTask(this.Message, this.MailSettings));
                        FillEmail fill = new FillEmail();
                        fill.Process(paramz);

                        Sitecore.Modules.EmailCampaign.Core.Pipelines.SendEmail.SendEmail sender = new Sitecore.Modules.EmailCampaign.Core.Pipelines.SendEmail.SendEmail();
                        sender.Process(paramz);
                    }
                    else
                    {
                        base.SendStandardMessage(receiver);
                    }
                }
            }
            return "";
        }

        public string SendNonCampaignMessage(Contact receiver)
        {
            string str;
            Assert.ArgumentNotNull(receiver, "receiver");
            if (this.HasAccessToMailServer(false, out str))
            {
                return this.SendNonCampaignMessageCore(receiver);
            }
            return str;
        }
    }
    public interface INonCampaignEmail
    {
        bool SendAsCampaign
        {
            get;
            set;
        }
    }

I have to say, this took some time to figure out. I kept getting hit over the head with internal methods.
I believe this is the only way to achieve sending of non-campaign email with ECM and it’s only possible because Sitecore made Sitecore.Modules.EmailCampaign.SendingManager.GetSmtpSettings(out smptSetingsError) accessible. I have a feeling they will make this one internal too, I have no way of knowing. I’ve written this in 6.5.

There’s another class involved here, it’s the one representing the email template:

public class NonCampaignMail : WebPageMail, INonCampaignEmail
    {
        public NonCampaignMail(Item item)
            : base(item)
        {
        }

        new public static NonCampaignMail Create(string name, Item destination)
        {
            return FromItem(MessageItem.Create(name, destination, "{7B8A5AE9-149E-48B9-B597-E1A2A8D2CCCC}"));
        }

        new public static NonCampaignMail Create(string name, TargetAudienceBase sl)
        {
            return Create(name, sl.InnerItem);
        }

        new public static NonCampaignMail FromItem(Item item)
        {
            if (IsCorrectMessageItem(item))
            {
                return new NonCampaignMail(item);
            }
            return null;
        }

        new public static bool IsCorrectMessageItem(Item item)
        {
            return Util.IsTemplateDescendant(item, "{7B8A5AE9-149E-48B9-B597-E1A2A8D2CCCC}");
        }

        public bool SendAsCampaign
        {
            get;
            set;
        }

        public void Send(bool asCampaign)
        {
            Contact contact = Sitecore.Modules.EmailCampaign.Util.GetContactFromName("user.Name");
            if ((contact != null) && !string.IsNullOrEmpty(contact.Profile.Email))
            {
                this.SendAsCampaign = asCampaign;
                new SendingManager(this).SendNonCampaignMessage(contact);
            } 
        }

Going even further, I could extend the Sitecore.Modules.EmailCampaign.Core.TypeResolver to make sure predefined email types are sent as non-campaigns even when sent from Sitecore’s admin-interface:

    public class TypeResolver : Sitecore.Modules.EmailCampaign.Core.TypeResolver
    {
        override public MessageItem GetCorrectMessageObject(Item item)
        {
            if (item != null)
            {
                if (NonCampaignMail.IsCorrectMessageItem(item))
                {
                    return NonCampaignMail.FromItem(item);
                }
            }
            return base.GetCorrectMessageObject(item);
        }
    }

Untested, non-production code again

2 thoughts on “Send non-campaign emails with sitecore ECM

  1. John

    In looking over this solution I see you are creating a new FakeTask . What does this class look like?

    Reply
    1. amc Post author

      Hi John,

      FakeTask is a class out of “Assembly Sitecore.EmailCampaign.dll, v1.0.0.0”, it’s not something I’ve written.
      Thankfully I was able to find the original solution and navigate to the metadata in VS, it looks like this


      using Sitecore.Modules.EmailCampaign;
      using Sitecore.Modules.EmailCampaign.Core;
      using System;
      using System.Collections.Generic;

      namespace Sitecore.Modules.EmailCampaign.Core.Dispatch
      {
      public class FakeTask : MessageTask
      {
      public FakeTask(MessageItem messageItem, SMTPSettings smtpSettings);

      protected override void DoProcessing(RecipientInfo record, object arg);
      protected override List GetNextRecordBunch();
      }
      }

      I’m imagining this translates into something very simple, and “fake”:


      namespace Sitecore.Modules.EmailCampaign.Core.Dispatch
      {
      public class FakeTask : MessageTask
      {
      public FakeTask(MessageItem messageItem, SMTPSettings smtpSettings) : base(messageItem, smtpSettings)
      {
      }

      protected override void DoProcessing(RecipientInfo record, object arg)
      {
      }

      protected override List GetNextRecordBunch()
      {
      return null;
      }
      }
      }

      Hope that helps.

      Reply

Leave a Reply