Copied to clipboard

Flag this post as spam?

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


  • ewuski 88 posts 234 karma points
    Mar 20, 2024 @ 20:03
    ewuski
    0

    Transactional email in a loop not working

    Can the transactional service handle sending transactional emails in a loop?

    We are trying to send a transactional email to multiple customers:

    Option 1

    var customersToEmail = await GetCustomers();
    
    foreach (var customer in customersToEmail)
    {
       _transactionalEmailService.SendReminderEmail(customer);
    }
    

    and then:

    public CommandResult<SendTransactionalEmailResponse> SendReminderEmail(ReminderEmailModel customer)
    {
        return _newsletterStudioService.SendTransactional(
            SendTransactionalEmailRequest.Create(customer)
                .SendTo(customer.Email)
                .WithSubject(customer.Subject)
                .Build()
        );
    }
    

    First email goes out and then the consecutive email fails with the error:

    System.InvalidOperationException: Context flow is already suppressed. at System.Threading.ExecutionContext.SuppressFlow() at NewsletterStudio.Core.Public.NewsletterStudioService.SendTransactional(SendTransactionalEmailRequest request)

    Option 2

    If we try to execute it in async mode then the first email gets sent tout and the consecutive email hits the campaign service instead of the transactional.

    var customersToEmail = await GetCustomers();
    
    foreach (var customer in customersToEmail)
    {
        await _transactionalEmailService.SendReminderEmail(customer);
    }
    

    and then:

    public async Task<CommandResult<SendTransactionalEmailResponse>> SendReminderEmail(ReminderEmailModel customer)
    {
        return await Task.FromResult(_newsletterStudioService.SendTransactional(
            SendTransactionalEmailRequest.Create(customer)
                .SendTo(customer.Email)
                .WithSubject(customer.Subject)
                .Build())
        );
    }
    

    Umbraco 10.8.3 NS 10.0.8

  • Markus Johansson 1911 posts 5757 karma points MVP c-trib
    Mar 21, 2024 @ 09:38
    Markus Johansson
    0

    Hi!

    Are you running this in a background job in some way?

    I need to look closer at why you're getting the "Context flow is already suppressed."-error but a potential workaround for you is to force the sending to be sequential by chaining on the .NotAsync() call when building up the SendTransactionalEmailRequest.

    Update your "Option 1" so look something like this:

    return await Task.FromResult(_newsletterStudioService.SendTransactional(
        SendTransactionalEmailRequest.Create(customer)
            .SendTo(customer.Email)
            .WithSubject(customer.Subject)
            .NotAsync()
            .Build())
    

    Let me know if this works as a workaround for your problem?

    Cheers!

  • ewuski 88 posts 234 karma points
    Mar 29, 2024 @ 14:10
    ewuski
    0

    Hi, No, it didn't help.

    If I add .NotAsync() I am getting the following on the first send (no matter within async or sync method):

    System.InvalidOperationException
      HResult=0x80131509
      Message=Cannot resolve scoped service 'Microsoft.AspNetCore.Mvc.ViewFeatures.Buffers.IViewBufferScope' from root provider.
      Source=Microsoft.Extensions.DependencyInjection
      StackTrace:
       at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteValidator.ValidateResolution(Type serviceType, IServiceScope scope, IServiceScope rootScope)
       at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(Type serviceType, ServiceProviderEngineScope serviceProviderEngineScope)
       at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType)
       at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService(IServiceProvider provider, Type serviceType)
       at Microsoft.Extensions.DependencyInjection.ServiceProviderServiceExtensions.GetRequiredService[T](IServiceProvider provider)
       at Microsoft.AspNetCore.Mvc.Razor.RazorView.<RenderAsync>d__18.MoveNext()
       at NewsletterStudio.Web.Rendering.RazorHostViewRenderer.<RenderToStringAsync>d__6.MoveNext()
       at NewsletterStudio.Web.Rendering.RazorHostViewRenderer.RenderPartialViewToString(String viewName, Object model)
       at NewsletterStudio.Core.Rendering.EmailRenderer.Render(IRecipientDataModel recipient)
       at NewsletterStudio.Core.Sending.Transactional.TransactionalEmailSender.Send(SendTransactionalEmailRequest request)
    
  • Markus Johansson 1911 posts 5757 karma points MVP c-trib
    Mar 29, 2024 @ 15:02
    Markus Johansson
    0

    Hi!

    Can you explain more about your use case please?

    Are you sending from inside a HTTP-request or are you doing this in some kind of background job? If not, are you using a async method to send?

    Please explain the process so that I understand the context.

    If you don't feel comfortable sharing inner details here, please reach out over email markus {at sign goes here} enkelmedia.se.

  • ewuski 88 posts 234 karma points
    20 days ago
    ewuski
    0

    Hi Markus, It is an API call that calls the service where is the loop I quoted in my first post.

    I tried both with async and without it.

  • Markus Johansson 1911 posts 5757 karma points MVP c-trib
    20 days ago
    Markus Johansson
    0

    Hi!

    I need to understand the exact details around this, what do you mean with "API call"?

    Where exactly are you hosting this code?

    var customersToEmail = await GetCustomers();
    
    foreach (var customer in customersToEmail)
    {
       _transactionalEmailService.SendReminderEmail(customer);
    }
    

    Is it a "regular" API Controller like this:

    [ApiController]
    public class MyController : Controller 
    {
       public ActionResult Something()
       {
           var customersToEmail = await GetCustomers();
    
          foreach (var customer in customersToEmail)
          {
             _transactionalEmailService.SendReminderEmail(customer);
          }
    
       }
    }
    

    Could you provide some more exact details around how/where you are calling the service?

    Are you using anything "special" framework? Minimal API, API Controllers? Fast Endpoints? Please provide as much details as possible so that I can replicate the issue.

    The thing is that it looks like the INewsletterStudioService is used in context where the dependency injection container does not have a scope and the rendering engine is dependent on e.g. IViewBufferScope which is a scoped dependency. The fact that the error says "....from root provider." indicates that there is something about the context is which the service is used that is causing the issue - that's why I need as much details as possible.

    Cheers!

Please Sign in or register to post replies

Write your reply to:

Draft