Sitecore Submit Action – Send Notification Email using Sitecore Dispatch Manager

I’m going to walk you through how to use Sitecore Dispatch Manager to implement Send Notification Email for Submit Action in Sitecore Form Submissions.

Let’s go ahead and create Form Submit Action.

Sitecore Item Path: /sitecore/system/Settings/Forms/Submit Actions/Send Notification Email

Add “Send Notification Email” action on the Submit button.

Now let’s write the code for CustomSendNotificationEmail class

You’ll need the following references in the solution:
Sitecore.ExperienceForms
Sitecore.ExperienceForms.Mvc
Sitecore.ExperienceForms.SubmitAction
Sitecore.EDS.Core

using Newtonsoft.Json;
using Sitecore.Data;
using Sitecore.Diagnostics;
using Sitecore.ExperienceForms.Models;
using Sitecore.ExperienceForms.Mvc.Models.Fields;
using Sitecore.ExperienceForms.Processing;
using Sitecore.ExperienceForms.Processing.Actions;
using System;
using System.Collections.Generic;
using System.Linq;
using CompanyName.Foundation.Core.Managers;
using CompanyName.Foundation.Core.Models;
using static System.FormattableString;

namespace CompanyName.Foundation.Core.Extensions
{
    public class CustomSendNotificationEmail : SubmitActionBase<string>
    {
        public CustomSendNotificationEmail(ISubmitActionData submitActionData) : base(submitActionData)
        {
        }

        EmailManager em = new EmailManager(new Sitecore.EDS.Core.Dispatch.DispatchManager());

        protected override bool Execute(string data, FormSubmitContext formSubmitContext)
        {
            try
            {
                Assert.ArgumentNotNull(data, nameof(data));
                Assert.ArgumentNotNull(formSubmitContext, nameof(formSubmitContext));

                var formDefinition = JsonConvert.DeserializeObject<EmailFormDefinition>(data);

                if (formDefinition == null)
                {
                    Logger.LogError(Invariant($"Form {formSubmitContext.FormId} can't submitted. Parameters is empty."), this);
                    return false;
                }

                if (formDefinition.Emails == null || !formDefinition.Emails.Any())
                {
                    Logger.LogError(Invariant($"Form {formSubmitContext.FormId} can't submitted.`Emails` parameter is empty."), this);
                    return false;
                }

                if (String.IsNullOrEmpty(formDefinition.FromEmailId))
                {
                    Logger.LogError(Invariant($"Form {formSubmitContext.FormId} can't submitted.`FromEmailId` parameter is empty."), this);
                    return false;
                }

                if (String.IsNullOrEmpty(formDefinition.FromEmailName))
                {
                    Logger.LogError(Invariant($"Form {formSubmitContext.FormId} can't submitted.`FromEmailName` parameter is empty."), this);
                    return false;
                }

                if (String.IsNullOrEmpty(formDefinition.EmailSubjectLine))
                {
                    Logger.LogError(Invariant($"Form {formSubmitContext.FormId} can't submitted.`EmailSubjectLine` parameter is empty."), this);
                    return false;
                }

                if (!formSubmitContext.HasErrors)
                {
                    var formData = new Dictionary<string, string>();
                    foreach (var field in formSubmitContext.Fields)
                    {
                        var title = Sitecore.Context.Database.GetItem(new ID(field.ItemId))["Title"];
                        if (!formData.ContainsKey(title))
                        {
                            formData.Add(title, GetValue(field));
                        }
                    }

                    if (!formData.Any())
                    {
                        return true;
                    }

                    var emailBody = string.Empty;
                    foreach (var d in formData)
                    {
                        emailBody += "<div>";
                        emailBody += $"<span>{d.Key}</span>: <span>{d.Value}</span>";
                        emailBody += "</div>";
                    }

                    em.SendEmail(formDefinition.EmailSubjectLine, formDefinition.FromEmailId, formDefinition.FromEmailName, formDefinition.Emails, emailBody);

                    Logger.Info(Invariant($"Form {formSubmitContext.FormId} submitted successfully."), this);
                    return true;
                }
            }
            catch (Exception ex)
            {
                Log.Error($"{nameof(formSubmitContext.FormId)}: from send error", ex, this);
            }

            return false;
        }

        protected override bool TryParse(string value, out string target)
        {
            target = value;
            return true;
        }

        private static string GetValue(object field)
        {
            var value = "";

            if (field is CheckBoxListViewModel)
            {
                var _field = field as CheckBoxListViewModel;
                if (_field.Value != null)
                    value = string.Join(", ", _field.Value);
            }
            else if (field is ListViewModel)
            {
                var _field = field as ListViewModel;
                if (_field.Value != null)
                    value = _field.Value.FirstOrDefault();
            }
            else if (field is DateViewModel)
            {
                var _field = field as DateViewModel;
                if (_field.Value != null)
                    value = _field.Value?.ToString(_field.DateFormat);
            }
            else
            {
                value = field?.GetType().GetProperty("Value")?.GetValue(field, null)?.ToString() ?? string.Empty;
            }

            return value;
        }

    }
}

On the line 32 you will see DeserializeObject to EmailFormDefinition object. Create a new EmailFormDefinition Model class and add the reference in the CustomSendNotificationEmail class.

using System;
using System.Collections.Generic;
using Newtonsoft.Json;
using Sitecore.Data;

namespace CompanyName.Foundation.Core.Models
{
    [Serializable]
    public class EmailFormDefinition
    {

        [JsonProperty("emails")]
        public List<string> Emails { get; set; }
        

        [JsonProperty("fromEmailId")]
        public string FromEmailId { get; set; }

        [JsonProperty("fromEmailName")]
        public string FromEmailName { get; set; }

        [JsonProperty("emailSubjectLine")]
        public string EmailSubjectLine { get; set; }
    }
}

Now we need EmailManager class to send an email using DispatchManager.

using Sitecore.Diagnostics;
using Sitecore.EDS.Core.Dispatch;
using System;
using System.Collections.Generic;


namespace CompanyName.Foundation.Core.Managers
{
    public class EmailManager
    {
        private readonly IDispatchManager _dispatchManager;

        public EmailManager(IDispatchManager dispatchManager)
        {
            this._dispatchManager = dispatchManager;
        }

        public bool SendEmail(string subject, string fromEmailAddress, string fromName, List<string> recipients, string htmlBody)
        {
            EmailMessage message = new EmailMessage
            {
                Subject = subject,
                FromAddress = fromEmailAddress,
                FromName = fromName,
                ContentType = MessageContentType.Html,
                Recipients = recipients,
                HtmlBody = htmlBody,
                ReplyTo = fromEmailAddress
            };

            return this.SendEmail(message);
        }

        public bool SendEmail(EmailMessage emailMessage)
        {
            try
            {
                if (!this._dispatchManager.IsConfigured)
                {
                    throw new Exception(message: "Dispatch Manager is not configured");
                }

                DispatchResult dispatchResult = this._dispatchManager.SendAsync(emailMessage).Result;
                return true;
            }
            catch(Exception ex)
            {
                Log.Error(ex.InnerException.ToString(), this);
            }

            return false;
        }

    }
}

That’s it with the code 🙂

On the CMS go the form Submit Action “Send Notification Email” and add the following parameters:

{“emails”:[nikkipunjabi@outlook.com],”fromEmailName”:”CompanyName Notification”,”emailSubjectLine”:”Complaint Form Submission”,”fromEmailId”:no-reply@comms.COMPANYNAME.ae}


Please Note: in the emails — you can add Multiple ToEmailAddresses. You can set Emails (To Email Address), From Email Name (Sender Name), From Email Id (Sender Email ID), Email Subject Line

Output:

The development of this feature can be improved in many ways but it depends entirely on your requirements and availability of time. For example, adding or editing parameter values directly on the form submit action on Sitecore Forms. The Sender Name and Sender Email Address should be configured from the configuration items, and the Email Body can be customized directly from the CMS. Alternatively, if the SMTP configuration is using Custom SMTP and it allows you to set the sender email address to any address, you can have the reply email go to the actual user who submitted the form.

Challenges:

#1 – Execute Method is not getting triggerred.

Solution: First check the breakpoint on the class constructor – in my case, breakpoint was hitting on the class constructor but not the execute method. The reason was simple, “Send Notification Email” action item was in the end while “Redirect To URL” action item was before that.

#2 – data.Chilkat fail reason: “DataFailure”

"Failed to send the email message due to incorrect data.Chilkat fail reason: DataFailure"

"   at Sitecore.EDS.Core.Net.Smtp.ChilkatTransportClient.SendAsync(Email message)\r\n   at Sitecore.EDS.Core.Net.Smtp.ChilkatMessageTransport.<>c__DisplayClass9_0.<<SendTaskAsync>g__SendAsyncLocal|0>d.MoveNext()\r\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n   at Sitecore.ExM.Framework.Helpers.Retry.<OperationWithBasicRetryAsync>d__4`1.MoveNext()\r\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at Sitecore.EDS.Core.Net.Smtp.ChilkatMessageTransport.<SendTaskAsync>d__9.MoveNext()\r\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at Sitecore.EDS.Providers.SparkPost.Dispatch.DispatchProvider.<SendEmailAsync>d__5.MoveNext()\r\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at Sitecore.EDS.Core.Dispatch.DispatchProviderBase.<SendAsync>d__5.MoveNext()\r\n   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n   at Sitecore.EDS.Core.Dispatch.DispatchManager.<SendAsync>d__6.MoveNext()"

{Name = "ChilkatTransportClient" FullName = "Sitecore.EDS.Core.Net.Smtp.ChilkatTransportClient"}

Solution: In our case, I spent a lot of time figuring out that Sitecore Email Cloud only supports a specific Email Address as the From Email Address. It does not support having other email addresses as the From Email Address. When I entered no-reply@comms.companyName.com – it started working and we received a proper notification email upon form submission. If my understanding is incorrect, Email Cloud will not allow us to enter another domain for the Sender Email Address. It will only allow DKIM verified domains to send an email using Email Cloud. You can correct me by adding comments if I am wrong in this regard.

References:

https://www.xcentium.com/blog/2019/04/11/how-to-send-custom-email-using-sitecore-dispatch-manager-and-test-it-locally

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.