Custom emails are typically a specialized form of a custom notification. While all notifications can be delivered via the email distribution type, notifications that implement IEmailNotificationType support rendering specific strings for the email's subject, body, header, and footer. And beyond that, email notifications that implement IScriptedEmail enable the email's definition to be customized within Email Studio .
Why Should I Create an Email Notification Type?
New email notification types are useful when you want to be more specific about how a notification is represented as email, including defining the email's subject, body, header, and footer and optionally making these components editable in Email Studio.
Creating an IEmailNotificationType that supports scripting with IScriptedEmail
Starting with the previously-created custom INotificationType, add the following interfaces: IEmailNotificationType, IScriptedEmail.
Implement these interfaces as follows:
#region IEmailNotificationType public string Get(EmailTarget target, Notification notification) { if (notification == null || notification.ExtendedAttributes == null) return null; var commentIdAttribute = notification.ExtendedAttributes.FirstOrDefault(ea => ea.Key == "TargetCommentId"); if (commentIdAttribute == null) return null; var commentId = Guid.Parse(commentIdAttribute.Value); var comment = Apis.Get<IComments>().Get(commentId); if (comment == null) return null; var user = Apis.Get<IUsers>().Get(new UsersGetOptions { Id = notification.UserId }); if (user == null) return null; return _scriptedEmailController.Render(target, new ScriptedEmailRenderOptions { Context = new Dictionary<string, object> { { "Content", notification.Content }, { "Comment", comment } }, ApplicationId = notification?.Content?.Application?.ApplicationId, ApplicationTypeId = notification?.Content?.Application?.ApplicationTypeId }); } #endregion #region IScriptedEmail IScriptedEmailController _scriptedEmailController; public Guid ScriptedEmailId => new Guid("efed29fa-e94e-41f4-b36d-74f9f1df29a0"); public void SetController(IScriptedEmailController controller) => _scriptedEmailController = controller; public IDictionary<string, Type> ContextualData => new Dictionary<string, Type> { { "Content", typeof(Content) }, { "Comment", typeof(Comment) } }; public IDictionary<string, object> GetSampleContext() => new Dictionary<string, object> { { "Content", null }, { "Comment", null } }; #endregion
ContextualData
and and the dictionary passed to Render
's Context option. The dictionary passed to Render
's Context option contains the contextual items made available to this email's script when it executes. ContextualData defines the types of these objects to enable $context_v1_email.Context
to be accurately documented within the automatic and inline API documentation for this email. When implemented, GetSampleContext
(), allows this email to contain sample defaults for these objects when rendering previews of the email.Full plugin sample:
using System; using System.Collections.Generic; using System.Linq; using Telligent.Evolution.Extensibility; using Telligent.Evolution.Extensibility.Api.Entities.Version1; using Telligent.Evolution.Extensibility.Api.Version1; using Telligent.Evolution.Extensibility.Content.Version1; using Telligent.Evolution.Extensibility.Email.Version1; namespace Samples { public class SampleNotificationType : INotificationType, IEmailNotificationType, IScriptedEmail { private INotificationController _notificationController; #region IPlugin public string Name => "Sample Notification"; public string Description => "This plugin demonstrates the INotificationType plugin type"; public void Initialize() { Apis.Get<IComments>().Events.AfterCreate += CommentEvents_AfterCreate; } #endregion #region INotificationType public string NotificationTypeName => "Sample"; public string NotificationTypeDescription => "Sends a sample notification."; public string NotificationTypeCategory => "Samples"; public Guid NotificationTypeId => new Guid("3C0542FD-5AB0-4386-911C-86CCF530BAEE"); public bool IsCacheable => true; public bool VaryCacheByUser => true; public bool CanDeleteNotification(Guid notificationId, int userId) { var notification = Apis.Get<INotifications>().Get(notificationId); return notification != null && notification.UserId == userId; } public string GetMessage(Guid notificationId, string target) { var notification = Apis.Get<INotifications>().Get(notificationId); if (notification == null || notification.ExtendedAttributes == null) return null; var commentIdAttribute = notification.ExtendedAttributes.FirstOrDefault(ea => ea.Key == "TargetCommentId"); if (commentIdAttribute == null) return null; var commentId = Guid.Parse(commentIdAttribute.Value); var comment = Apis.Get<IComments>().Get(commentId); if (comment == null) return null; var user = Apis.Get<IUsers>().Get(new UsersGetOptions { Id = notification.UserId }); if (user == null) return null; return $"The following comment was added by {user.DisplayName}: \"{comment.Body()}\""; } public string GetTargetUrl(Guid notificationId) { var notification = Apis.Get<INotifications>().Get(notificationId); return notification != null && notification.Content != null ? notification.Content.Url : null; } public void SetController(INotificationController controller) { _notificationController = controller; } #endregion private void CommentEvents_AfterCreate(CommentAfterCreateEventArgs e) { if (e == null || e.Content == null || e.User == null || !e.IsApproved || !e.Content.CreatedByUserId.HasValue || e.CommentTypeId.GetValueOrDefault(Guid.Empty) != Guid.Empty) { return; } var comment = Apis.Get<IComments>().Get(e.CommentId); if (comment != null && comment.IsApproved) { AddNotifications(e.Content.ContentId, e.Content.ContentTypeId, e.CommentId, e.Content.CreatedByUserId.Value, e.UserId); } } private void AddNotifications(Guid contentId, Guid contentTypeId, Guid commentId, int contentAuthor, int actorId) { var comment = Apis.Get<IComments>().Get(commentId); if (comment == null) return; var attributes = new List<IExtendedAttribute> { new ExtendedAttribute { Key = "TargetCommentId", Value = comment.CommentId.ToString("N") } }; _notificationController.CreateUpdate(new NotificationCreateUpdateOptions { ContentId = contentId, ContentTypeId = contentTypeId, LastUpdate = DateTime.UtcNow, UserId = contentAuthor, ActorIdToAdd = actorId, ExtendedAttributes = attributes }); } #region IEmailNotificationType public string Get(EmailTarget target, Notification notification) { if (notification == null || notification.ExtendedAttributes == null) return null; var commentIdAttribute = notification.ExtendedAttributes.FirstOrDefault(ea => ea.Key == "TargetCommentId"); if (commentIdAttribute == null) return null; var commentId = Guid.Parse(commentIdAttribute.Value); var comment = Apis.Get<IComments>().Get(commentId); if (comment == null) return null; var user = Apis.Get<IUsers>().Get(new UsersGetOptions { Id = notification.UserId }); if (user == null) return null; return _scriptedEmailController.Render(target, new ScriptedEmailRenderOptions { Context = new Dictionary<string, object> { { "Content", notification.Content }, { "Comment", comment } }, ApplicationId = notification?.Content?.Application?.ApplicationId, ApplicationTypeId = notification?.Content?.Application?.ApplicationTypeId }); } #endregion #region IScriptedEmail IScriptedEmailController _scriptedEmailController; public Guid ScriptedEmailId => new Guid("efed29fa-e94e-41f4-b36d-74f9f1df29a0"); public void SetController(IScriptedEmailController controller) => _scriptedEmailController = controller; public IDictionary<string, Type> ContextualData => new Dictionary<string, Type> { { "Content", typeof(Content) }, { "Comment", typeof(Comment) } }; public IDictionary<string, object> GetSampleContext() => new Dictionary<string, object> { { "Content", null }, { "Comment", null } }; #endregion } }
Creating a matching default script implementation
Create the following file in the CFS path using the ScriptedEmailId: /filestorage/defaultemail/efed29fae94e41f4b36d74f9f1df29a0.xml
. This defines the default implementation of the email script which can be customized, published, or reverted within Email Studio .
<scriptedEmail name="Sample Email" version="13.0.0.0" description="Raises notifications on comments." id="efed29fae94e41f4b36d74f9f1df29a0"> <subjectScript language="Velocity"><![CDATA[ $context_v1_email.Context.Comment.User.DisplayName commented on $context_v1_email.Context.Content.HtmlName('Email') ]]></subjectScript> <headerScript language="Velocity"><![CDATA[ $context_v1_email.Context.Comment.User.DisplayName commented on $context_v1_email.Context.Content.HtmlName('Email') ]]></headerScript> <bodyScript language="Velocity"><![CDATA[ Comment Body: $context_v1_email.Context.Comment.Body() ]]></bodyScript> <footerScript language="Velocity" /> </scriptedEmail>