Completed initial database design
continuous-integration/drone/pr Build is passing

Sealed qualifying public classes
Migrated database changes
This commit is contained in:
Khwezi Mngoma
2026-05-27 09:12:04 +02:00
parent 70860efcfb
commit 902942eee6
86 changed files with 2883 additions and 140 deletions
+47 -30
View File
@@ -4,7 +4,7 @@ using LiteCharms.Features.Email.Models;
namespace LiteCharms.Features.Email;
public class EmailService(IOptions<SmtpSettings> options) : IDisposable
public sealed class EmailService(IOptions<SmtpSettings> options) : IDisposable
{
private readonly SmtpSettings settings = options.Value;
private readonly SmtpClient client = new();
@@ -16,6 +16,7 @@ public class EmailService(IOptions<SmtpSettings> options) : IDisposable
public async ValueTask<Result<Response>> SendEmailAsync(Message message, CancellationToken cancellationToken = default)
{
using var activity = EmailTelemetry.Source.StartActivity("Email Send");
activity?.SetTag("email.recipient", message.Recipient?.Address);
try
@@ -27,21 +28,7 @@ public class EmailService(IOptions<SmtpSettings> options) : IDisposable
return Result.Fail<Response>("Smtp service is disconnected.");
}
var email = new MimeMessage();
email.From.Add(new MailboxAddress(message.Sender!.Name, message.Sender.Address!));
email.To.Add(new MailboxAddress(message.Recipient!.Name, message.Recipient!.Address!));
email.Subject = message.Subject!;
var bodyBuilder = new BodyBuilder();
if (message.Body!.Properties.HasAttachments)
foreach (var attachment in message.Body?.Attachments!)
bodyBuilder.Attachments.Add(attachment.Name!, attachment.FileStream!, cancellationToken);
if (!message.Body.Properties.IsHtml) bodyBuilder.TextBody = message.Body.Message;
if (message.Body.Properties.IsHtml) bodyBuilder.HtmlBody = message.Body.Message;
email.Body = bodyBuilder.ToMessageBody();
var email = ConstructEmail(message, cancellationToken);
var response = await client.SendAsync(email, cancellationToken);
@@ -69,21 +56,9 @@ public class EmailService(IOptions<SmtpSettings> options) : IDisposable
await DisconnectAsync(cancellationToken);
if (response.Contains("421"))
{
Status = EmailStatuses.TooManyConnections;
var failCheckResult = HandleNegativeResponse(response);
return Result.Fail<Response>(response);
}
if (response.Contains("451"))
{
Status = EmailStatuses.ConnectionAborted;
return Result.Fail<Response>(response);
}
EmailTelemetry.EmailsFailed.Add(1, new TagList { { "error_message", response } });
if (failCheckResult.IsFailed) return failCheckResult;
Status = EmailStatuses.Disconnected;
@@ -100,6 +75,48 @@ public class EmailService(IOptions<SmtpSettings> options) : IDisposable
}
}
private static MimeMessage ConstructEmail(Message message, CancellationToken cancellationToken)
{
var email = new MimeMessage();
email.From.Add(new MailboxAddress(message.Sender!.Name, message.Sender.Address!));
email.To.Add(new MailboxAddress(message.Recipient!.Name, message.Recipient!.Address!));
email.Subject = message.Subject!;
var bodyBuilder = new BodyBuilder();
if (message.Body!.Properties.HasAttachments)
foreach (var attachment in message.Body?.Attachments!)
bodyBuilder.Attachments.Add(attachment.Name!, attachment.FileStream!, cancellationToken);
if (!message.Body.Properties.IsHtml) bodyBuilder.TextBody = message.Body.Message;
if (message.Body.Properties.IsHtml) bodyBuilder.HtmlBody = message.Body.Message;
email.Body = bodyBuilder.ToMessageBody();
return email;
}
private Result<Response> HandleNegativeResponse(string response)
{
if (response.Contains("421", StringComparison.Ordinal))
{
Status = EmailStatuses.TooManyConnections;
return Result.Fail<Response>(response);
}
if (response.Contains("451", StringComparison.Ordinal))
{
Status = EmailStatuses.ConnectionAborted;
return Result.Fail<Response>(response);
}
EmailTelemetry.EmailsFailed.Add(1, new TagList { { "error_message", response } });
return Result.Fail<Response>(response);
}
public async ValueTask<Result<Response>> ConnectAsync(CancellationToken cancellationToken = default)
{
using var activity = EmailTelemetry.Source.StartActivity("Email Connect");