Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • jake platford 11 posts 120 karma points
    Nov 21, 2023 @ 09:47
    jake platford
    0

    Dynamic form notification email recipient based on form field

    Hi,

    I have an enquiry form on my website (v12) which uses Umbraco forms.

    The enquiry form features a branch selector dropdown, which allows uses to select the branch of the company they want to send their enquiry to. The dropdown is populated by a prevalue source (a list of branch nodes). The form submission field contains the node id for the branch.

    I would like to use the 'Send email with template (Razor)' workflow, and set the notification to be the address set on the Branch node (The Branch doc type has a 'notificationEmailAddress' field).

    If I try to use {branch} in the recipient email field of the workflow, it returns the following error:

    Example error

  • Marc Goodson 2141 posts 14344 karma points MVP 8x c-trib
    Nov 22, 2023 @ 14:45
    Marc Goodson
    0

    Hi Jake

    With this scenario you can created your own Custom WorkflowType...

    I think I've done nearly the exact same thing before, where the Umbraco Form has a PreValue source for a list of stores, populated from Umbraco Nodes, the 'Value' field is the Umbraco Node Id, and the Caption is the name of the store...

    Then, in the Custom Workflow step you can read the value of the selected branch/(store in my case) from the submitted form details and then get that node from Umbraco and read the store/branch email address and then send the email there...

    this is the kind of thing I had:

    public class SendEmailToSelectedStoreWorkflow : WorkflowType
        {
            private readonly ILogger<SendEmailToSelectedStoreWorkflow> _logger;
            private readonly IEmailService _emailService;
            private readonly IWebpackService _webpackService;
            private readonly IOptions<SiteSettingsOptions> _siteSettings;
            private readonly IUmbracoContextAccessor _umbracoContextAccessor;
    
            public SendEmailToSelectedStoreWorkflow(ILogger<SendEmailToSelectedStoreWorkflow> logger, IWebpackService webpackService,IEmailService emailService, IOptions<SiteSettingsOptions> siteSettings, IUmbracoContextAccessor umbracoContextAccessor)
            {
                _logger = logger;
                _webpackService = webpackService;
                _emailService = emailService;
                _siteSettings= siteSettings;    
                _umbracoContextAccessor = umbracoContextAccessor;
    
                this.Id = new Guid("4d3ac0b3-bd01-4e7a-854b-5fdaabe21a8c");
                this.Name = "Send Email To Selected Store";
                this.Description = "This workflow forwards the email containing the forms submission onto the store selected in the store dropdown on the form";
                this.Icon = "icon-store";
                this.Group = "Services";
            }
    
            public override WorkflowExecutionStatus Execute(WorkflowExecutionContext context)
            {
                _logger.LogInformation("SendEmailToSelectedStoreWorkflow STARTED: " + context.Form.Name);
                try
                {
                    var toEmail = string.Empty;
                    var storeName = string.Empty;
    
                    var logoUrl = _siteSettings.Value.SiteDomain + "/" + _webpackService.GetImageFile("logo-png");
                    var htmlBody = $"<p style='margin-top: 5px;'><br/></p><img width='260' height='46' src='{logoUrl}'/><p style='margin-top: 10px;' ><br/></p>";
                    var subject = context.Form.Name;
                    var storeDropdownFieldAlias = "storesDropdown";
    
                    foreach (var recordField in context.Record.RecordFields)
                    {
                        // check if values exist for the record
                        if (recordField.Value.Values != null && recordField.Value.Values.Any())
                        {
                            // read the value and alias of the record field
                            var formFieldValue = recordField.Value.Values[0].ToString();
                            var formFieldAlias = recordField.Value.Alias;
                            storeName = formFieldValue;         
                            //if it's the dropdown field
    
                            if (formFieldAlias.Equals(storeDropdownFieldAlias,StringComparison.InvariantCultureIgnoreCase))
                            {
                                _logger.LogInformation($"Found {storeDropdownFieldAlias} with FormFieldValue: {formFieldValue}");
                                if (!String.IsNullOrWhiteSpace(formFieldValue))
                                {
                                    if (_umbracoContextAccessor.TryGetUmbracoContext(out IUmbracoContext? context) == false)
                                        {
                                        var store = context.Content.GetById(formFieldValue);
                                        if (store!=null){
                                            toEmail = store.Value<string>("storeEmail");
                                            storeName = store.Name;
                                            subject += " for " + storeName;
                                        }
    
                                        else
                                        {                   
    
                                            _logger.LogInformation($"No Store Found");
    
                                        }
                                    }
                                    else {
                                    _logger.LogInformation($"No Umbraco Context Found!");
    
                                    }
    
                                }
                                else
                                {
                                    _logger.LogInformation("No Form Field Value For Store Dropdown!");
                                }
                            }
    
                            htmlBody += "<h4 style='font-weight: 700; color: #000000; font-size: 16px;'>" +
                                        recordField.Value.Field.Caption + "</h4>"
                                        + "<p style='margin-top: 0;'>" + storeName + "</p>";
                        }
                        else
                        {
                            _logger.LogInformation($"SendEmailToSelectedStoreWorkflow NULL FIELD: {context.Form.Name} - {recordField.Value.Alias} of type {recordField.Value.DataTypeAlias}");
    
                        }
    
                    }
                    AsyncHelper.RunSync(() => _emailService.SendMessageAsync("[email protected]", "YourWebsite Website", toEmail, storeName, subject, htmlBody));
    
    
                }
                catch (Exception ex)
                {
                    _logger.LogInformation("SendEmailToSelectedStoreWorkflow ERROR: " + context.Form.Name + " " + ex.Message);
                }
                _logger.LogInformation("SendEmailToSelectedStoreWorkflow ENDED: " + context.Form.Name);
                return WorkflowExecutionStatus.Completed;
            }
    
            public override List<Exception> ValidateSettings()
            {
                return new List<Exception>();
            }
        }
    

    Hopefully that gives you a steer?

    regards

    Marc

  • jake platford 11 posts 120 karma points
    Nov 22, 2023 @ 15:26
    jake platford
    0

    Hi Marc,

    Thanks for your response, that does do what I've asked for - however, I need to be able to use a selected template (like the default 'Send email with template (Razor)' workflow does rather than a hardcoded string for the email body like in your example. (Apologies, I should have been more specific!)

  • Marc Goodson 2141 posts 14344 karma points MVP 8x c-trib
    Nov 22, 2023 @ 15:54
    Marc Goodson
    0

    Hi Jake

    If you add this to the custom Workflow Type as a public property

        [Umbraco.Forms.Core.Attributes.Setting("Store Dropdown Field Alias", Alias = "storeDropdownFieldAlias",
        Description = "Enter the alias of the field that contains the Store dropdown, if left blank, will default to try to use 'storesDropdown'",
        View = "TextField")]
    
        public string StoreDropdownFieldAlias { get; set; }
    

    you'll get a field that you can set when you add the workflow to a form, that you can then read inside your implementation to avoid hardcoding...

    We have multiple forms with dropdowns on which to choose the store, and they all have different alias!

    So I added the textfield above, so that when we add the custom workflow step, we can apply it to the specific form field...

    Similarly this could be the path to an XSLT file, and you could inside the custom implementation above, apply the provided XSLT file to the data passed into the Workflow, just like the custom one does! (in fact your custom workflowtype might be able to inherit from the XSLT one that is shipped, and you just override the implementation to get the email, and call the base method to do the template fangling... but that is a guess!

    regards

    marc

  • jake platford 11 posts 120 karma points
    Nov 22, 2023 @ 16:26
    jake platford
    100

    Overriding the implementation of the default 'Send email with template (Razor)' works perfectly - thanks for the suggestion!

    Below is the workflow class that I created to get it working:

    public class SendEmailToBranchWorkflow : SendRazorEmail
    {
        private readonly IContentService _contentService;
        private readonly IContentTypeService _contentTypeService;
        private readonly IConfiguration _config;
    
        public SendEmailToBranchWorkflow(Umbraco.Cms.Core.Hosting.IHostingEnvironment hostingEnvironment, IOptions<GlobalSettings> globalSettings, 
            IHttpContextAccessor httpContextAccessor, IFieldTypeStorage fieldTypeStorage, IFormService formService, 
            IUmbracoContextAccessor umbracoContextAccessor, IPageService pageService, IWorkflowEmailService workflowEmailService, 
            MediaFileManager mediaFileManager, FileSystems fileSystems, IPublishedUrlProvider publishedUrlProvider, 
            ILogger<SendRazorEmail> logger, IPlaceholderParsingService placeholderParsingService, 
            IPrevalueSourceService prevalueSourceService, IFieldPreValueSourceTypeService fieldPreValueSourceTypeService, IConfiguration config,
            IContentService contentService, IContentTypeService contentTypeService)
            : base(hostingEnvironment, globalSettings, httpContextAccessor, fieldTypeStorage, formService, umbracoContextAccessor, pageService, workflowEmailService, 
                  mediaFileManager, fileSystems, publishedUrlProvider, logger, placeholderParsingService, prevalueSourceService, fieldPreValueSourceTypeService)
        {
            _contentService = contentService;
            _contentTypeService = contentTypeService;
            _config = config;
        }
        public override WorkflowExecutionStatus Execute(WorkflowExecutionContext context)
        {
            var emailToSendTo = string.Empty;
            var record = context.Record;
            var branch = GetBranchForSubmission(record);
            if (branch != null)
            {
                var notificationEmail = branch.GetValue<string>(nameof(Branch.NotificationEmailAddress));
                if (!string.IsNullOrWhiteSpace(notificationEmail))
                {
                    emailToSendTo = notificationEmail;
                }
            }
    
            if (!string.IsNullOrWhiteSpace(emailToSendTo))
            {
                base.Email += (";" + emailToSendTo);
            }
    
            return base.Execute(context);
        }
    
        public IContent GetBranchForSubmission(Record record)
        {
            var branchId= record.GetValue<string>("branch");
            if (!string.IsNullOrWhiteSpace(branchId))
            {
                var branchType = _contentTypeService.Get(Branch.ModelTypeAlias);
                var branchPages = _contentService.GetPagedOfType(branchType.Id, 0, 50, out _, null);
                if (branchPages  != null)
                {
                    return branchPages .FirstOrDefault(f => f.Id == int.Parse(branchId));
                }
            }
    
            return null;
        }
    
    }
    
  • Marc Goodson 2141 posts 14344 karma points MVP 8x c-trib
    Nov 22, 2023 @ 17:15
    Marc Goodson
    1

    Great!

Please Sign in or register to post replies

Write your reply to:

Draft