feat: consume transactional email notifications

Add contract validation, SMTP delivery results, terminal failure context, neutral development seeding, and local Docker setup.

Ref: IT-1033
This commit is contained in:
2026-08-04 12:32:28 +03:00
parent b8435ac07b
commit 2757869176
37 changed files with 1465 additions and 122 deletions
@@ -0,0 +1,63 @@
namespace HrynCo.NotificationService.Worker.Services.EmailProcessing;
using HrynCo.NotificationService.Contracts.Messages;
using Hrynco.RabbitMq;
using Microsoft.Extensions.Logging;
internal sealed class NotificationResultPublisher : INotificationResultPublisher
{
private readonly ILogger<NotificationResultPublisher> _logger;
private readonly IRabbitMqPublisher _publisher;
public NotificationResultPublisher(
IRabbitMqPublisher publisher,
ILogger<NotificationResultPublisher> logger)
{
_publisher = publisher;
_logger = logger;
}
public async Task PublishAsync(
SendEmailMessage message,
string? deliveryError,
CancellationToken cancellationToken)
{
CorrelationContext correlationContext = message.CorrelationContext;
string? replyTo = correlationContext.ReplyTo;
if (string.IsNullOrWhiteSpace(replyTo))
{
return;
}
try
{
var result = new NotificationResultMessage
{
CorrelationContext = correlationContext with { ReplyTo = null },
Data = new NotificationResultData
{
ServiceName = message.Data.ServiceName,
RecipientEmail = message.Data.RecipientEmail,
TemplateKey = message.Data.TemplateKey,
Timestamp = DateTimeOffset.UtcNow,
ErrorMessage = deliveryError
}
};
await _publisher.PublishAsync(replyTo, result, cancellationToken);
_logger.LogDebug(
"Notification result published to reply queue {Queue} [CorrelationId={CorrelationId}]",
replyTo,
correlationContext.CorrelationId);
}
catch (Exception exception)
{
_logger.LogWarning(
exception,
"Failed to publish notification result to reply queue {Queue} [CorrelationId={CorrelationId}]",
replyTo,
correlationContext.CorrelationId);
}
}
}