Steve McNiven-Scott (https://www.sitefinitysteve.com) asked a question.
/Sitefinity/Administration/Settings/Basic/SystemEmailTemplates
Can we add to these to use in sending off messages in custom code?
Steve McNiven-Scott (https://www.sitefinitysteve.com) asked a question.
/Sitefinity/Administration/Settings/Basic/SystemEmailTemplates
Can we add to these to use in sending off messages in custom code?

Hi Steve,
It is possible to achieve this. A system email template is represented by a class that inherits Telerik.Sitefinity.Services.Notifications.SitefinityActionMessageTemplate. This class has two abstract methods that need to be implemented - GetPlaceholderFields and GetDefaultMessageTemplate where you specify the available placeholder fields and default html for the email. Here is a sample:
public class SampleMessageTemplate : SitefinityActionMessageTemplate
{
internal static class PlaceholderFields
{
// Note that the field name must contain a . character
public static readonly PlaceholderField Name = new PlaceholderField("Subscriber.Name", "Full name");
public static readonly PlaceholderField Email = new PlaceholderField("Subscriber.Email", "Email");
}
public SampleMessageTemplate()
{
this.ModuleName = "ModuleName";
}
public override IMessageTemplateRequest GetDefaultMessageTemplate()
{
var messageTemplate = new MessageTemplateRequestProxy();
messageTemplate.Subject = $"Sample Template - {{|{PlaceholderFields.Name.FieldName}|}}";
messageTemplate.BodyHtml = ControlTemplateResolver.ResolveTemplate("SitefinityWebApp.SampleTemplate.htm", Assembly.GetExecutingAssembly());
return messageTemplate;
}
public override IEnumerable<PlaceholderField> GetPlaceholderFields()
{
return new PlaceholderField[]
{
PlaceholderFields.Email
};
}
}
In my case I am loading the html from a .html file that is set with Build action embedded resource in the project. The markup is:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Some Title</title>
</head>
<body style="background-color: #f2f2f2; padding: 0px; margin: 0px auto; zoom: 100%;">
Hello {|Subscriber.Name|}! You have received an email at {|Subscriber.Email|}.
</body>
</html>
This is where the easy part ends. The system email templates feature has been designed to only work with Sitefinity modules. If you are creating a Sitefinity module you can implement the IActionMessageTemplatesProvider interface, implement the GetActionMessageTemplates method and return an array of your message templates like so:
public IEnumerable<IActionMessageTemplate> GetActionMessageTemplates()
{
return new IActionMessageTemplate[] { new SampleMessageTemplate() };
}
A workaround exists that will enable you to register your templates for an existing Sitefinity module. The downside is that that module will appear in the "Used In" column when viewing the list of system email templates. Nevertheless, for this approach you need to create a class that inherits Telerik.Sitefinity.Services.ServiceBase and again implements IActionMessageTemplatesProvider:
public class SampleMessageTemplatesProvider : ServiceBase, IActionMessageTemplatesProvider
{
public override Type[] Interfaces => new Type[] { };
public IEnumerable<IActionMessageTemplate> GetActionMessageTemplates()
{
return new IActionMessageTemplate[] { new SampleMessageTemplate() };
}
}
If you decide to go with this approach you will also need to set the ModuleName property of your template class to the respective module. Example:
public SampleMessageTemplate()
{
this.ModuleName = "News";
}
After that you register this class as a system service under Administration -> Settings -> Advanced -> System -> SystemService. The tricky part is that the Name of the registered service must match the name of an enabled Sitefinity module. For example "News". In my case the data was:
Name: News
Title: Custom Templates Provider
Type: SitefinityWebApp.SampleMessageTemplatesProvider, SitefinityWebApp
StartupType: OnApplicationStart
After the registration you need to restart Sitefinity. At this point the template will appear under Settings -> System email templates and can be edited.
The next part is using the template. First you will need a way for resolving the template. Here's the helper method I used:
public class SystemEmailHelpers
{
public static IMessageTemplateRequest ResolveTemplate(IActionMessageTemplate actionMessageTemplate)
{
var ns = SystemManager.GetNotificationService();
IMessageTemplateRequest template = null;
actionMessageTemplate.ApplyVariations((SitefinityActionMessageTemplate.Variations.SiteId, SystemManager.CurrentContext.CurrentSite.Id.ToString()));
template = ns.GetSystemMessageTemplate(null, actionMessageTemplate.GetKey());
if (template == null)
{
actionMessageTemplate.ApplyVariations((SitefinityActionMessageTemplate.Variations.SiteId, null));
template = ns.GetSystemMessageTemplate(null, actionMessageTemplate.GetKey());
}
if (template == null)
{
template = actionMessageTemplate.GetDefaultMessageTemplate();
}
return template;
}
}
After having the template you can send the email like so:
var template = SystemEmailHelpers.ResolveTemplate(new SampleMessageTemplate());
IMessageJobRequest messageJob = new MessageJobRequestProxy()
{
Subscribers = new List<ISubscriberRequest> { new SubscriberRequestProxy { Email = "test@email.com" } },
MessageTemplate = template,
Description = "Sitefinity configuration error"
};
SystemManager.GetNotificationService().SendMessage(
new ServiceContext(null, null),
messageJob,
new Dictionary<string, string> {
{ SampleMessageTemplate.PlaceholderFields.Name.FieldName, "Velizar" },
{ SampleMessageTemplate.PlaceholderFields.Email.FieldName, "velizar-test@email.com" }
});
I hope this helps you out.
Velizar
Wow thanks for the detail!
Am I nuts or is the [sf_notif_msg_template] table storing not templates, but the completed parameters filled in message log?

Hi Steve,
The sf_notif_msg_template table stores the templates with the parameters in them. In the above example with the custom template the stored body html (unless modified) would be:
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>Some Title</title> </head> <body style="background-color: #f2f2f2; padding: 0px; margin: 0px auto; zoom: 100%;"> Hello {|Subscriber.Name|}! You have received an {|Subscriber.Email|}. </body> </html>
The resolve key is:
{SitefinityWebApp.SampleMessageTemplate}{News}{00000000-0000-0000-0000-000000000000}{00000000-0000-0000-0000-000000000000}{}
where the second empty GUID is the id of the site and would be different if the template is modified for a specific site. Example:
{SitefinityWebApp.SampleMessageTemplate}{News}{00000000-0000-0000-0000-000000000000}{f94d24bf-13db-4ce1-8a53-fbf6489e2ba6}{}
I hope this helps,
Velizar
Hi Steve,
It is possible to achieve this. A system email template is represented by a class that inherits Telerik.Sitefinity.Services.Notifications.SitefinityActionMessageTemplate. This class has two abstract methods that need to be implemented - GetPlaceholderFields and GetDefaultMessageTemplate where you specify the available placeholder fields and default html for the email. Here is a sample:
public class SampleMessageTemplate : SitefinityActionMessageTemplate
{
internal static class PlaceholderFields
{
// Note that the field name must contain a . character
public static readonly PlaceholderField Name = new PlaceholderField("Subscriber.Name", "Full name");
public static readonly PlaceholderField Email = new PlaceholderField("Subscriber.Email", "Email");
}
public SampleMessageTemplate()
{
this.ModuleName = "ModuleName";
}
public override IMessageTemplateRequest GetDefaultMessageTemplate()
{
var messageTemplate = new MessageTemplateRequestProxy();
messageTemplate.Subject = $"Sample Template - {{|{PlaceholderFields.Name.FieldName}|}}";
messageTemplate.BodyHtml = ControlTemplateResolver.ResolveTemplate("SitefinityWebApp.SampleTemplate.htm", Assembly.GetExecutingAssembly());
return messageTemplate;
}
public override IEnumerable<PlaceholderField> GetPlaceholderFields()
{
return new PlaceholderField[]
{
PlaceholderFields.Name,
PlaceholderFields.Email
};
}
}
In my case I am loading the html from a .html file that is set with Build action embedded resource in the project. The markup is:
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>Some Title</title>
</head>
<body style="background-color: #f2f2f2; padding: 0px; margin: 0px auto; zoom: 100%;">
Hello {|Subscriber.Name|}! You have received an email at {|Subscriber.Email|}.
</body>
</html>
This is where the easy part ends. The system email templates feature has been designed to only work with Sitefinity modules. If you are creating a Sitefinity module you can implement the IActionMessageTemplatesProvider interface, implement the GetActionMessageTemplates method and return an array of your message templates like so:
public IEnumerable<IActionMessageTemplate> GetActionMessageTemplates()
{
return new IActionMessageTemplate[] { new SampleMessageTemplate() };
}
A workaround exists that will enable you to register your templates for an existing Sitefinity module. The downside is that that module will appear in the "Used In" column when viewing the list of system email templates. Nevertheless, for this approach you need to create a class that inherits Telerik.Sitefinity.Services.ServiceBase and again implements IActionMessageTemplatesProvider:
public class SampleMessageTemplatesProvider : ServiceBase, IActionMessageTemplatesProvider
{
public override Type[] Interfaces => new Type[] { };
public IEnumerable<IActionMessageTemplate> GetActionMessageTemplates()
{
return new IActionMessageTemplate[] { new SampleMessageTemplate() };
}
}
If you decide to go with this approach you will also need to set the ModuleName property of your template class to the respective module. Example:
public SampleMessageTemplate()
{
this.ModuleName = "News";
}
After that you register this class as a system service under Administration -> Settings -> Advanced -> System -> SystemService. The tricky part is that the Name of the registered service must match the name of an enabled Sitefinity module. For example "News". In my case the data was:
Title: Custom Templates Provider
Type: SitefinityWebApp.SampleMessageTemplatesProvider, SitefinityWebApp
StartupType: OnApplicationStart
After the registration you need to restart Sitefinity. At this point the template will appear under Settings -> System email templates and can be edited.
The next part is using the template. First you will need a way for resolving the template. Here's the helper method I used:
public class SystemEmailHelpers
{
public static IMessageTemplateRequest ResolveTemplate(IActionMessageTemplate actionMessageTemplate)
{
var ns = SystemManager.GetNotificationService();
IMessageTemplateRequest template = null;
actionMessageTemplate.ApplyVariations((SitefinityActionMessageTemplate.Variations.SiteId, SystemManager.CurrentContext.CurrentSite.Id.ToString()));
template = ns.GetSystemMessageTemplate(null, actionMessageTemplate.GetKey());
if (template == null)
{
actionMessageTemplate.ApplyVariations((SitefinityActionMessageTemplate.Variations.SiteId, null));
template = ns.GetSystemMessageTemplate(null, actionMessageTemplate.GetKey());
}
if (template == null)
{
template = actionMessageTemplate.GetDefaultMessageTemplate();
}
return template;
}
}
After having the template you can send the email like so:
var template = SystemEmailHelpers.ResolveTemplate(new SampleMessageTemplate());
IMessageJobRequest messageJob = new MessageJobRequestProxy()
{
Subscribers = new List<ISubscriberRequest> { new SubscriberRequestProxy { Email = "test@email.com" } },
MessageTemplate = template,
Description = "Sitefinity configuration error"
};
SystemManager.GetNotificationService().SendMessage(
new ServiceContext(null, null),
messageJob,
new Dictionary<string, string> {
{ SampleMessageTemplate.PlaceholderFields.Name.FieldName, "Velizar" },
{ SampleMessageTemplate.PlaceholderFields.Email.FieldName, "velizar-test@email.com" }
});
I hope this helps you out.
Velizar