From 31dfbe1ccf61afaac8b544f406eba5cccfba4b78 Mon Sep 17 00:00:00 2001 From: Tudor Stanciu Date: Thu, 19 Jan 2023 19:45:00 +0200 Subject: [PATCH] Added MailKit --- Correo.sln | 17 +++-- dependencies.props | 1 + .../Extensions/ModelExtensions.cs | 11 ++++ .../Correo.Application.csproj | 1 - .../DependencyInjectionExtensions.cs | 2 - src/Correo.MailKit/Correo.MailKit.csproj | 18 ++++++ .../DependencyInjectionExtensions.cs | 16 +++++ .../Extensions/ModelExtensions.cs | 35 +++++++++++ src/Correo.MailKit/MailKitSmtpClient.cs | 62 +++++++++++++++++++ .../Models/SmtpClientOptions.cs | 19 ++++++ .../DependencyInjectionExtensions.cs | 4 +- .../Extensions/ModelExtensions.cs | 8 +-- .../{SmtpClientMailer.cs => NetSmtpClient.cs} | 7 ++- src/Correo/Correo.csproj | 2 + src/Correo/Extensions/SmtpExtensions.cs | 30 +++++++++ src/Correo/Extensions/StartupExtensions.cs | 3 + src/Correo/appsettings.json | 3 +- 17 files changed, 219 insertions(+), 20 deletions(-) create mode 100644 src/Correo.Abstractions/Extensions/ModelExtensions.cs create mode 100644 src/Correo.MailKit/Correo.MailKit.csproj create mode 100644 src/Correo.MailKit/DependencyInjectionExtensions.cs create mode 100644 src/Correo.MailKit/Extensions/ModelExtensions.cs create mode 100644 src/Correo.MailKit/MailKitSmtpClient.cs create mode 100644 src/Correo.MailKit/Models/SmtpClientOptions.cs rename src/Correo.SmtpClient/{SmtpClientMailer.cs => NetSmtpClient.cs} (89%) create mode 100644 src/Correo/Extensions/SmtpExtensions.cs diff --git a/Correo.sln b/Correo.sln index 9e256cb..1baef48 100644 --- a/Correo.sln +++ b/Correo.sln @@ -18,15 +18,17 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "solution items", "solution README.md = README.md EndProjectSection EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Correo.Application", "src\Correo.Application\Correo.Application.csproj", "{3AEA1AB4-F068-4C39-A173-AD65F3F8E2F2}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Correo.Application", "src\Correo.Application\Correo.Application.csproj", "{3AEA1AB4-F068-4C39-A173-AD65F3F8E2F2}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Correo.PublishedLanguage", "src\Correo.PublishedLanguage\Correo.PublishedLanguage.csproj", "{DA47BCEE-9AE7-4F20-A04F-5866966503C5}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Correo.PublishedLanguage", "src\Correo.PublishedLanguage\Correo.PublishedLanguage.csproj", "{DA47BCEE-9AE7-4F20-A04F-5866966503C5}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Correo.Domain", "src\Correo.Domain\Correo.Domain.csproj", "{A2D2694C-AB68-49B0-B4B0-94BBFF48C043}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Correo.Domain", "src\Correo.Domain\Correo.Domain.csproj", "{A2D2694C-AB68-49B0-B4B0-94BBFF48C043}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Correo.SmtpClient", "src\Correo.SmtpClient\Correo.SmtpClient.csproj", "{76793477-8219-4FFB-AA08-3F2224EC4968}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Correo.SmtpClient", "src\Correo.SmtpClient\Correo.SmtpClient.csproj", "{76793477-8219-4FFB-AA08-3F2224EC4968}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Correo.Abstractions", "src\Correo.Abstractions\Correo.Abstractions.csproj", "{ED8048DC-8509-4085-97F0-F9D9A59A689A}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Correo.Abstractions", "src\Correo.Abstractions\Correo.Abstractions.csproj", "{ED8048DC-8509-4085-97F0-F9D9A59A689A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Correo.MailKit", "src\Correo.MailKit\Correo.MailKit.csproj", "{325B77E1-D752-4578-8BF7-793905C38DCD}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -58,6 +60,10 @@ Global {ED8048DC-8509-4085-97F0-F9D9A59A689A}.Debug|Any CPU.Build.0 = Debug|Any CPU {ED8048DC-8509-4085-97F0-F9D9A59A689A}.Release|Any CPU.ActiveCfg = Release|Any CPU {ED8048DC-8509-4085-97F0-F9D9A59A689A}.Release|Any CPU.Build.0 = Release|Any CPU + {325B77E1-D752-4578-8BF7-793905C38DCD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {325B77E1-D752-4578-8BF7-793905C38DCD}.Debug|Any CPU.Build.0 = Debug|Any CPU + {325B77E1-D752-4578-8BF7-793905C38DCD}.Release|Any CPU.ActiveCfg = Release|Any CPU + {325B77E1-D752-4578-8BF7-793905C38DCD}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -69,6 +75,7 @@ Global {A2D2694C-AB68-49B0-B4B0-94BBFF48C043} = {245E2FBE-DFDF-40B4-94B7-5DDA216E58AD} {76793477-8219-4FFB-AA08-3F2224EC4968} = {245E2FBE-DFDF-40B4-94B7-5DDA216E58AD} {ED8048DC-8509-4085-97F0-F9D9A59A689A} = {245E2FBE-DFDF-40B4-94B7-5DDA216E58AD} + {325B77E1-D752-4578-8BF7-793905C38DCD} = {245E2FBE-DFDF-40B4-94B7-5DDA216E58AD} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {86FCF989-26FC-41E9-8A23-9485606D619D} diff --git a/dependencies.props b/dependencies.props index ce84682..03a5ea3 100644 --- a/dependencies.props +++ b/dependencies.props @@ -8,5 +8,6 @@ 12.0.0 9.0.0 6.0.30 + 3.4.3 \ No newline at end of file diff --git a/src/Correo.Abstractions/Extensions/ModelExtensions.cs b/src/Correo.Abstractions/Extensions/ModelExtensions.cs new file mode 100644 index 0000000..a5f3acb --- /dev/null +++ b/src/Correo.Abstractions/Extensions/ModelExtensions.cs @@ -0,0 +1,11 @@ +using System.Collections.Generic; +using System.Linq; + +namespace Correo.Abstractions.Extensions +{ + public static class ModelExtensions + { + public static string Log(this IEnumerable addresses) + => addresses != null ? string.Join(',', addresses.Select(z => z.Address)) : string.Empty; + } +} diff --git a/src/Correo.Application/Correo.Application.csproj b/src/Correo.Application/Correo.Application.csproj index 882d546..abbbfb9 100644 --- a/src/Correo.Application/Correo.Application.csproj +++ b/src/Correo.Application/Correo.Application.csproj @@ -14,7 +14,6 @@ - diff --git a/src/Correo.Application/DependencyInjectionExtensions.cs b/src/Correo.Application/DependencyInjectionExtensions.cs index 2a73b8a..0fd3631 100644 --- a/src/Correo.Application/DependencyInjectionExtensions.cs +++ b/src/Correo.Application/DependencyInjectionExtensions.cs @@ -1,5 +1,4 @@ using Correo.Domain.Models; -using Correo.SmtpClient; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; @@ -10,7 +9,6 @@ namespace Correo.Application public static void AddApplicationServices(this IServiceCollection services, IConfiguration configuration) { services.Configure(configuration.GetSection("DefaultSender")); - services.AddSmtpClientServices(configuration.GetSection("SmtpClient")); } } } diff --git a/src/Correo.MailKit/Correo.MailKit.csproj b/src/Correo.MailKit/Correo.MailKit.csproj new file mode 100644 index 0000000..3ae22fb --- /dev/null +++ b/src/Correo.MailKit/Correo.MailKit.csproj @@ -0,0 +1,18 @@ + + + + net6.0 + + + + + + + + + + + + + + diff --git a/src/Correo.MailKit/DependencyInjectionExtensions.cs b/src/Correo.MailKit/DependencyInjectionExtensions.cs new file mode 100644 index 0000000..8e02510 --- /dev/null +++ b/src/Correo.MailKit/DependencyInjectionExtensions.cs @@ -0,0 +1,16 @@ +using Correo.Abstractions; +using Correo.MailKit.Models; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; + +namespace Correo.MailKit +{ + public static class DependencyInjectionExtensions + { + public static void AddMailKitSmtpClient(this IServiceCollection services, IConfigurationSection configuration) + { + services.Configure(configuration); + services.AddTransient(); + } + } +} \ No newline at end of file diff --git a/src/Correo.MailKit/Extensions/ModelExtensions.cs b/src/Correo.MailKit/Extensions/ModelExtensions.cs new file mode 100644 index 0000000..ace04ae --- /dev/null +++ b/src/Correo.MailKit/Extensions/ModelExtensions.cs @@ -0,0 +1,35 @@ +using Correo.Abstractions; +using MimeKit; +using System.Collections.Generic; + +namespace Correo.MailKit.Extensions +{ + internal static class ModelExtensions + { + private static MailboxAddress ToMailboxAddress(this EmailMessage.MailAddress address) + => new MailboxAddress(address.DisplayName, address.Address); + + private static void AddRange(this InternetAddressList list, IEnumerable addresses) + { + foreach (var item in addresses) + list.Add(item.ToMailboxAddress()); + } + + public static MimeMessage ToMailMessage(this EmailMessage message) + { + var subtype = message.IsBodyHtml ? "html" : "plain"; + var mailMessage = new MimeMessage() + { + Subject = message.Subject, + Body = new TextPart(subtype) { Text = message.Body } + }; + + mailMessage.From.Add(message.From.ToMailboxAddress()); + mailMessage.To.AddRange(message.To); + mailMessage.Cc.AddRange(message.Cc); + mailMessage.Bcc.AddRange(message.Bcc); + + return mailMessage; + } + } +} diff --git a/src/Correo.MailKit/MailKitSmtpClient.cs b/src/Correo.MailKit/MailKitSmtpClient.cs new file mode 100644 index 0000000..ba47158 --- /dev/null +++ b/src/Correo.MailKit/MailKitSmtpClient.cs @@ -0,0 +1,62 @@ +using Correo.Abstractions; +using Correo.Abstractions.Extensions; +using Correo.MailKit.Extensions; +using Correo.MailKit.Models; +using MailKit.Net.Smtp; +using Microsoft.Extensions.Logging; +using Microsoft.Extensions.Options; +using System; +using System.Net; +using System.Threading; +using System.Threading.Tasks; + +namespace Correo.MailKit +{ + internal class MailKitSmtpClient : IMailer, IDisposable + { + private readonly IOptions _optionsAccessor; + private readonly SmtpClient _smtpClient; + private readonly ILogger _logger; + + public MailKitSmtpClient(IOptions optionsAccessor, ILogger logger) + { + _optionsAccessor = optionsAccessor; + _logger = logger; + + var options = _optionsAccessor.Value; + + _smtpClient = new SmtpClient(); + _smtpClient.Connect(options.Server, options.Port, options.EnableSsl); + + if (options.UseAuthentication) + _smtpClient.Authenticate(options.Authentication.UserName, options.Authentication.Password); + + if (options.TrustServer) + ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true; + } + + public void Dispose() + { + _smtpClient?.Disconnect(true); + _smtpClient?.Dispose(); + GC.SuppressFinalize(this); + } + + public void SendEmail(EmailMessage message) + { + var mailMessage = message.ToMailMessage(); + _smtpClient.Send(mailMessage); + Log(message); + } + + public async Task SendEmailAsync(EmailMessage message, CancellationToken token = default) + { + var mailMessage = message.ToMailMessage(); + await _smtpClient.SendAsync(mailMessage, token); + Log(message); + } + + private void Log(EmailMessage message) + => _logger.LogInformation($"Email sent: Subject: {message.Subject}; From: {message.From.Address}; To: {message.To.Log()}; Cc: {message.Cc.Log()}; Bcc: {message.Bcc.Log()};"); + } +} diff --git a/src/Correo.MailKit/Models/SmtpClientOptions.cs b/src/Correo.MailKit/Models/SmtpClientOptions.cs new file mode 100644 index 0000000..b6b074e --- /dev/null +++ b/src/Correo.MailKit/Models/SmtpClientOptions.cs @@ -0,0 +1,19 @@ +namespace Correo.MailKit.Models +{ + public record SmtpClientOptions + { + public string Server { get; init; } + public int Port { get; init; } + public bool EnableSsl { get; init; } + public bool UseAuthentication { get; init; } + public bool TrustServer { get; init; } + public AuthenticationOptions Authentication { get; init; } + + public record AuthenticationOptions + { + public string UserName { get; init; } + public string Domain { get; init; } + public string Password { get; init; } + } + } +} diff --git a/src/Correo.SmtpClient/DependencyInjectionExtensions.cs b/src/Correo.SmtpClient/DependencyInjectionExtensions.cs index c65fbc4..f45929c 100644 --- a/src/Correo.SmtpClient/DependencyInjectionExtensions.cs +++ b/src/Correo.SmtpClient/DependencyInjectionExtensions.cs @@ -7,10 +7,10 @@ namespace Correo.SmtpClient { public static class DependencyInjectionExtensions { - public static void AddSmtpClientServices(this IServiceCollection services, IConfigurationSection configuration) + public static void AddNetSmtpClient(this IServiceCollection services, IConfigurationSection configuration) { services.Configure(configuration); - services.AddTransient(); + services.AddTransient(); } } } \ No newline at end of file diff --git a/src/Correo.SmtpClient/Extensions/ModelExtensions.cs b/src/Correo.SmtpClient/Extensions/ModelExtensions.cs index 628394a..a9b43c6 100644 --- a/src/Correo.SmtpClient/Extensions/ModelExtensions.cs +++ b/src/Correo.SmtpClient/Extensions/ModelExtensions.cs @@ -1,19 +1,15 @@ using Correo.Abstractions; using System.Collections.Generic; -using System.Linq; using System.Net.Mail; namespace Correo.SmtpClient.Extensions { internal static class ModelExtensions { - public static string Log(this IEnumerable addresses) - => addresses != null ? string.Join(',', addresses.Select(z => z.Address)) : string.Empty; - - public static MailAddress ToMailAddress(this EmailMessage.MailAddress address) + private static MailAddress ToMailAddress(this EmailMessage.MailAddress address) => new MailAddress(address.Address, address.DisplayName); - public static void AddRange(this MailAddressCollection collection, IEnumerable addresses) + private static void AddRange(this MailAddressCollection collection, IEnumerable addresses) { foreach (var item in addresses) collection.Add(item.ToMailAddress()); diff --git a/src/Correo.SmtpClient/SmtpClientMailer.cs b/src/Correo.SmtpClient/NetSmtpClient.cs similarity index 89% rename from src/Correo.SmtpClient/SmtpClientMailer.cs rename to src/Correo.SmtpClient/NetSmtpClient.cs index 4ec4945..732d678 100644 --- a/src/Correo.SmtpClient/SmtpClientMailer.cs +++ b/src/Correo.SmtpClient/NetSmtpClient.cs @@ -1,4 +1,5 @@ using Correo.Abstractions; +using Correo.Abstractions.Extensions; using Correo.SmtpClient.Extensions; using Correo.SmtpClient.Models; using Microsoft.Extensions.Logging; @@ -10,13 +11,13 @@ using System.Threading.Tasks; namespace Correo.SmtpClient { - public class SmtpClientMailer : IMailer, IDisposable + internal class NetSmtpClient : IMailer, IDisposable { private readonly IOptions _optionsAccessor; private readonly System.Net.Mail.SmtpClient _smtpClient; - private readonly ILogger _logger; + private readonly ILogger _logger; - public SmtpClientMailer(IOptions optionsAccessor, ILogger logger) + public NetSmtpClient(IOptions optionsAccessor, ILogger logger) { _optionsAccessor = optionsAccessor; _logger = logger; diff --git a/src/Correo/Correo.csproj b/src/Correo/Correo.csproj index 47d3913..c2bb7f9 100644 --- a/src/Correo/Correo.csproj +++ b/src/Correo/Correo.csproj @@ -16,6 +16,8 @@ + + diff --git a/src/Correo/Extensions/SmtpExtensions.cs b/src/Correo/Extensions/SmtpExtensions.cs new file mode 100644 index 0000000..67cca23 --- /dev/null +++ b/src/Correo/Extensions/SmtpExtensions.cs @@ -0,0 +1,30 @@ +using Correo.MailKit; +using Correo.SmtpClient; +using Microsoft.Extensions.Configuration; +using Microsoft.Extensions.DependencyInjection; +using System; + +namespace Correo.Extensions +{ + public static class SmtpExtensions + { + public static void AddSmtpClient(this IServiceCollection services, IConfiguration configuration) + { + var configSection = configuration.GetSection("SmtpClient"); + var mediator = configSection.GetValue("Mediator", ".NET"); + + if (mediator.Equals(".NET", StringComparison.InvariantCultureIgnoreCase)) + { + services.AddNetSmtpClient(configSection); + } + else if (mediator.Equals("MailKit", StringComparison.InvariantCultureIgnoreCase)) + { + services.AddMailKitSmtpClient(configSection); + } + else + { + throw new NotImplementedException($"SmtpClient:Mediator={mediator} is not implemented."); + } + } + } +} diff --git a/src/Correo/Extensions/StartupExtensions.cs b/src/Correo/Extensions/StartupExtensions.cs index ab29ef6..8da630a 100644 --- a/src/Correo/Extensions/StartupExtensions.cs +++ b/src/Correo/Extensions/StartupExtensions.cs @@ -29,6 +29,9 @@ namespace Correo.Extensions // Messaging services.AddMessaging(configuration); + // Add SMTP client + services.AddSmtpClient(configuration); + // Application services services.AddApplicationServices(configuration); } diff --git a/src/Correo/appsettings.json b/src/Correo/appsettings.json index 7d867b5..3539786 100644 --- a/src/Correo/appsettings.json +++ b/src/Correo/appsettings.json @@ -30,14 +30,15 @@ "Name": "HomeLab" }, "SmtpClient": { + "Mediator": ".NET", //.NET, MailKit "Server": "smtp.gmail.com", "Port": "587", + "UseAuthentication": true, "Authentication": { "UserName": "@gmail.com", "Domain": "", "Password": "********" }, - "UseAuthentication": true, "EnableSsl": true, "TrustServer": false }