diff --git a/framework/Volo.Abp.sln b/framework/Volo.Abp.sln index 3c3336de1f..13ef057f97 100644 --- a/framework/Volo.Abp.sln +++ b/framework/Volo.Abp.sln @@ -242,9 +242,13 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Ldap", "src\Volo.A EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Ldap.Tests", "test\Volo.Abp.Ldap.Tests\Volo.Abp.Ldap.Tests.csproj", "{38FB8F75-426E-4265-8D0E-E121837B6FCC}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Dapper", "src\Volo.Abp.Dapper\Volo.Abp.Dapper.csproj", "{D863A3C3-CC1D-426F-BDD4-02E7AE2A3170}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Dapper", "src\Volo.Abp.Dapper\Volo.Abp.Dapper.csproj", "{D863A3C3-CC1D-426F-BDD4-02E7AE2A3170}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.Dapper.Tests", "test\Volo.Abp.Dapper.Tests\Volo.Abp.Dapper.Tests.csproj", "{E026A085-D881-4AE0-9F08-422AC3903BD7}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Volo.Abp.Dapper.Tests", "test\Volo.Abp.Dapper.Tests\Volo.Abp.Dapper.Tests.csproj", "{E026A085-D881-4AE0-9F08-422AC3903BD7}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.MailKit", "src\Volo.Abp.MailKit\Volo.Abp.MailKit.csproj", "{0CAED4CC-1CFD-4092-A326-AFE4DB3A9AB4}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Volo.Abp.MailKit.Tests", "test\Volo.Abp.MailKit.Tests\Volo.Abp.MailKit.Tests.csproj", "{70DD6E17-B98B-4B00-8F38-C489E291BB53}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -732,6 +736,14 @@ Global {E026A085-D881-4AE0-9F08-422AC3903BD7}.Debug|Any CPU.Build.0 = Debug|Any CPU {E026A085-D881-4AE0-9F08-422AC3903BD7}.Release|Any CPU.ActiveCfg = Release|Any CPU {E026A085-D881-4AE0-9F08-422AC3903BD7}.Release|Any CPU.Build.0 = Release|Any CPU + {0CAED4CC-1CFD-4092-A326-AFE4DB3A9AB4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {0CAED4CC-1CFD-4092-A326-AFE4DB3A9AB4}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0CAED4CC-1CFD-4092-A326-AFE4DB3A9AB4}.Release|Any CPU.ActiveCfg = Release|Any CPU + {0CAED4CC-1CFD-4092-A326-AFE4DB3A9AB4}.Release|Any CPU.Build.0 = Release|Any CPU + {70DD6E17-B98B-4B00-8F38-C489E291BB53}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {70DD6E17-B98B-4B00-8F38-C489E291BB53}.Debug|Any CPU.Build.0 = Debug|Any CPU + {70DD6E17-B98B-4B00-8F38-C489E291BB53}.Release|Any CPU.ActiveCfg = Release|Any CPU + {70DD6E17-B98B-4B00-8F38-C489E291BB53}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -857,6 +869,8 @@ Global {38FB8F75-426E-4265-8D0E-E121837B6FCC} = {447C8A77-E5F0-4538-8687-7383196D04EA} {D863A3C3-CC1D-426F-BDD4-02E7AE2A3170} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} {E026A085-D881-4AE0-9F08-422AC3903BD7} = {447C8A77-E5F0-4538-8687-7383196D04EA} + {0CAED4CC-1CFD-4092-A326-AFE4DB3A9AB4} = {5DF0E140-0513-4D0D-BE2E-3D4D85CD70E6} + {70DD6E17-B98B-4B00-8F38-C489E291BB53} = {447C8A77-E5F0-4538-8687-7383196D04EA} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {BB97ECF4-9A84-433F-A80B-2A3285BDD1D5} diff --git a/framework/src/Volo.Abp.MailKit/Volo.Abp.MailKit.csproj b/framework/src/Volo.Abp.MailKit/Volo.Abp.MailKit.csproj new file mode 100644 index 0000000000..8af1220e76 --- /dev/null +++ b/framework/src/Volo.Abp.MailKit/Volo.Abp.MailKit.csproj @@ -0,0 +1,24 @@ + + + + + + netstandard2.0 + Volo.Abp.MailKit + Volo.Abp.MailKit + $(AssetTargetFallback);portable-net45+win8+wp8+wpa81; + false + false + false + + + + + + + + + + + + \ No newline at end of file diff --git a/framework/src/Volo.Abp.MailKit/Volo/Abp/MailKit/AbpMailKitModule.cs b/framework/src/Volo.Abp.MailKit/Volo/Abp/MailKit/AbpMailKitModule.cs new file mode 100644 index 0000000000..9027172cf4 --- /dev/null +++ b/framework/src/Volo.Abp.MailKit/Volo/Abp/MailKit/AbpMailKitModule.cs @@ -0,0 +1,11 @@ +using Volo.Abp.Emailing; +using Volo.Abp.Modularity; + +namespace Volo.Abp.MailKit +{ + [DependsOn(typeof(AbpEmailingModule))] + public class AbpMailKitModule : AbpModule + { + + } +} diff --git a/framework/src/Volo.Abp.MailKit/Volo/Abp/MailKit/AbpMailKitOptions.cs b/framework/src/Volo.Abp.MailKit/Volo/Abp/MailKit/AbpMailKitOptions.cs new file mode 100644 index 0000000000..fd25f0f7f7 --- /dev/null +++ b/framework/src/Volo.Abp.MailKit/Volo/Abp/MailKit/AbpMailKitOptions.cs @@ -0,0 +1,9 @@ +using MailKit.Security; + +namespace Volo.Abp.MailKit +{ + public class AbpMailKitOptions + { + public SecureSocketOptions? SecureSocketOption { get; set; } + } +} diff --git a/framework/src/Volo.Abp.MailKit/Volo/Abp/MailKit/IMailKitSmtpEmailSender.cs b/framework/src/Volo.Abp.MailKit/Volo/Abp/MailKit/IMailKitSmtpEmailSender.cs new file mode 100644 index 0000000000..54514814fc --- /dev/null +++ b/framework/src/Volo.Abp.MailKit/Volo/Abp/MailKit/IMailKitSmtpEmailSender.cs @@ -0,0 +1,11 @@ +using System.Threading.Tasks; +using MailKit.Net.Smtp; +using Volo.Abp.Emailing; + +namespace Volo.Abp.MailKit +{ + public interface IMailKitSmtpEmailSender: IEmailSender + { + Task BuildClientAsync(); + } +} diff --git a/framework/src/Volo.Abp.MailKit/Volo/Abp/MailKit/MailKitSmtpEmailSender.cs b/framework/src/Volo.Abp.MailKit/Volo/Abp/MailKit/MailKitSmtpEmailSender.cs new file mode 100644 index 0000000000..426be33c80 --- /dev/null +++ b/framework/src/Volo.Abp.MailKit/Volo/Abp/MailKit/MailKitSmtpEmailSender.cs @@ -0,0 +1,99 @@ +using System.Net.Mail; +using System.Threading.Tasks; +using Volo.Abp.BackgroundJobs; +using Volo.Abp.DependencyInjection; +using Volo.Abp.Emailing; +using Volo.Abp.Emailing.Smtp; +using MailKit.Security; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Options; +using MimeKit; +using Volo.Abp.Threading; +using SmtpClient = MailKit.Net.Smtp.SmtpClient; + +namespace Volo.Abp.MailKit +{ + [Dependency(ServiceLifetime.Transient, ReplaceServices = true)] + public class MailKitSmtpEmailSender : EmailSenderBase, IMailKitSmtpEmailSender + { + protected AbpMailKitOptions AbpMailKitOptions { get; } + + protected ISmtpEmailSenderConfiguration SmtpConfiguration { get; } + + public MailKitSmtpEmailSender(ISmtpEmailSenderConfiguration smtpConfiguration, + IBackgroundJobManager backgroundJobManager, + IOptions abpMailKitConfiguration) + : base(smtpConfiguration, backgroundJobManager) + { + AbpMailKitOptions = abpMailKitConfiguration.Value; + SmtpConfiguration = smtpConfiguration; + } + + protected override async Task SendEmailAsync(MailMessage mail) + { + using (var client = await BuildClientAsync()) + { + var message = MimeMessage.CreateFromMailMessage(mail); + await client.SendAsync(message); + await client.DisconnectAsync(true); + } + } + + protected override void SendEmail(MailMessage mail) + { + using (var client = AsyncHelper.RunSync(BuildClientAsync)) + { + var message = MimeMessage.CreateFromMailMessage(mail); + client.Send(message); + client.Disconnect(true); + } + } + + public async Task BuildClientAsync() + { + var client = new SmtpClient(); + + try + { + await ConfigureClient(client); + return client; + } + catch + { + client.Dispose(); + throw; + } + } + + protected virtual async Task ConfigureClient(SmtpClient client) + { + client.Connect( + await SmtpConfiguration.GetHostAsync(), + await SmtpConfiguration.GetPortAsync(), + await GetSecureSocketOption() + ); + + if (await SmtpConfiguration.GetUseDefaultCredentialsAsync()) + { + return; + } + + client.Authenticate( + await SmtpConfiguration.GetUserNameAsync(), + await SmtpConfiguration.GetPasswordAsync() + ); + } + + protected virtual async Task GetSecureSocketOption() + { + if (AbpMailKitOptions.SecureSocketOption.HasValue) + { + return AbpMailKitOptions.SecureSocketOption.Value; + } + + return await SmtpConfiguration.GetEnableSslAsync() + ? SecureSocketOptions.SslOnConnect + : SecureSocketOptions.StartTlsWhenAvailable; + } + } +} diff --git a/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/AbpEmailingTestModule.cs b/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/AbpEmailingTestModule.cs index 831258c5d5..2746da3847 100644 --- a/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/AbpEmailingTestModule.cs +++ b/framework/test/Volo.Abp.Emailing.Tests/Volo/Abp/Emailing/AbpEmailingTestModule.cs @@ -1,4 +1,5 @@ -using Volo.Abp.Emailing.Localization; +using Volo.Abp.Autofac; +using Volo.Abp.Emailing.Localization; using Volo.Abp.Localization; using Volo.Abp.Modularity; using Volo.Abp.VirtualFileSystem; @@ -7,6 +8,7 @@ namespace Volo.Abp.Emailing { [DependsOn( typeof(AbpEmailingModule), + typeof(AbpAutofacModule), typeof(AbpTestBaseModule))] public class AbpEmailingTestModule : AbpModule { diff --git a/framework/test/Volo.Abp.MailKit.Tests/Volo.Abp.MailKit.Tests.csproj b/framework/test/Volo.Abp.MailKit.Tests/Volo.Abp.MailKit.Tests.csproj new file mode 100644 index 0000000000..17097b1bf0 --- /dev/null +++ b/framework/test/Volo.Abp.MailKit.Tests/Volo.Abp.MailKit.Tests.csproj @@ -0,0 +1,20 @@ + + + + netcoreapp2.2 + latest + true + false + false + false + + + + + + + + + + + \ No newline at end of file diff --git a/framework/test/Volo.Abp.MailKit.Tests/Volo/Abp/MailKit/AbpMailKitTestModule.cs b/framework/test/Volo.Abp.MailKit.Tests/Volo/Abp/MailKit/AbpMailKitTestModule.cs new file mode 100644 index 0000000000..b0d6e9f7da --- /dev/null +++ b/framework/test/Volo.Abp.MailKit.Tests/Volo/Abp/MailKit/AbpMailKitTestModule.cs @@ -0,0 +1,13 @@ +using Volo.Abp.Autofac; +using Volo.Abp.Modularity; + +namespace Volo.Abp.MailKit +{ + [DependsOn( + typeof(AbpMailKitModule), + typeof(AbpAutofacModule), + typeof(AbpTestBaseModule))] + public class AbpMailKitTestModule :AbpModule + { + } +} diff --git a/framework/test/Volo.Abp.MailKit.Tests/Volo/Abp/MailKit/MailKitSmtpEmailSender_Tests.cs b/framework/test/Volo.Abp.MailKit.Tests/Volo/Abp/MailKit/MailKitSmtpEmailSender_Tests.cs new file mode 100644 index 0000000000..8404b8df4e --- /dev/null +++ b/framework/test/Volo.Abp.MailKit.Tests/Volo/Abp/MailKit/MailKitSmtpEmailSender_Tests.cs @@ -0,0 +1,48 @@ +using System.Net.Mail; +using System.Threading.Tasks; +using NSubstitute; +using Volo.Abp.BackgroundJobs; +using Volo.Abp.Emailing.Smtp; +using Xunit; + +namespace Volo.Abp.MailKit +{ + //Tests are commented because those tests can pass only when a true email configuration is set. + public class MailKitSmtpEmailSender_Tests : AbpIntegratedTest + { + //[Fact] + public async Task ShouldSendMailMessageAsync() + { + var mailSender = CreateMailKitEmailSender(); + var mailMessage = new MailMessage("from_mail_address@asd.com", "to_mail_address@asd.com", "subject", "body") + { IsBodyHtml = true }; + + await mailSender.SendAsync(mailMessage); + } + + //[Fact] + public void ShouldSendMailMessage() + { + var mailSender = CreateMailKitEmailSender(); + var mailMessage = new MailMessage("from_mail_address@asd.com", "to_mail_address@asd.com", "subject", "body") + { IsBodyHtml = true }; + + mailSender.Send(mailMessage); + } + + private static MailKitSmtpEmailSender CreateMailKitEmailSender() + { + var mailConfig = Substitute.For(); + var bgJob = Substitute.For(); + + mailConfig.GetHostAsync().Returns(Task.FromResult("stmp_server_name")); + mailConfig.GetUserNameAsync().Returns(Task.FromResult("mail_server_user_name")); + mailConfig.GetPasswordAsync().Returns(Task.FromResult("mail_server_password")); + mailConfig.GetPortAsync().Returns(Task.FromResult(587)); + mailConfig.GetEnableSslAsync().Returns(Task.FromResult(false)); + + var mailSender = new MailKitSmtpEmailSender(mailConfig, bgJob, null); + return mailSender; + } + } +} diff --git a/modules/account/src/Volo.Abp.Account.Application/Volo.Abp.Account.Application.csproj b/modules/account/src/Volo.Abp.Account.Application/Volo.Abp.Account.Application.csproj index 097e1f6c55..14f9c8f991 100644 --- a/modules/account/src/Volo.Abp.Account.Application/Volo.Abp.Account.Application.csproj +++ b/modules/account/src/Volo.Abp.Account.Application/Volo.Abp.Account.Application.csproj @@ -13,7 +13,6 @@ - diff --git a/modules/account/src/Volo.Abp.Account.Application/Volo/Abp/Account/AbpAccountApplicationModule.cs b/modules/account/src/Volo.Abp.Account.Application/Volo/Abp/Account/AbpAccountApplicationModule.cs index 8fecc2d4e0..601ce9a3d3 100644 --- a/modules/account/src/Volo.Abp.Account.Application/Volo/Abp/Account/AbpAccountApplicationModule.cs +++ b/modules/account/src/Volo.Abp.Account.Application/Volo/Abp/Account/AbpAccountApplicationModule.cs @@ -1,5 +1,4 @@ -using Volo.Abp.Emailing; -using Volo.Abp.Identity; +using Volo.Abp.Identity; using Volo.Abp.Modularity; using Volo.Abp.UI.Navigation.Urls; using Volo.Abp.UI.Navigation; @@ -9,7 +8,6 @@ namespace Volo.Abp.Account { [DependsOn( typeof(AbpAccountApplicationContractsModule), - typeof(AbpEmailingModule), typeof(AbpIdentityApplicationModule), typeof(AbpUiNavigationModule) )] diff --git a/nupkg/common.ps1 b/nupkg/common.ps1 index eaea068daa..24a73876a7 100644 --- a/nupkg/common.ps1 +++ b/nupkg/common.ps1 @@ -81,6 +81,7 @@ $projects = ( "framework/src/Volo.Abp.Json", "framework/src/Volo.Abp.Ldap", "framework/src/Volo.Abp.Localization.Abstractions", + "framework/src/Volo.Abp.MailKit", "framework/src/Volo.Abp.Localization", "framework/src/Volo.Abp.MemoryDb", "framework/src/Volo.Abp.MongoDB",