189 lines
8.2 KiB
C#
189 lines
8.2 KiB
C#
using System.Net;
|
|
using System.Net.Mail;
|
|
using System.Net.Mime;
|
|
using e_suite.API.Common.exceptions;
|
|
using e_suite.API.Common.repository;
|
|
using e_suite.Database.Audit;
|
|
using e_suite.Database.Audit.AuditEngine;
|
|
using e_suite.Service.Mail.Facade;
|
|
using e_suite.Service.Mail.Helper;
|
|
using eSuite.Core.MailService;
|
|
using Microsoft.Extensions.Configuration;
|
|
|
|
namespace e_suite.Service.Mail;
|
|
|
|
public class MailService : IMailService
|
|
{
|
|
private readonly IConfiguration _configuration;
|
|
private readonly IUserManagerRepository _userManagerRepository;
|
|
private readonly IMailServiceRepository _mailServiceRepository;
|
|
private readonly ISmtpClientFactory _smtpClientFactory;
|
|
const long SunStrategyDomainId = 1;
|
|
|
|
public MailService(IConfiguration configuration, IUserManagerRepository userManagerRepository, IMailServiceRepository mailServiceRepository, ISmtpClientFactory smtpClientFactory)
|
|
{
|
|
_configuration = configuration;
|
|
_userManagerRepository = userManagerRepository;
|
|
_mailServiceRepository = mailServiceRepository;
|
|
_smtpClientFactory = smtpClientFactory;
|
|
}
|
|
|
|
public async Task RequestEMailAsync(MailRequest emailRequest, CancellationToken cancellationToken)
|
|
{
|
|
var username = _configuration.GetConfigValue("MAIL_USERNAME", "Smtp:Username", string.Empty);
|
|
var host = _configuration.GetConfigValue("MAIL_SERVER", "Smtp:Server", "defaultmailserver");
|
|
|
|
var port = _configuration.GetConfigValue("MAIL_PORT", "Smtp:Port", 25);
|
|
var fromAddress = _configuration.GetConfigValue("MAIL_ADDRESS", "Smtp:FromAddress", "defaultFromAddress");
|
|
var fromDisplayName = _configuration.GetConfigValue("MAIL_DISPLAY_NAME","Smtp:FromDisplayName", "eSuite MailService");
|
|
|
|
foreach (var address in emailRequest.To)
|
|
{
|
|
var message = new MailMessage
|
|
{
|
|
Body = null,
|
|
BodyEncoding = null,
|
|
BodyTransferEncoding = TransferEncoding.QuotedPrintable,
|
|
DeliveryNotificationOptions = DeliveryNotificationOptions.None,
|
|
From = new MailAddress(fromAddress!, fromDisplayName),
|
|
HeadersEncoding = null,
|
|
IsBodyHtml = false,
|
|
Priority = MailPriority.Normal,
|
|
Sender = null!,
|
|
Subject = null,
|
|
SubjectEncoding = null,
|
|
};
|
|
|
|
var user = await _userManagerRepository.GetUserByEmail(address.Email, cancellationToken) ??
|
|
throw new NotFoundException($"Unable to find user for e-mail {address.Email}");
|
|
|
|
message.To.Add(new MailAddress(address.Email, address.DisplayName));
|
|
|
|
await PrepareMessageBody(message, emailRequest, user.DomainId, cancellationToken);
|
|
|
|
using var client = _smtpClientFactory.CreateSmtpClient(host, port);
|
|
|
|
if (!string.IsNullOrEmpty(username))
|
|
{
|
|
var password = _configuration.GetConfigValue("MAIL_PASSWORD", "Smtp:Password", string.Empty);
|
|
client.Credentials = new NetworkCredential(username, password);
|
|
}
|
|
|
|
client.EnableSsl = _configuration.GetValue("Smtp:EnableSSL", false);
|
|
client.Timeout = _configuration.GetValue("Smtp:timeout", 30000);
|
|
|
|
#pragma warning disable SYSLIB0014
|
|
//There is no option be to use the ServicePointManager at the moment.
|
|
ServicePointManager.ServerCertificateValidationCallback = CertificateValidationCallBack!;
|
|
#pragma warning restore SYSLIB0014
|
|
|
|
try
|
|
{
|
|
await client.SendMailAsync(message, cancellationToken);
|
|
var auditUserDetails = new AuditUserDetails
|
|
{
|
|
UserDisplayName = "Mail service"
|
|
};
|
|
|
|
var fields = new Dictionary<string, Change>
|
|
{
|
|
["Address"] = new()
|
|
{
|
|
NewValue = address.Email,
|
|
},
|
|
["DisplayName"] = new()
|
|
{
|
|
NewValue = address.DisplayName
|
|
},
|
|
["EmailType"] = new()
|
|
{
|
|
NewValue = emailRequest.EmailType
|
|
},
|
|
["Subject"] = new()
|
|
{
|
|
NewValue = message.Subject
|
|
}
|
|
};
|
|
await _userManagerRepository.AddAdhocAuditEntry(auditUserDetails, AuditType.EmailSent, fields, cancellationToken);
|
|
}
|
|
catch (Exception e)
|
|
{
|
|
Console.WriteLine(e);
|
|
throw;
|
|
}
|
|
}
|
|
}
|
|
|
|
private async Task PrepareMessageBody(MailMessage message, MailRequest emailRequest, long domainId,
|
|
CancellationToken cancellationToken)
|
|
{
|
|
message.IsBodyHtml = true;
|
|
|
|
var mailTemplate =
|
|
await _mailServiceRepository.GetMailTemplate(domainId, emailRequest.EmailType, cancellationToken) ?? await _mailServiceRepository.GetMailTemplate(SunStrategyDomainId, emailRequest.EmailType,
|
|
cancellationToken) ??
|
|
throw new NotImplementedException($"{emailRequest.EmailType} not implemented");
|
|
|
|
message.Subject = mailTemplate.Subject;
|
|
message.Body = $"<html><head></head><body>{mailTemplate.TemplateDefinition}<body></html>";
|
|
|
|
SubstituteParameters(message, emailRequest);
|
|
|
|
}
|
|
|
|
private static void SubstituteParameters(MailMessage message, MailRequest emailRequest)
|
|
{
|
|
foreach (var parameter in emailRequest.Parameters)
|
|
message.Body = message.Body.Replace($"${parameter.Key}", parameter.Value, StringComparison.InvariantCultureIgnoreCase);
|
|
}
|
|
|
|
/// <summary>
|
|
/// https://docs.microsoft.com/en-us/previous-versions/office/developer/exchange-server-2010/dd633677(v=exchg.80)?redirectedfrom=MSDN
|
|
/// </summary>
|
|
/// <param name="sender"></param>
|
|
/// <param name="certificate"></param>
|
|
/// <param name="chain"></param>
|
|
/// <param name="sslPolicyErrors"></param>
|
|
/// <returns></returns>
|
|
private static bool CertificateValidationCallBack(
|
|
object sender,
|
|
System.Security.Cryptography.X509Certificates.X509Certificate certificate,
|
|
System.Security.Cryptography.X509Certificates.X509Chain chain,
|
|
System.Net.Security.SslPolicyErrors sslPolicyErrors)
|
|
{
|
|
// If the certificate is a valid, signed certificate, return true.
|
|
if (sslPolicyErrors == System.Net.Security.SslPolicyErrors.None) return true;
|
|
|
|
// If there are errors in the certificate chain, look at each error to determine the cause.
|
|
if ((sslPolicyErrors & System.Net.Security.SslPolicyErrors.RemoteCertificateChainErrors) != 0)
|
|
{
|
|
if (chain != null && chain.ChainStatus != null)
|
|
foreach (var status in chain.ChainStatus)
|
|
if (certificate.Subject == certificate.Issuer &&
|
|
status.Status == System.Security.Cryptography.X509Certificates.X509ChainStatusFlags
|
|
.UntrustedRoot)
|
|
{
|
|
// Self-signed certificates with an untrusted root are valid.
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
if (status.Status != System.Security.Cryptography.X509Certificates.X509ChainStatusFlags
|
|
.NoError)
|
|
// If there are any other errors in the certificate chain, the certificate is invalid,
|
|
// so the method returns false.
|
|
return false;
|
|
}
|
|
|
|
// When processing reaches this line, the only errors in the certificate chain are
|
|
// untrusted root errors for self-signed certificates. These certificates are valid
|
|
// for default Exchange server installations, so return true.
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
// In all other cases, return false.
|
|
return false;
|
|
}
|
|
}
|
|
} |