Files
agrynco 2757869176 feat: consume transactional email notifications
Add contract validation, SMTP delivery results, terminal failure context, neutral development seeding, and local Docker setup.

Ref: IT-1033
2026-08-04 12:32:28 +03:00

81 lines
2.9 KiB
C#

namespace HrynCo.NotificationService.Worker.Services.EmailProcessing;
using System.Net.Mail;
using System.Net.Sockets;
public static class NotificationDeliveryErrorFormatter
{
private const int MaximumErrorLength = 2000;
private const string FallbackError = "Notification delivery failed after all retry attempts.";
public static string Format(Exception exception)
{
string technicalMessage = Normalize(exception.GetBaseException().Message);
if (string.IsNullOrWhiteSpace(technicalMessage))
{
return FallbackError;
}
string contextualMessage = CreateContextualMessage(exception, technicalMessage);
return contextualMessage.Length <= MaximumErrorLength
? contextualMessage
: contextualMessage[..MaximumErrorLength];
}
private static string CreateContextualMessage(Exception exception, string technicalMessage)
{
if (FindException<SmtpFailedRecipientException>(exception) is not null)
{
return "SMTP delivery failed after all retry attempts: " +
"the SMTP server rejected the recipient address.";
}
SocketException? socketException = FindException<SocketException>(exception);
if (socketException is not null)
{
string reason = socketException.SocketErrorCode switch
{
SocketError.HostNotFound or SocketError.NoData =>
"the configured SMTP server host could not be resolved",
SocketError.ConnectionRefused =>
"the configured SMTP server refused the connection",
SocketError.TimedOut =>
"the connection to the configured SMTP server timed out",
_ when technicalMessage.Contains(
"Name or service not known",
StringComparison.OrdinalIgnoreCase) =>
"the configured SMTP server host could not be resolved",
_ => "the configured SMTP server could not be reached"
};
return $"SMTP delivery failed after all retry attempts: {reason} ({technicalMessage}).";
}
if (FindException<SmtpException>(exception) is not null)
{
return $"SMTP delivery failed after all retry attempts ({technicalMessage}).";
}
return $"Notification delivery failed after all retry attempts ({technicalMessage}).";
}
private static TException? FindException<TException>(Exception exception)
where TException : Exception
{
for (Exception? current = exception; current is not null; current = current.InnerException)
{
if (current is TException typedException)
{
return typedException;
}
}
return null;
}
private static string Normalize(string message)
{
return message.ReplaceLineEndings(" ").Trim();
}
}