diff --git a/src/infrastructure/DigitalData.MessagingService.Infrastructure/DependencyInjection.cs b/src/infrastructure/DigitalData.MessagingService.Infrastructure/DependencyInjection.cs index 2a7ebf6..8b713f6 100644 --- a/src/infrastructure/DigitalData.MessagingService.Infrastructure/DependencyInjection.cs +++ b/src/infrastructure/DigitalData.MessagingService.Infrastructure/DependencyInjection.cs @@ -29,13 +29,17 @@ public static class DependencyInjection IConfiguration configuration) { // --- External Services --- - // Email Service - SMTP outbound (Limilabs Mail.dll) - services.AddSingleton(); + // Email Service - SMTP outbound (Limilabs Mail.dll) - OAuth2 aware + services.AddSingleton(); + services.AddSingleton(); + services.AddSingleton(sp => sp.GetRequiredService()); // Email Service - IMAP inbound (Limilabs Mail.dll) - // Fresh connection per call — stateless and thread-safe. services.AddScoped(); - + + // Email Service - POP3 inbound (Limilabs Mail.dll) + services.AddScoped(); + // PDF Processing Service (using DevExpress.Pdf) services.AddScoped(); diff --git a/src/infrastructure/DigitalData.MessagingService.Infrastructure/Queue/SendingEmailConsumer.cs b/src/infrastructure/DigitalData.MessagingService.Infrastructure/Queue/SendingEmailConsumer.cs index 80c6f0a..acf5102 100644 --- a/src/infrastructure/DigitalData.MessagingService.Infrastructure/Queue/SendingEmailConsumer.cs +++ b/src/infrastructure/DigitalData.MessagingService.Infrastructure/Queue/SendingEmailConsumer.cs @@ -2,6 +2,7 @@ using System.Text; using System.Text.Json; using DigitalData.MessagingService.Application.Common.Interfaces; using DigitalData.MessagingService.RabbitMQ; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using RabbitMQ.Client; using RabbitMQ.Client.Events; @@ -31,7 +32,7 @@ public sealed class SendingEmailConsumer : IAsyncDisposable /// public Guid RuntimeId { get; } = Guid.NewGuid(); - public SendingEmailConsumer(string queueName, IEmailService emailService, RabbitMqConnectionFactory cnnFactory, ILogger? logger = null) + public SendingEmailConsumer(string queueName, IEmailService emailService, IServiceScopeFactory scopeFactory, RabbitMqConnectionFactory cnnFactory, ILogger? logger = null) { _logger = logger; _queueName = queueName; @@ -41,8 +42,6 @@ public sealed class SendingEmailConsumer : IAsyncDisposable { var channel = await _lazyChannel.Value; - // prefetchCount=1 ensures this consumer processes one message at a time before acking. - // Parallelism comes from running multiple consumer instances, not from within a single channel. await channel.BasicQosAsync(prefetchSize: 0, prefetchCount: 1, global: false); var consumer = new AsyncEventingBasicConsumer(channel); @@ -57,8 +56,14 @@ public sealed class SendingEmailConsumer : IAsyncDisposable if (oMailEvent is not null) { - // Send email via SMTP (SMTP config is injected in IEmailService via IOptions) - await emailService.SendEmailAsync(oMailEvent.Mail, args.CancellationToken); + if (oMailEvent.UseImapAppend) + { + await using var scope = scopeFactory.CreateAsyncScope(); + var imapService = scope.ServiceProvider.GetRequiredService(); + await imapService.SendAndAppendAsync(oMailEvent.Mail, oMailEvent.SentFolder, args.CancellationToken); + } + else + await emailService.SendEmailAsync(oMailEvent.Mail, args.CancellationToken); // Acknowledge message after successful processing await channel.BasicAckAsync(args.DeliveryTag, false, args.CancellationToken); diff --git a/src/infrastructure/DigitalData.MessagingService.Infrastructure/Queue/SendingEmailConsumerPool.cs b/src/infrastructure/DigitalData.MessagingService.Infrastructure/Queue/SendingEmailConsumerPool.cs index 691b62c..7242eec 100644 --- a/src/infrastructure/DigitalData.MessagingService.Infrastructure/Queue/SendingEmailConsumerPool.cs +++ b/src/infrastructure/DigitalData.MessagingService.Infrastructure/Queue/SendingEmailConsumerPool.cs @@ -1,5 +1,6 @@ using DigitalData.MessagingService.Application.Common.Interfaces; using DigitalData.MessagingService.RabbitMQ; +using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; @@ -8,8 +9,6 @@ namespace DigitalData.MessagingService.Infrastructure.Queue; /// /// Manages a pool of instances that compete for messages /// on the same RabbitMQ queue (competing consumers pattern). -/// Each consumer owns a dedicated channel, so they process messages fully in parallel -/// without any shared locking or synchronization primitives. /// public sealed class SendingEmailConsumerPool : IAsyncDisposable { @@ -20,6 +19,7 @@ public sealed class SendingEmailConsumerPool : IAsyncDisposable public SendingEmailConsumerPool( IOptions config, IEmailService emailService, + IServiceScopeFactory scopeFactory, RabbitMqConnectionFactory cnnFactory, ILogger? logger = null, ILogger? consumerLogger = null) @@ -29,7 +29,7 @@ public sealed class SendingEmailConsumerPool : IAsyncDisposable _consumers = [.. Enumerable .Range(0, _concurrency) - .Select(_ => new SendingEmailConsumer(config.Value.QueueName, emailService, cnnFactory, consumerLogger))]; + .Select(_ => new SendingEmailConsumer(config.Value.QueueName, emailService, scopeFactory, cnnFactory, consumerLogger))]; } ///