Open Closed

Notification Event Control #10634


User avatar
0
RahulRaj created

We understand that ABP Commercial/Pro provides the Text Template Management module to view, edit, replace, and manage seeded text/email templates. However, our requirement is not only template management. What we seem to be missing is an event-driven notification management layer, where the Host admin can manage which system events generate email notifications.

Our business requirements are:

  • Define and maintain a set of supported notification events.
  • Associate each notification event with an existing ABP text template.
  • Store notification settings at the Host level, including whether email delivery is enabled or disabled for each event.
  • When a notification event is triggered, verify the Host-level setting before sending an email.
  • If email delivery is enabled, render the associated ABP text template using runtime values such as tenant, user, and event-specific data.
  • Send the rendered email through ABP’s existing email sending infrastructure.
Markdown supported.
Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)

3 Answer(s)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    Hi,

    ABP doesn't ship a dedicated "event-driven notification management" module that wires events to templates with a host-level on/off switch. But every building block you need is already in the framework, and composing them takes only a thin coordinator class. Here is the pattern we recommend.

    1. Define your notification events as constants

    public static class AppNotificationEvents
    {
        public const string UserRegistered = "App.Notifications.UserRegistered";
        public const string OrderPlaced    = "App.Notifications.OrderPlaced";
    }
    

    2. Register a host-only setting per event (the on/off switch)

    WithProviders("G") (= GlobalSettingValueProvider.ProviderName) restricts the setting to the host level, so tenants cannot override it.

    public class AppNotificationSettingDefinitionProvider : SettingDefinitionProvider
    {
        public override void Define(ISettingDefinitionContext context)
        {
            context.Add(new SettingDefinition(
                    $"{AppNotificationEvents.UserRegistered}.EmailEnabled",
                    defaultValue: "true",
                    isVisibleToClients: true)
                .WithProviders(GlobalSettingValueProvider.ProviderName));
    
            context.Add(new SettingDefinition(
                    $"{AppNotificationEvents.OrderPlaced}.EmailEnabled",
                    defaultValue: "true",
                    isVisibleToClients: true)
                .WithProviders(GlobalSettingValueProvider.ProviderName));
        }
    }
    

    3. Register a text template per event

    public class AppEmailTemplateDefinitionProvider : TemplateDefinitionProvider
    {
        public override void Define(ITemplateDefinitionContext context)
        {
            context.Add(new TemplateDefinition(
                    AppNotificationEvents.UserRegistered,
                    layout: StandardEmailTemplates.Layout,
                    localizationResource: typeof(AppResource))
                .WithVirtualFilePath("/Emailing/Templates/UserRegistered.tpl", isInlineLocalized: true));
        }
    }
    

    Add the Text Template Management module (Volo.Abp.TextTemplateManagement.*) to your solution. With it installed, host admins can edit the rendered content of every template through the UI; ITemplateRenderer checks the DB first and falls back to your .tpl file, so updates take effect without redeploy.

    4. The coordinator: setting check → render → send

    This is the single place every notification flows through.

    public class NotificationDispatcher : IDomainService, ITransientDependency
    {
        protected ITemplateRenderer TemplateRenderer { get; }
        protected ISettingProvider SettingProvider { get; }
        protected IEmailSender EmailSender { get; }
    
        public NotificationDispatcher(
            ITemplateRenderer templateRenderer,
            ISettingProvider settingProvider,
            IEmailSender emailSender)
        {
            TemplateRenderer = templateRenderer;
            SettingProvider = settingProvider;
            EmailSender = emailSender;
        }
    
        public virtual async Task DispatchEmailAsync(
            string eventCode, string to, string subject, object model, string? cultureName = null)
        {
            var enabled = await SettingProvider.GetAsync<bool>($"{eventCode}.EmailEnabled");
            if (!enabled)
            {
                return;
            }
    
            var body = await TemplateRenderer.RenderAsync(eventCode, model, cultureName);
            await EmailSender.QueueAsync(to, subject, body);
        }
    }
    

    QueueAsync pushes the email into the ABP background job queue, so the calling event handler isn't blocked by SMTP.

    5. Hook your business events

    Any local or distributed event handler (or just any application service) calls the dispatcher:

    public class UserRegisteredEmailHandler
        : ILocalEventHandler<UserRegisteredEto>, ITransientDependency
    {
        private readonly NotificationDispatcher _dispatcher;
    
        public UserRegisteredEmailHandler(NotificationDispatcher dispatcher)
            => _dispatcher = dispatcher;
    
        public Task HandleEventAsync(UserRegisteredEto eventData)
            => _dispatcher.DispatchEmailAsync(
                AppNotificationEvents.UserRegistered,
                eventData.Email,
                "Welcome",
                new { eventData.UserName, eventData.TenantName });
    }
    

    Inside the .tpl file you reference the model fields ({{model.user_name}}, {{model.tenant_name}}, …) using Scriban or Razor depending on which engine you registered.

    Summary

    • Static event codes give you a stable contract.
    • Host-only settings give the host admin the per-event email on/off switch you described.
    • TemplateDefinition + the Text Template Management module gives admins a UI to edit template content.
    • NotificationDispatcher is the single chokepoint that checks the switch, renders, and sends — keeps your business code clean.

    If you later need admins to add new event codes at runtime (without redeploy), you can promote the static class into a NotificationEvent entity (Code / TemplateName / IsEmailEnabled) and resolve it from DB inside the dispatcher — but most teams don't need that and the static approach is much simpler.

    Thanks

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    RahulRaj created

    In our notification use case, the email body is rendered from an ABP text template using runtime values such as tenant, user, and event-specific data.

    Can the** email subject** also be managed dynamically through ABP Text Templates in ABP Pro?

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    Hi,

    Yes, you can. ITemplateRenderer.RenderAsync is just a string-template renderer — it doesn't care whether the output is HTML, plain text, or a single line for an email subject. So you simply register a second template per event for the subject and render it the same way you render the body.

    Register a Subject template alongside the Body template

    For the subject template, don't pass a layout — you don't want the HTML layout wrapped around a one-line subject.

    public class AppEmailTemplateDefinitionProvider : TemplateDefinitionProvider
    {
        public override void Define(ITemplateDefinitionContext context)
        {
            context.Add(new TemplateDefinition(
                    $"{AppNotificationEvents.UserRegistered}.Subject",
                    localizationResource: typeof(AppResource))
                .WithVirtualFilePath("/Emailing/Templates/UserRegistered.Subject.tpl", isInlineLocalized: true));
    
            context.Add(new TemplateDefinition(
                    $"{AppNotificationEvents.UserRegistered}.Body",
                    layout: StandardEmailTemplates.Layout,
                    localizationResource: typeof(AppResource))
                .WithVirtualFilePath("/Emailing/Templates/UserRegistered.Body.tpl", isInlineLocalized: true));
        }
    }
    

    UserRegistered.Subject.tpl is just one line:

    Welcome {{model.user_name}} to {{model.tenant_name}}!
    

    Render both in the dispatcher

    public virtual async Task DispatchEmailAsync(
        string eventCode, string to, object model, string? cultureName = null)
    {
        var enabled = await SettingProvider.GetAsync<bool>($"{eventCode}.EmailEnabled");
        if (!enabled)
        {
            return;
        }
    
        var subject = await TemplateRenderer.RenderAsync($"{eventCode}.Subject", model, cultureName);
        var body    = await TemplateRenderer.RenderAsync($"{eventCode}.Body", model, cultureName);
    
        await EmailSender.QueueAsync(to, subject.Trim(), body);
    }
    

    subject.Trim() removes the trailing newline that template engines add to the rendered output — without it, some SMTP servers reject or fold the subject line.

    Admin UI behavior

    The Text Template Management module lists every registered TemplateDefinition in its UI (it just calls ITemplateDefinitionManager.GetAllAsync() under the hood). So once you register the .Subject template, the host admin sees it next to the .Body template and can edit both independently — no extra configuration, permission, or feature flag needed.

    Thanks

    Markdown supported.
    Copy, paste, or drag & drop images and files (max 100 MB per file, 100 MB total per post)
Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v10.8.0-preview. Updated on September 16, 2026, 14:50
1
ABP Assistant
🔐 You need to be logged in to use the chatbot. Please log in first.