Updated AuthController and CvController to return exception messages in 500 responses and enhanced logging. MailService now throws descriptive exceptions on email send failures, allowing upstream error reporting and preserving failed messages.
82 lines
3.8 KiB
C#
82 lines
3.8 KiB
C#
using AutoMapper;
|
|
using KBR.Shared.Mail;
|
|
using PortBlog.API.Common.Constants;
|
|
using PortBlog.API.Entities;
|
|
using PortBlog.API.Models;
|
|
using PortBlog.API.Repositories.Contracts;
|
|
using PortBlog.API.Services.Contracts;
|
|
using System.Net;
|
|
using System.Net.Mail;
|
|
|
|
namespace PortBlog.API.Services
|
|
{
|
|
/// <summary>
|
|
/// Provides functionality for sending emails and logging message activity.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// Initializes a new instance of the <see cref="MailService"/> class.
|
|
/// </remarks>
|
|
/// <param name="configuration">The application configuration.</param>
|
|
/// <param name="logger">The logger instance.</param>
|
|
/// <param name="mailRepository">The mail repository for storing messages.</param>
|
|
/// <param name="mapper">The AutoMapper instance.</param>
|
|
public class MailService(IConfiguration configuration, ILogger<MailService> logger, IMailRepository mailRepository, IMapper mapper) : IMailService
|
|
{
|
|
|
|
/// <summary>
|
|
/// Sends an email message asynchronously using the provided message details.
|
|
/// </summary>
|
|
/// <param name="messageSendDto">The message details to send.</param>
|
|
/// <returns>A task representing the asynchronous operation.</returns>
|
|
public async Task SendAsync(MessageSendDto messageSendDto)
|
|
{
|
|
logger.LogInformation("Sending message from {Name} ({FromEmail}).", messageSendDto.Name, messageSendDto.FromEmail);
|
|
messageSendDto.Subject = $"Message from {messageSendDto.Name}: Portfolio";
|
|
var messageEntity = mapper.Map<Message>(messageSendDto);
|
|
try
|
|
{
|
|
var mailSettings = configuration.GetSection("MailSettings").Get<MailSettingsDto>();
|
|
|
|
if (mailSettings != null && mailSettings.Enable)
|
|
{
|
|
using (var client = new SmtpClient())
|
|
{
|
|
client.Host = mailSettings.Host;
|
|
client.Port = mailSettings.Port;
|
|
client.DeliveryMethod = SmtpDeliveryMethod.Network;
|
|
client.UseDefaultCredentials = false;
|
|
client.EnableSsl = true;
|
|
client.Credentials = new NetworkCredential(mailSettings.Email, mailSettings.Password);
|
|
|
|
using var mailMessage = new MailMessage(
|
|
from: new MailAddress(mailSettings.Email),
|
|
to: new MailAddress(MailHelpers.ReplaceEmailDomain(messageSendDto.ToEmail, mailSettings.Domain), messageSendDto.Name)
|
|
);
|
|
|
|
mailMessage.Subject = messageSendDto.Subject;
|
|
mailMessage.Body = messageSendDto.Content;
|
|
mailMessage.IsBodyHtml = true;
|
|
|
|
client.Send(mailMessage);
|
|
messageSendDto.SentStatus = (int)MailConstants.MailStatus.Success;
|
|
}
|
|
|
|
mailRepository.AddMessage(messageEntity);
|
|
await mailRepository.SaveChangesAsync();
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
// Log full exception and persist failed message.
|
|
logger.LogCritical(ex, "Exception while sending mail from {FromEmail} ({Name}).", messageSendDto.FromEmail, messageSendDto.Name);
|
|
messageSendDto.SentStatus = (int)MailConstants.MailStatus.Failed;
|
|
mailRepository.AddMessage(messageEntity);
|
|
await mailRepository.SaveChangesAsync();
|
|
|
|
// Throw a descriptive exception so callers can return an error message to the client.
|
|
throw new InvalidOperationException($"Failed to send email to '{messageSendDto.ToEmail}'. See inner exception for details.", ex);
|
|
}
|
|
}
|
|
}
|
|
}
|