├── .gitattributes ├── .gitignore ├── .vscode ├── launch.json ├── tasks.json └── tasks.json.old ├── LICENSE ├── NullDesk.Mailer.sln ├── NullDesk.Mailer.sln.GhostDoc.user.dic ├── README.md ├── deploy.ps1 ├── samples └── mailer-cli │ ├── .vscode │ ├── launch.json │ └── tasks.json │ └── mailer │ ├── App_Data │ ├── Attachments │ │ └── test.txt │ └── Templates │ │ ├── template1.html │ │ └── template1.txt │ ├── Commands │ ├── CliCommand.cs │ ├── DropDb.cs │ ├── SendMail.cs │ ├── SendSimpleMessage.cs │ └── SendTemplateMessage.cs │ ├── Configuration │ ├── MailHistoryDbSettings.cs │ └── TestMessageSettings.cs │ ├── Extensions │ └── AnsiColorExtensions.cs │ ├── Program.cs │ ├── Properties │ └── launchSettings.json │ ├── Startup.cs │ ├── appsettings.json │ └── mailer.csproj ├── src ├── NullDesk.Extensions.Mailer.Core │ ├── Extensions │ │ ├── AttachmentFileExtensions.cs │ │ ├── DependencyInjectionExtensions.cs │ │ ├── DirectoryInfoExtensions.cs │ │ ├── FileSystemTemplateBodyExtensions.cs │ │ ├── MailerFactoryExtensions.cs │ │ ├── StreamExtensions.cs │ │ └── StringExtensions.cs │ ├── Fluent │ │ ├── Extensions │ │ │ ├── MailerContentBodyFluentExtensions.cs │ │ │ ├── MailerMessageFluentExtensions.cs │ │ │ ├── MessageRecipientFluentExtensions.cs │ │ │ └── MessageSenderFluentExtensions.cs │ │ ├── Infrastrucutre │ │ │ ├── BuilderContentBodyContext.cs │ │ │ ├── BuilderContext.cs │ │ │ ├── BuilderRecipientContext.cs │ │ │ ├── IBuilderContext.cs │ │ │ └── IBuilderStepsCompleted.cs │ │ ├── MessageBuider.cs │ │ ├── MessageBuilder.BuildContentStep.cs │ │ ├── MessageBuilder.BuildFromStep.cs │ │ ├── MessageBuilder.BuildPostContentStep.cs │ │ ├── MessageBuilder.BuildRecipientsStep.cs │ │ ├── MessageBuilder.BuildReplyToStep.cs │ │ └── MessageBuilder.BuildSubjectStep.cs │ ├── HistoryModel │ │ ├── IHistoryStore.cs │ │ ├── IHistoryStoreSettings.cs │ │ ├── InMemoryHistoryStore.cs │ │ ├── NullHistoryStore.cs │ │ └── StandardHistoryStoreSettings.cs │ ├── Infrastructure │ │ ├── AsyncLock.cs │ │ └── AsyncSemaphore.cs │ ├── MailerModel │ │ ├── IMailer.cs │ │ ├── IMailerFactory.cs │ │ ├── IMailerSettings.cs │ │ ├── IProxyMailer.cs │ │ ├── IProxyMailerSettings.cs │ │ ├── Mailer.cs │ │ ├── MailerFactory.cs │ │ ├── NullMailer.cs │ │ ├── NullMailerSettings.cs │ │ ├── SafetyMailer.cs │ │ ├── SafetyMailerSettings.cs │ │ └── SmtpMailerSettings.cs │ ├── MessageModel │ │ ├── AttachmentStreamJsonConverter.cs │ │ ├── ContentBody.cs │ │ ├── DeliveryItem.cs │ │ ├── DeliverySummary.cs │ │ ├── IMessageAddress.cs │ │ ├── IMessageBody.cs │ │ ├── MailerMessage.cs │ │ ├── MessageBodyJsonConverter.cs │ │ ├── MessageRecipient.cs │ │ ├── MessageSender.cs │ │ └── TemplateBody.cs │ └── NullDesk.Extensions.Mailer.Core.csproj ├── NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer │ ├── DependencyInjectionExtensions.cs │ ├── Migrations │ │ ├── 20170530063924_Initial.Designer.cs │ │ ├── 20170530063924_Initial.cs │ │ ├── 20170604221538_SourceAppName.Designer.cs │ │ ├── 20170604221538_SourceAppName.cs │ │ ├── 20170711052447_ResizeExceptionMessage.Designer.cs │ │ ├── 20170711052447_ResizeExceptionMessage.cs │ │ └── SqlHistoryContextModelSnapshot.cs │ ├── NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer.csproj │ ├── SqlEntityHistoryStoreSettings.cs │ ├── SqlHistoryContext.cs │ └── SqlHistoryContextFactory.cs ├── NullDesk.Extensions.Mailer.History.EntityFramework │ ├── DependencyInjectionExtensions.cs │ ├── EntityHistoryStore.cs │ ├── EntityHistoryStoreSettings.cs │ ├── HistoryContext.cs │ ├── HistoryDeliveryItem.cs │ └── NullDesk.Extensions.Mailer.History.EntityFramework.csproj ├── NullDesk.Extensions.Mailer.MailKit │ ├── Authentication │ │ ├── IMkSmtpAuthenticator.cs │ │ ├── MkSmtpAccessTokenAuthenticator.cs │ │ ├── MkSmtpBasicAuthenticator.cs │ │ ├── MkSmtpCredentialsAuthenticator.cs │ │ └── NullAuthenticator.cs │ ├── Extensions │ │ ├── BodyBuilderExtensions.cs │ │ ├── DependencyInjectionExtensions.cs │ │ └── MailerFactoryExtensions.cs │ ├── MailerModel │ │ ├── MkFileTemplateSettings.cs │ │ ├── MkSmtpAuthenticationSettings.cs │ │ ├── MkSmtpMailer.cs │ │ └── MkSmtpMailerSettings.cs │ └── NullDesk.Extensions.Mailer.MailKit.csproj └── NullDesk.Extensions.Mailer.SendGrid │ ├── Extensions │ ├── DependencyInjectionExtensions.cs │ └── MailerFactoryExtensions.cs │ ├── MailerModel │ ├── SendGridMailer.cs │ └── SendGridMailerSettings.cs │ └── NullDesk.Extensions.Mailer.SendGrid.csproj ├── test ├── NullDesk.Extensions.Mailer.Core.Tests │ ├── HistorySerializationTests.cs │ ├── Infrastructure │ │ └── HistorySerializationFixture.cs │ ├── MailerFactoryTests.cs │ ├── MessageBuidler.BuildFromStep.BuildFromWithDisplayStep.Tests.cs │ ├── MessageBuidler.BuildFromStep.Tests.cs │ ├── MessageBuilder.BuildContentStep.BuildBodyStep.BuildBodyCompleteStep.Tests.cs │ ├── MessageBuilder.BuildContentStep.BuildBodyStep.BuildHtmlBodyStep.Tests.cs │ ├── MessageBuilder.BuildContentStep.BuildBodyStep.BuildTextBodyStep.Tests.cs │ ├── MessageBuilder.BuildContentStep.BuildBodyStep.Tests.cs │ ├── MessageBuilder.BuildContentStep.BuildContentTemplateStep.Tests.cs │ ├── MessageBuilder.BuildContentStep.Tests.cs │ ├── MessageBuilder.BuildRecipientsStep.BuldToStep.BuildRecipientSubstitutionStep.Tests.cs │ ├── MessageBuilder.BuildRecipientsStep.BuldToStep.BuildRecipientWithDisplaySubstitutionStep.Tests.cs │ ├── MessageBuilder.BuildRecipientsStep.BuldToStep.BuiltToWithDisplayStep.Tests.cs │ ├── MessageBuilder.BuildRecipientsStep.BuldToStep.Tests.cs │ ├── MessageBuilder.BuildRecipientsStep.Tests.cs │ ├── MessageBuilder.BuildSubjectStep.BuildWithSubjectStep.Tests.cs │ ├── MessageBuilder.BuildSubjectStep.Tests.cs │ ├── MessageBuilder.Tests.cs │ ├── MessageBuilderBuildPostContentStep.BuildAttachmentOrSubstitutionStep.Tests.cs │ ├── MessageBuilderBuildPostContentStep.Tests.cs │ ├── NullDesk.Extensions.Mailer.Core.Tests.csproj │ ├── NullMailer.Tests.cs │ └── xunit.runner.json ├── NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer.Tests │ ├── Infrastructure │ │ ├── SqlIntegrationFixture.cs │ │ ├── TestSqlHistoryContext.cs │ │ └── TestSqlHistoryContextFactory.cs │ ├── Migrations │ │ ├── 20170314025003_Initial.Designer.cs │ │ ├── 20170314025003_Initial.cs │ │ ├── 20170528045718_ReplyTo.Designer.cs │ │ ├── 20170528045718_ReplyTo.cs │ │ └── TestSqlHistoryContextModelSnapshot.cs │ ├── NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer.Tests.csproj │ ├── SqlHistoryTests.cs │ └── xunit.runner.json ├── NullDesk.Extensions.Mailer.History.EntityFramework.Tests │ ├── HistoryContextTests.cs │ ├── Infrastructure │ │ ├── MemoryEfFixture.cs │ │ └── TestHistoryContext.cs │ ├── NullDesk.Extensions.Mailer.History.EntityFramework.Tests.csproj │ └── xunit.runner.json ├── NullDesk.Extensions.Mailer.MailKit.Tests │ ├── Infrastructure │ │ ├── FactoryMailFixture.cs │ │ ├── FactorySafetyMailFixture.cs │ │ ├── FailureMailFixture.cs │ │ ├── GmailMailFixture.cs │ │ ├── HistoryMailFixture.cs │ │ ├── MailFixture.cs │ │ ├── ReusableMailFixture.cs │ │ └── StandardMailFixture.cs │ ├── MailKitGmailMailerTests.cs │ ├── MailKitMessageHistoryTests.cs │ ├── MailKitSafetySmtpFactoryMailerTests.cs │ ├── MailKitSettingsFromJsonTests.cs │ ├── MailKitSmtpFactoryMailerTests.cs │ ├── MailKitSmtpMailerFailureTests.cs │ ├── MailKitSmtpMailerTests.cs │ ├── MailKitSmtpParallelMailerTests.cs │ ├── NullDesk.Extensions.Mailer.MailKit.Tests.csproj │ ├── appsettings.json │ └── xunit.runner.json ├── NullDesk.Extensions.Mailer.SendGrid.Tests │ ├── Infrastructure │ │ ├── FactoryMailFixture.cs │ │ ├── HistoryMailFixture.cs │ │ ├── ReusableMailFixture.cs │ │ ├── SendGridMailerFakes.cs │ │ └── StandardMailFixture.cs │ ├── NullDesk.Extensions.Mailer.SendGrid.Tests.csproj │ ├── SendGridFactoryMailerTests.cs │ ├── SendGridMailerTests.cs │ ├── SendGridMessageHistoryTests.cs │ ├── SendGridParallelMailerTests.cs │ └── xunit.runner.json ├── NullDesk.Extensions.Mailer.Tests.Common │ ├── NullDesk.Extensions.Mailer.Tests.Common.csproj │ ├── StandardMailerTestData.cs │ ├── TemplateMailerTestData.cs │ └── TestParallelMailMessage.cs └── TestData │ ├── attachments │ ├── testFile.1.txt │ └── testFile.2.txt │ └── templates │ ├── template1.htm │ ├── template1.txt │ └── template2.txt └── version-bump.ps1 /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Samples (console)", 6 | "type": "coreclr", 7 | "request": "launch", 8 | "preLaunchTask": "build", 9 | "program": "${workspaceRoot}\\samples\\mailer-cli\\mailer\\bin\\Debug\\netcoreapp1.1\\mailer.dll", 10 | "args": ["send", "simple", "-a"], 11 | "cwd": "${workspaceRoot}\\samples\\mailer-cli\\mailer", 12 | "symbolPath": [], 13 | "externalConsole": false, 14 | "stopAtEntry": false, 15 | "internalConsoleOptions": "openOnSessionStart" 16 | }, 17 | { 18 | "name": ".NET Core Attach", 19 | "type": "coreclr", 20 | "request": "attach", 21 | "processId": "${command:pickProcess}" 22 | } 23 | ] 24 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "command": "dotnet", 4 | "args": [], 5 | "tasks": [ 6 | { 7 | "label": "build", 8 | "type": "shell", 9 | "command": "dotnet", 10 | "args": [ 11 | "build" 12 | ], 13 | "problemMatcher": "$msCompile", 14 | "group": { 15 | "_id": "build", 16 | "isDefault": false 17 | } 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /.vscode/tasks.json.old: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.1.0", 3 | "command": "dotnet", 4 | "isShellCommand": true, 5 | "args": [], 6 | "tasks": [{ 7 | "taskName": "build", 8 | "args": [], 9 | "isBuildCommand": true, 10 | "problemMatcher": "$msCompile" 11 | }] 12 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Stephen M. Redd 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /NullDesk.Mailer.sln.GhostDoc.user.dic: -------------------------------------------------------------------------------- 1 | Xunit 2 | -------------------------------------------------------------------------------- /deploy.ps1: -------------------------------------------------------------------------------- 1 | <# 2 | .SYNOPSIS 3 | Local powershell script buld and deploy nuget packages. 4 | 5 | .DESCRIPTION 6 | Run from the repository root. Uses dotnet pack and nuget.exe to build and 7 | publish nuget packages. Often used to publish experimental beta versions 8 | without going through the formal CICD pipeline. 9 | 10 | .PARAMETER apikey 11 | API Key for nuget.org 12 | 13 | .EXAMPLE 14 | .\deploy.ps1 15 | 16 | #> 17 | [cmdletbinding()] 18 | param([Parameter(Mandatory)][string]$apikey, [switch]$publish = $false) 19 | 20 | $rootDir = Get-Location 21 | $srcDir = Get-ChildItem ./src 22 | $outputDir = Join-Path -Path $rootDir -ChildPath '/packOutput' 23 | Write-Output `n 24 | 25 | if (-not (Test-Path -Path $outputDir -PathType Container)) { 26 | Write-Output "Creating output directory: $outputDir" 27 | New-Item -Path $outputDir -ItemType Directory 28 | } 29 | Write-Output "Cleaning output directory: $outputDir" 30 | Remove-Item $outputDir\* 31 | Write-Output `n 32 | 33 | if(!$config){ 34 | $config = "Release" 35 | Write-Output "Configuration $config" 36 | } 37 | 38 | Write-Output "restoring packages" 39 | & dotnet restore 40 | 41 | [object[]]$projectFolders = $NULL 42 | 43 | # loop through projects and collect src and test project paths 44 | foreach ($folder in $srcDir) { 45 | $p = Join-Path -Path $folder.FullName -ChildPath '*.csproj'; 46 | # only src project folders -> folders with a csproj file 47 | if (Test-Path $p -PathType Leaf) { 48 | $projectFolders += $folder.FullName 49 | } 50 | } 51 | 52 | foreach($srcFolder in $projectFolders){ 53 | Write-Output "Build packages" 54 | & dotnet pack $srcFolder -c $config -o $outputDir -p:IncludeSymbols=true -p:SymbolPackageFormat=snupkg 55 | } 56 | Write-Output `n 57 | if($publish){ 58 | Write-Output "Publish packages" 59 | & dotnet nuget push $outputDir\*.* -s https://api.nuget.org/v3/index.json -k $apikey 60 | Write-Output `n 61 | } 62 | else 63 | { 64 | Write-Output "Skiped publishing packages; use the -publish switch to publish" 65 | } 66 | Write-Output "Done" 67 | -------------------------------------------------------------------------------- /samples/mailer-cli/.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": ".NET Core Launch (console)", 6 | "type": "coreclr", 7 | "request": "launch", 8 | "preLaunchTask": "build", 9 | "program": "${workspaceRoot}\\mailer\\bin\\Debug\\netcoreapp1.1\\mailer.dll", 10 | "args": [], 11 | "cwd": "${workspaceRoot}\\mailer", 12 | "externalConsole": false, 13 | "stopAtEntry": false, 14 | "internalConsoleOptions": "openOnSessionStart" 15 | }, 16 | { 17 | "name": ".NET Core Attach", 18 | "type": "coreclr", 19 | "request": "attach", 20 | "processId": "${command.pickProcess}" 21 | } 22 | ] 23 | } -------------------------------------------------------------------------------- /samples/mailer-cli/.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.1.0", 3 | "command": "dotnet", 4 | "isShellCommand": true, 5 | "args": [], 6 | "tasks": [ 7 | { 8 | "taskName": "build", 9 | "args": [ 10 | "${workspaceRoot}\\mailer\\project.json" 11 | ], 12 | "isBuildCommand": true, 13 | "problemMatcher": "$msCompile" 14 | } 15 | ] 16 | } -------------------------------------------------------------------------------- /samples/mailer-cli/mailer/App_Data/Attachments/test.txt: -------------------------------------------------------------------------------- 1 | Test attachment content here! 2 | 3 | The End -------------------------------------------------------------------------------- /samples/mailer-cli/mailer/App_Data/Templates/template1.html: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | Test Message 7 | 8 | 9 | 10 |
Hello %name%,
11 |
 
12 |
13 | This is a test message from the NullDesk Mailer Extensions. This 14 | message was sent via SMTP using a file template. 15 |
16 |
 
17 |
Your name is %name%
18 |
 
19 |
Thanks,
20 |
 
21 |
Bot
22 | 23 | 24 | -------------------------------------------------------------------------------- /samples/mailer-cli/mailer/App_Data/Templates/template1.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | Hello %name%, 4 | 5 | This is a test plain text message from xUnit the automated test runner included with the NullDesk Mailer Extensions. 6 | 7 | Thanks, 8 | 9 | Bot 10 | -------------------------------------------------------------------------------- /samples/mailer-cli/mailer/Commands/CliCommand.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.CommandLineUtils; 2 | using Microsoft.Extensions.DependencyInjection; 3 | 4 | namespace Sample.Mailer.Cli.Commands 5 | { 6 | public static class CliCommandExtensions 7 | { 8 | public static void ConfigureCliCommand(this CommandLineApplication app) where T : CliCommand 9 | { 10 | Program.ServiceProvider.GetService().Configure(app); 11 | } 12 | } 13 | 14 | public abstract class CliCommand 15 | { 16 | protected CliCommand(AnsiConsole console) 17 | { 18 | Reporter = console; 19 | } 20 | 21 | protected AnsiConsole Reporter { get; set; } 22 | 23 | public abstract void Configure(CommandLineApplication app); 24 | } 25 | } -------------------------------------------------------------------------------- /samples/mailer-cli/mailer/Commands/DropDb.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.CommandLineUtils; 2 | using NullDesk.Cli; 3 | using NullDesk.Extensions.Mailer.Core; 4 | using NullDesk.Extensions.Mailer.History.EntityFramework; 5 | using NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer; 6 | 7 | namespace Sample.Mailer.Cli.Commands 8 | { 9 | public class DropDb : CliCommand 10 | { 11 | public DropDb(AnsiConsole console, IHistoryStore history) : base(console) 12 | { 13 | Context = ((EntityHistoryStore) history).GetHistoryContext(); 14 | } 15 | 16 | private HistoryContext Context { get; } 17 | 18 | public override void Configure(CommandLineApplication app) 19 | { 20 | app.Command("drop-db", sendApp => 21 | { 22 | sendApp.HelpOption("-?|-h|--help"); 23 | sendApp.FullName = "Drop History Database"; 24 | sendApp.Description = "Removes the history database if present"; 25 | sendApp.AllowArgumentSeparator = true; 26 | 27 | sendApp.OnExecute(() => 28 | { 29 | var result = Context.Database.EnsureDeleted(); 30 | var message = result ? "Database removed".Cyan() : "Failed to remove database".Red(); 31 | 32 | Reporter.WriteLine(message); 33 | Context.Dispose(); 34 | return result ? 0 : 1; 35 | }); 36 | }, false); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /samples/mailer-cli/mailer/Commands/SendMail.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.CommandLineUtils; 2 | 3 | namespace Sample.Mailer.Cli.Commands 4 | { 5 | public class SendMail : CliCommand 6 | { 7 | public SendMail(AnsiConsole console) : base(console) 8 | { 9 | } 10 | 11 | public override void Configure(CommandLineApplication app) 12 | { 13 | app.Command("send", sendApp => 14 | { 15 | sendApp.HelpOption("-?|-h|--help"); 16 | sendApp.FullName = "Attempts to send a test Email"; 17 | sendApp.Description = "Sends Email"; 18 | sendApp.AllowArgumentSeparator = true; 19 | 20 | 21 | sendApp.ConfigureCliCommand(); 22 | sendApp.ConfigureCliCommand(); 23 | 24 | sendApp.OnExecute(() => 25 | { 26 | sendApp.ShowHelp(); 27 | return 0; 28 | }); 29 | }, false); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /samples/mailer-cli/mailer/Commands/SendSimpleMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Threading; 5 | using Microsoft.Extensions.CommandLineUtils; 6 | using Microsoft.Extensions.Options; 7 | using NullDesk.Cli; 8 | using NullDesk.Extensions.Mailer.Core; 9 | using Sample.Mailer.Cli.Configuration; 10 | 11 | namespace Sample.Mailer.Cli.Commands 12 | { 13 | public class SendSimpleMessage : CliCommand 14 | { 15 | public SendSimpleMessage(AnsiConsole console, IMailer mailer, 16 | IOptions settings) : base(console) 17 | { 18 | Mailer = mailer; 19 | Settings = settings.Value.SimpleMessageSettings; 20 | } 21 | 22 | private IMailer Mailer { get; } 23 | 24 | private SimpleMessageSettings Settings { get; } 25 | 26 | public override void Configure(CommandLineApplication app) 27 | { 28 | app.Command("simple", simpleApp => 29 | { 30 | simpleApp.HelpOption("-?|-h|--help"); 31 | simpleApp.FullName = "Send Simple Message"; 32 | simpleApp.Description = 33 | "Attempts to send a simple test message through the currently configured provider, no template is used"; 34 | simpleApp.AllowArgumentSeparator = true; 35 | 36 | var addAttachments = simpleApp.Option("-a|--attachments", 37 | "Include attachment files if specified in the messsage settings (see appsettings.json)", 38 | CommandOptionType.NoValue); 39 | 40 | simpleApp.OnExecute(async () => 41 | { 42 | IEnumerable result = null; 43 | try 44 | { 45 | var dItems = Mailer.CreateMessage(b => b 46 | .Subject(Settings.Subject) 47 | .And.To(Settings.ToAddress) 48 | .WithDisplayName(Settings.ToDisplayName) 49 | .And.ForBody() 50 | .WithHtml(Settings.HtmlBody) 51 | .AndPlainText(Settings.TextBody) 52 | .And.WithAttachments(Settings.AttachmentFiles) 53 | .Build() 54 | ); 55 | result = await Mailer.SendAllAsync(CancellationToken.None); 56 | } 57 | catch (Exception ex) 58 | { 59 | Reporter.WriteLine($"[Error] {ex.Message}"); 60 | Reporter.WriteLine(string.Empty); 61 | } 62 | var message = result == null || !result.All(r => r.IsSuccess) 63 | ? "Failed to send email".Red() 64 | : "Email sent".Cyan(); 65 | 66 | Reporter.WriteLine(message); 67 | 68 | return 0; 69 | }); 70 | }, false); 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /samples/mailer-cli/mailer/Configuration/MailHistoryDbSettings.cs: -------------------------------------------------------------------------------- 1 | namespace Sample.Mailer.Cli.Configuration 2 | { 3 | public class MailHistoryDbSettings 4 | { 5 | public bool EnableHistory { get; set; } = true; 6 | 7 | public string ConnectionString { get; set; } 8 | } 9 | } -------------------------------------------------------------------------------- /samples/mailer-cli/mailer/Configuration/TestMessageSettings.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Sample.Mailer.Cli.Configuration 4 | { 5 | public class SimpleMessageSettings 6 | { 7 | public string ToAddress { get; set; } 8 | 9 | public string ToDisplayName { get; set; } 10 | 11 | public string Subject { get; set; } 12 | 13 | public string HtmlBody { get; set; } 14 | 15 | public string TextBody { get; set; } 16 | 17 | public IEnumerable AttachmentFiles { get; set; } 18 | } 19 | 20 | public class TemplateMessageSettings 21 | { 22 | public string Template { get; set; } 23 | 24 | public string ToAddress { get; set; } 25 | 26 | public string ToDisplayName { get; set; } 27 | 28 | public string Subject { get; set; } 29 | 30 | public Dictionary ReplacementVariables { get; set; } 31 | 32 | public IEnumerable AttachmentFiles { get; set; } 33 | } 34 | 35 | public class TestMessageSettings 36 | { 37 | public SimpleMessageSettings SimpleMessageSettings { get; set; } 38 | 39 | public TemplateMessageSettings SendGridTemplateMessage { get; set; } 40 | 41 | public TemplateMessageSettings MailKitTemplateMessage { get; set; } 42 | } 43 | } -------------------------------------------------------------------------------- /samples/mailer-cli/mailer/Extensions/AnsiColorExtensions.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable once CheckNamespace 2 | 3 | namespace NullDesk.Cli 4 | { 5 | public static class AnsiColorExtensions 6 | { 7 | public static string Black(this string text) 8 | { 9 | return "\x1B[30m" + text + "\x1B[39m"; 10 | } 11 | 12 | public static string Red(this string text) 13 | { 14 | return "\x1B[31m" + text + "\x1B[39m"; 15 | } 16 | 17 | public static string Green(this string text) 18 | { 19 | return "\x1B[32m" + text + "\x1B[39m"; 20 | } 21 | 22 | public static string Yellow(this string text) 23 | { 24 | return "\x1B[33m" + text + "\x1B[39m"; 25 | } 26 | 27 | public static string Blue(this string text) 28 | { 29 | return "\x1B[34m" + text + "\x1B[39m"; 30 | } 31 | 32 | public static string Magenta(this string text) 33 | { 34 | return "\x1B[35m" + text + "\x1B[39m"; 35 | } 36 | 37 | public static string Cyan(this string text) 38 | { 39 | return "\x1B[36m" + text + "\x1B[39m"; 40 | } 41 | 42 | public static string White(this string text) 43 | { 44 | return "\x1B[37m" + text + "\x1B[39m"; 45 | } 46 | 47 | public static string Bold(this string text) 48 | { 49 | return "\x1B[1m" + text + "\x1B[22m"; 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /samples/mailer-cli/mailer/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Extensions.CommandLineUtils; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Microsoft.Extensions.Options; 5 | using Sample.Mailer.Cli.Commands; 6 | using Sample.Mailer.Cli.Configuration; 7 | 8 | namespace Sample.Mailer.Cli 9 | { 10 | public class Program 11 | { 12 | public static IServiceProvider ServiceProvider { get; set; } 13 | 14 | public static void Main(string[] args) 15 | { 16 | if (args == null || args.Length < 1) 17 | { 18 | args = new[] {"--help"}; 19 | } 20 | new Startup().Run(args); 21 | 22 | var reporter = ServiceProvider.GetService(); 23 | 24 | reporter.WriteLine(string.Empty); 25 | var app = new CommandLineApplication(false) 26 | { 27 | Name = "mailer", 28 | FullName = "NullDesk Sample Mailer CLI", 29 | Description = "Send email using the NullDesk Mailer Extensions.", 30 | AllowArgumentSeparator = true 31 | }; 32 | 33 | 34 | app.HelpOption("-?|-h|--help"); 35 | 36 | app.ConfigureCliCommand(); 37 | 38 | var historySettings = ServiceProvider.GetService>(); 39 | if (historySettings.Value.EnableHistory) 40 | { 41 | app.ConfigureCliCommand(); 42 | } 43 | app.OnExecute(() => 44 | { 45 | app.ShowHelp(); 46 | return 0; 47 | }); 48 | try 49 | { 50 | app.Execute(args); 51 | } 52 | catch (Exception ex) 53 | { 54 | Console.Write(ex.ToString()); 55 | } 56 | } 57 | } 58 | } -------------------------------------------------------------------------------- /samples/mailer-cli/mailer/Properties/launchSettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "profiles": { 3 | "mailer": { 4 | "commandName": "Project", 5 | "commandLineArgs": "send simple" 6 | } 7 | } 8 | } -------------------------------------------------------------------------------- /samples/mailer-cli/mailer/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "Logging": { 3 | "IncludeScopes": true, 4 | "LogLevel": { 5 | "Default": "Debug", 6 | "System": "Information", 7 | "Microsoft": "Information" 8 | } 9 | }, 10 | "MailHistoryDbSettings": { 11 | "IsEnabled": true, 12 | "StoreAttachmentContents": false, 13 | "ConnectionString": "Server=(localdb)\\MSSQLLocalDB;Database=NullDeskMailerSampleCli;Trusted_Connection=True;", 14 | "AutoInitializeDatabase": true, 15 | "SourceApplicationName": "MailerSampleCLI" 16 | }, 17 | "MailSettings": { 18 | "ActiveMailService": "SafetyMailKit", 19 | "SafetyMailerSettings": { 20 | "SafeRecipientEmailAddress": "safe@test.com" 21 | }, 22 | "MkSmtpMailerSettings": { 23 | "FromEmailAddress": "test@test.com", 24 | "FromDisplayName": "Sample Mailer CLI - MailKit", 25 | "SmtpServer": "localhost", 26 | "SmtpPort": 25, 27 | "SmtpRequireSsl": false, 28 | "TemplateSettings": { 29 | "TemplatePath": "./App_Data/Templates", 30 | "HtmlTemplateFileExtensions": [ "html" ], 31 | "TextTemplateFileExtension": [ "txt" ] 32 | } 33 | }, 34 | "SendGridMailerSettings": { 35 | "ApiKey": "your key here", 36 | "FromEmailAddress": "test@test.com", 37 | "FromDisplayName": "Sample Mailer CLI - SendGrid", 38 | "IsSandboxMode": false 39 | } 40 | }, 41 | "TestMessageSettings": { 42 | "SimpleMessageSettings": { 43 | "ToAddress": "noone@nowhere.com", 44 | "ToDisplayName": "Mr. Nobody", 45 | "Subject": "Test Mail", 46 | "HtmlBody": 47 | "Test Message

Hello,

This is a test html message from the NullDesk Mailer-CLI Sample application.

Thanks,

Bot

", 48 | "TextBody": 49 | "Hellp,\n\nThis is a test plain text message from the NullDesk Mailer-CLI Sample application.\n\nThanks,\n\nbot", 50 | "AttachmentFiles": [".\\App_Data\\Attachments\\test.txt"] 51 | }, 52 | "SendGridTemplateMessage": { 53 | "Template": "a1dab65f-f2c1-4fb6-b9a6-002bcdb4b1c7", 54 | "ToAddress": "noone@nowhere.com", 55 | "ToDisplayName": "Mr. Nobody", 56 | "Subject": null, 57 | "ReplacementVariables": { 58 | "%name%": "Mr Nobody" 59 | }, 60 | "AttachmentFiles": [".\\App_Data\\Attachments\\test.txt"] 61 | }, 62 | "MailKitTemplateMessage": { 63 | "Template": "template1", 64 | "ToAddress": "noone@nowhere.com", 65 | "ToDisplayName": "Mr. Nobody", 66 | "Subject": "Test Mail", 67 | "ReplacementVariables": { 68 | "%name%": "Mr Nobody" 69 | }, 70 | "AttachmentFiles": [".\\App_Data\\Attachments\\test.txt"] 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /samples/mailer-cli/mailer/mailer.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | net9.0 4 | portable 5 | mailer 6 | Exe 7 | mailer 8 | false 9 | false 10 | false 11 | Sample.Mailer.Cli 12 | 13 | 14 | 15 | PreserveNewest 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | all 27 | runtime; build; native; contentfiles; analyzers; buildtransitive 28 | 29 | 30 | all 31 | runtime; build; native; contentfiles; analyzers 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/Extensions/DirectoryInfoExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using System.Linq; 3 | 4 | // ReSharper disable once CheckNamespace 5 | 6 | namespace NullDesk.Extensions.Mailer.Core 7 | { 8 | /// 9 | /// Class DirectoryInfoExtensions. 10 | /// 11 | public static class DirectoryInfoExtensions 12 | { 13 | /// 14 | /// Gets the first file by name with one of the specified extensions. 15 | /// 16 | /// The dir. 17 | /// Name of the file. 18 | /// The extensions. 19 | /// FileInfo. 20 | public static FileInfo GetFirstFileForExtensions(this DirectoryInfo dir, string fileName, 21 | params string[] extensions) 22 | { 23 | //ensure extensions list all start with dot 24 | var fExtensions = extensions.Select(e => e.StartsWith(".") ? e : $".{e}"); 25 | 26 | var files = dir.EnumerateFiles($"{fileName}.*"); 27 | 28 | return files.FirstOrDefault(f => fExtensions.Contains(f.Extension)); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/Extensions/FileSystemTemplateBodyExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.IO; 3 | using System.Linq; 4 | using System.Threading; 5 | using System.Threading.Tasks; 6 | using Microsoft.Extensions.Logging; 7 | 8 | // ReSharper disable once CheckNamespace 9 | 10 | namespace NullDesk.Extensions.Mailer.Core 11 | { 12 | /// 13 | /// Class FileSystemTemplateBodyExtensions. 14 | /// 15 | public static class FileSystemTemplateBodyExtensions 16 | { 17 | /// 18 | /// Gets a content body from a template body using filesystem templates. 19 | /// 20 | /// The tbody. 21 | /// The message. 22 | /// The template path. 23 | /// The HTML template file extensions. 24 | /// The text template file extensions. 25 | /// The logger. 26 | /// The cancellation token. 27 | /// Task<MimeEntity>. 28 | public static async Task GetContentBodyFromFileTemplatesAsync( 29 | this TemplateBody tbody, 30 | DeliveryItem message, 31 | string templatePath, 32 | IEnumerable htmlTemplateFileExtensions, 33 | IEnumerable textTemplateFileExtensions, 34 | ILogger logger, 35 | CancellationToken token = default(CancellationToken)) 36 | { 37 | var cbody = new ContentBody(); 38 | var templateName = tbody.TemplateName; 39 | var templateExists = false; 40 | var directory = new DirectoryInfo(templatePath); 41 | 42 | var htmlTemplate = directory.GetFirstFileForExtensions(templateName, htmlTemplateFileExtensions.ToArray()); 43 | if (htmlTemplate != null) 44 | { 45 | cbody.HtmlContent = await htmlTemplate.OpenText().ReadToEndAsync(); 46 | templateExists = true; 47 | } 48 | 49 | var textTemplate = directory.GetFirstFileForExtensions(templateName, textTemplateFileExtensions.ToArray()); 50 | if (textTemplate != null) 51 | { 52 | cbody.PlainTextContent = await textTemplate.OpenText().ReadToEndAsync(); 53 | templateExists = true; 54 | } 55 | 56 | if (!templateExists) 57 | { 58 | var ex = new FileNotFoundException($"No email message template found for TemplateName {templateName}"); 59 | logger.LogError(1, ex, ex.Message); 60 | throw ex; 61 | } 62 | 63 | return cbody; 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/Extensions/MailerFactoryExtensions.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.Logging; 2 | 3 | // ReSharper disable once CheckNamespace 4 | namespace NullDesk.Extensions.Mailer.Core 5 | { 6 | /// 7 | /// Class MailerFactoryExtensions. 8 | /// 9 | public static class MailerFactoryExtensions 10 | { 11 | /// 12 | /// Registers a null mailer with the factory. 13 | /// 14 | /// The factory. 15 | /// The mailer settings. 16 | /// The logger. 17 | /// The store. 18 | public static void AddNullMailer 19 | ( 20 | this MailerFactory factory, 21 | NullMailerSettings mailerSettings, 22 | ILogger logger = null, 23 | IHistoryStore store = null 24 | ) 25 | { 26 | factory.Register(mailerSettings, 27 | logger ?? factory.DefaultLoggerFactory?.CreateLogger(), 28 | factory.ConfigureHistoryStoreLogger(store)); 29 | } 30 | 31 | /// 32 | /// Registers a safety mailer proxy for the specified mailer type. 33 | /// 34 | /// The type of the t mailer. 35 | /// The type of the t mailer settings. 36 | /// The factory. 37 | /// The safety mailer settings. 38 | /// The mailer settings. 39 | /// The logger. 40 | /// The store. 41 | public static void AddSafetyMailer 42 | ( 43 | this MailerFactory factory, 44 | SafetyMailerSettings safetyMailerSettings, 45 | TMailerSettings mailerSettings, 46 | ILogger logger = null, 47 | IHistoryStore store = null 48 | ) 49 | where TMailer : class, IMailer 50 | where TMailerSettings : class, IMailerSettings 51 | { 52 | factory.Register, SafetyMailerSettings, TMailer, TMailerSettings>( 53 | safetyMailerSettings, 54 | mailerSettings, 55 | logger ?? factory.DefaultLoggerFactory?.CreateLogger(), 56 | factory.ConfigureHistoryStoreLogger(store)); 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/Extensions/StreamExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Threading.Tasks; 4 | 5 | namespace NullDesk.Extensions.Mailer.Core.Extensions 6 | { 7 | /// 8 | /// Class StreamExtensions. 9 | /// 10 | public static class StreamExtensions 11 | { 12 | /// 13 | /// Gets a base64 encoded string from the stream. 14 | /// 15 | /// The input. 16 | /// Task<System.String>. 17 | public static async Task ToBase64StringAsync(this Stream input) 18 | { 19 | if (input == null) 20 | { 21 | return null; 22 | } 23 | 24 | using (var ms = new MemoryStream()) 25 | { 26 | input.Position = 0; //put stream back to start 27 | await input.CopyToAsync(ms); 28 | return Convert.ToBase64String(ms.ToArray()); 29 | } 30 | } 31 | 32 | /// 33 | /// Gets a base64 encoded string from the stream. 34 | /// 35 | /// The input. 36 | /// Task<System.String>. 37 | public static string ToBase64String(this Stream input) 38 | { 39 | if (input == null) 40 | { 41 | return null; 42 | } 43 | 44 | using (var ms = new MemoryStream()) 45 | { 46 | input.Position = 0; //put stream back to start 47 | input.CopyTo(ms); 48 | return Convert.ToBase64String(ms.ToArray()); 49 | } 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/Extensions/StringExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Text; 3 | 4 | // ReSharper disable once CheckNamespace 5 | 6 | namespace NullDesk.Extensions.Mailer.Core 7 | { 8 | /// 9 | /// Class StringExtensions. 10 | /// 11 | public static class StringExtensions 12 | { 13 | /// 14 | /// Replaces content in a string for each of the values in a replacement variables dictionary 15 | /// 16 | /// The template content 17 | /// The replacement variables 18 | /// 19 | public static string PerformContentSubstitution(this string content, 20 | IDictionary replacementVariables) 21 | { 22 | var result = new StringBuilder(content); 23 | foreach (var item in replacementVariables) 24 | { 25 | result.Replace(item.Key, item.Value); 26 | } 27 | 28 | return result.ToString(); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/Fluent/Extensions/MailerContentBodyFluentExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace NullDesk.Extensions.Mailer.Core.Fluent.Extensions 2 | { 3 | /// 4 | /// Class MailerContentBodyFluentExtensions. 5 | /// 6 | public static class MailerContentBodyFluentExtensions 7 | { 8 | /// 9 | /// Adds an HTML email body. 10 | /// 11 | /// The body. 12 | /// The HTML. 13 | /// ContentBody. 14 | public static ContentBody WithHtml(this ContentBody body, string html) 15 | { 16 | body.HtmlContent = html; 17 | return body; 18 | } 19 | 20 | /// 21 | /// Adds a plain text email body. 22 | /// 23 | /// The body. 24 | /// The text. 25 | /// ContentBody. 26 | public static ContentBody WithPlainText(this ContentBody body, string text) 27 | { 28 | body.PlainTextContent = text; 29 | return body; 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/Fluent/Extensions/MessageRecipientFluentExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace NullDesk.Extensions.Mailer.Core.Fluent.Extensions 4 | { 5 | /// 6 | /// MailerRecipient Fluent API. 7 | /// 8 | public static class MessageRecipientFluentExtensions 9 | { 10 | /// 11 | /// Adds the specified email address to the sender's info. 12 | /// 13 | /// The sender. 14 | /// The email address. 15 | /// MessageRecipient. 16 | public static MessageRecipient ToAddress(this MessageRecipient recipient, string emailAddress) 17 | { 18 | recipient.EmailAddress = emailAddress; 19 | return recipient; 20 | } 21 | 22 | /// 23 | /// Adds a display name to the sender's info. 24 | /// 25 | /// The sender. 26 | /// The display name. 27 | /// MessageRecipient. 28 | public static MessageRecipient WithDisplayName(this MessageRecipient recipient, string displayName) 29 | { 30 | recipient.DisplayName = displayName; 31 | return recipient; 32 | } 33 | 34 | /// 35 | /// Adds one or more personalized replacement variables for the recipient. 36 | /// 37 | /// The message. 38 | /// The substitutions. 39 | /// MessageRecipient. 40 | /// Substitutions can be applied to the subject, html body, text body, and templates 41 | public static MessageRecipient WithSubstitutions(this MessageRecipient recipient, 42 | IDictionary substitutions) 43 | { 44 | foreach (var substitution in substitutions) 45 | { 46 | recipient.PersonalizedSubstitutions.Add(substitution); 47 | } 48 | 49 | return recipient; 50 | } 51 | 52 | /// 53 | /// Adds a personalized replacement variable for the recipient. 54 | /// 55 | /// The message. 56 | /// The token to replace. 57 | /// The value to substitue for the token. 58 | /// MessageRecipient. 59 | /// Substitutions can be applied to the subject, html body, text body, and templates 60 | public static MessageRecipient WithSubstitution(this MessageRecipient recipient, string key, string value) 61 | { 62 | recipient.PersonalizedSubstitutions.Add(new KeyValuePair(key, value)); 63 | 64 | return recipient; 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/Fluent/Extensions/MessageSenderFluentExtensions.cs: -------------------------------------------------------------------------------- 1 | namespace NullDesk.Extensions.Mailer.Core.Fluent.Extensions 2 | { 3 | /// 4 | /// MailerReplyTo Fluent API. 5 | /// 6 | public static class MessageSenderFluentExtensions 7 | { 8 | /// 9 | /// Adds the specified email address to the sender's info. 10 | /// 11 | /// The sender. 12 | /// The email address. 13 | /// MessageSender. 14 | public static MessageSender FromAddress(this MessageSender sender, string emailAddress) 15 | { 16 | sender.EmailAddress = emailAddress; 17 | return sender; 18 | } 19 | 20 | /// 21 | /// Adds a display name to the sender's info. 22 | /// 23 | /// The sender. 24 | /// The display name. 25 | /// MessageSender. 26 | public static MessageSender WithDisplayName(this MessageSender sender, string displayName) 27 | { 28 | sender.DisplayName = displayName; 29 | return sender; 30 | } 31 | 32 | /// 33 | /// Adds the specified email address as the message's reply to address for the sender. 34 | /// 35 | /// The sender. 36 | /// The reply to email address. 37 | /// MessageSender. 38 | public static MessageSender ReplyToAddress(this MessageSender sender, string emailAddress) 39 | { 40 | sender.ReplyToEmailAddress = emailAddress; 41 | return sender; 42 | } 43 | 44 | /// 45 | /// Adds a display name for the reply to address. 46 | /// 47 | /// The sender. 48 | /// The reply to display name. 49 | /// MessageSender. 50 | public static MessageSender WithReplyToDisplayName(this MessageSender sender, string displayName) 51 | { 52 | sender.ReplyToDisplayName = displayName; 53 | return sender; 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/Fluent/Infrastrucutre/BuilderContentBodyContext.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable CheckNamespace 2 | 3 | namespace NullDesk.Extensions.Mailer.Core.Fluent 4 | { 5 | /// 6 | /// Base fluent context for the message body content builder. 7 | /// 8 | /// 9 | public abstract class BuilderContentBodyContext : BuilderContext 10 | { 11 | /// 12 | /// Initializes a new instance of the class. 13 | /// 14 | /// The message context. 15 | /// The body. 16 | internal BuilderContentBodyContext(MailerMessage context, ContentBody body) : base(context) 17 | { 18 | Body = body; 19 | } 20 | 21 | /// 22 | /// Gets the body. 23 | /// 24 | /// The body. 25 | protected ContentBody Body { get; } 26 | } 27 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/Fluent/Infrastrucutre/BuilderContext.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable CheckNamespace 2 | 3 | namespace NullDesk.Extensions.Mailer.Core.Fluent 4 | { 5 | /// 6 | /// Base fluent context for the message builder. 7 | /// 8 | /// 9 | public abstract class BuilderContext : IBuilderContext 10 | { 11 | /// 12 | /// Initializes a new instance of the class. 13 | /// 14 | /// The context. 15 | internal BuilderContext(MailerMessage context) 16 | { 17 | ((IBuilderContext) this).Message = context; 18 | } 19 | 20 | /// 21 | /// Gets the context. 22 | /// 23 | /// 24 | /// Allows inheritors to access the mailer message directly without needing to cast to IBuilderContext each time. 25 | /// 26 | /// The context. 27 | protected MailerMessage Context => ((IBuilderContext) this).Message; 28 | 29 | /// 30 | /// The message this context refers to. 31 | /// 32 | /// 33 | /// Explicit interface implementation. Hidden from intellisense and general public usage, but still allows unit tests 34 | /// and other callers to cast the instance to IBuilderContext and directly access the underlying mailer message if 35 | /// necessary. 36 | /// 37 | /// The message. 38 | MailerMessage IBuilderContext.Message { get; set; } 39 | } 40 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/Fluent/Infrastrucutre/BuilderRecipientContext.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable CheckNamespace 2 | 3 | namespace NullDesk.Extensions.Mailer.Core.Fluent 4 | { 5 | /// 6 | /// Base fluent context for the message recipient builder. 7 | /// 8 | /// 9 | public abstract class BuilderRecipientContext : BuilderContext 10 | { 11 | /// 12 | /// Initializes a new instance of the class. 13 | /// 14 | /// The context. 15 | /// The recipient. 16 | internal BuilderRecipientContext(MailerMessage context, MessageRecipient recipient) : base(context) 17 | { 18 | Recipient = recipient; 19 | } 20 | 21 | /// 22 | /// The recipient. 23 | /// 24 | /// The recipient. 25 | protected MessageRecipient Recipient { get; } 26 | } 27 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/Fluent/Infrastrucutre/IBuilderContext.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable CheckNamespace 2 | 3 | namespace NullDesk.Extensions.Mailer.Core.Fluent 4 | { 5 | /// 6 | /// Interface for fluent message builder contexts. 7 | /// 8 | public interface IBuilderContext 9 | { 10 | /// 11 | /// The message being built by the context. 12 | /// 13 | /// The message. 14 | MailerMessage Message { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/Fluent/Infrastrucutre/IBuilderStepsCompleted.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable CheckNamespace 2 | 3 | namespace NullDesk.Extensions.Mailer.Core.Fluent 4 | { 5 | /// 6 | /// Marker Interface for a message builder step that can be built to return a usable mailer message 7 | /// 8 | public interface IBuilderStepsCompleted 9 | { 10 | /// 11 | /// Completes the fluent builder and returns the mailer message instance. 12 | /// 13 | /// MailerMessage. 14 | MailerMessage Build(); 15 | } 16 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/Fluent/MessageBuider.cs: -------------------------------------------------------------------------------- 1 | using NullDesk.Extensions.Mailer.Core.Fluent.Extensions; 2 | 3 | namespace NullDesk.Extensions.Mailer.Core.Fluent 4 | { 5 | /// 6 | /// Fluent builder for creating a MailerMessage. 7 | /// 8 | /// 9 | public partial class MessageBuilder : BuilderContext 10 | { 11 | /// 12 | /// Initializes a new instance of the class. 13 | /// 14 | public MessageBuilder() : base(new MailerMessage()) 15 | { 16 | } 17 | 18 | /// 19 | /// Add sender info with the specified email address. 20 | /// 21 | /// The email address. 22 | /// BuildFromStep. 23 | public BuildFromStep From(string emailAddress) 24 | { 25 | return new BuildFromStep(Context.From(emailAddress)); 26 | } 27 | 28 | /// 29 | /// Add sender info from mailer settings. 30 | /// 31 | /// The mailer settings. 32 | /// BuildSubjectStep. 33 | public BuildSubjectStep ForSettings(IMailerSettings mailerSettings) 34 | { 35 | return new BuildSubjectStep(Context.From(mailerSettings.FromEmailAddress, mailerSettings.FromDisplayName, 36 | mailerSettings.ReplyToEmailAddress, mailerSettings.ReplyToDisplayName)); 37 | } 38 | 39 | //Step 3 = MessageBuilder.BuildRecipientsStep.cs 40 | 41 | //Step 1 = MessageBuilder.BuildFromStep.cs 42 | 43 | 44 | //Step 2 = MessageBuilder.BuildSubjectStep.cs 45 | 46 | //Step 4 = MessageBuilder.BuildContentStep.cs 47 | 48 | //Step 5 = MessageBuilder.BuildPostContentStep 49 | } 50 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/Fluent/MessageBuilder.BuildReplyToStep.cs: -------------------------------------------------------------------------------- 1 | using NullDesk.Extensions.Mailer.Core.Fluent.Extensions; 2 | 3 | namespace NullDesk.Extensions.Mailer.Core.Fluent 4 | { 5 | public partial class MessageBuilder 6 | { 7 | /// 8 | /// Fluent message builder step for defining the message's reply to address. 9 | /// 10 | /// 11 | public class BuildReplyToStep : BuilderContext 12 | { 13 | /// 14 | /// Initializes a new instance of the class. 15 | /// 16 | /// The context. 17 | public BuildReplyToStep(MailerMessage context) : base(context) 18 | { 19 | } 20 | 21 | /// 22 | /// Advance to the next step in the fluent builder process 23 | /// 24 | /// The and. 25 | public BuildSubjectStep And 26 | => new BuildSubjectStep(Context); 27 | 28 | 29 | /// 30 | /// Adds a display name for the sender 31 | /// 32 | /// The display name. 33 | /// BuildFromWithDisplayStep. 34 | public BuildReplyToWithDisplayStep WithReplyToDisplayName(string displayName) 35 | { 36 | return new BuildReplyToWithDisplayStep(Context.From(Context.From.WithReplyToDisplayName(displayName))); 37 | } 38 | 39 | /// 40 | /// Fluent message builder step for defining the message's reply to addres. 41 | /// 42 | /// 43 | public class BuildReplyToWithDisplayStep : BuilderContext 44 | { 45 | /// 46 | /// Initializes a new instance of the class. 47 | /// 48 | /// The context. 49 | public BuildReplyToWithDisplayStep(MailerMessage context) : base(context) 50 | { 51 | } 52 | 53 | /// 54 | /// Advance to the next step in the fluent builder process 55 | /// 56 | /// The and. 57 | public BuildSubjectStep And 58 | => new BuildSubjectStep(Context); 59 | } 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/Fluent/MessageBuilder.BuildSubjectStep.cs: -------------------------------------------------------------------------------- 1 | using NullDesk.Extensions.Mailer.Core.Fluent.Extensions; 2 | 3 | namespace NullDesk.Extensions.Mailer.Core.Fluent 4 | { 5 | public partial class MessageBuilder 6 | { 7 | /// 8 | /// Fluent message builder step for defining the message's subject. 9 | /// 10 | /// 11 | public class BuildSubjectStep : BuilderContext 12 | { 13 | /// 14 | /// Initializes a new instance of the class. 15 | /// 16 | /// The context. 17 | public BuildSubjectStep(MailerMessage context) : base(context) 18 | { 19 | } 20 | 21 | /// 22 | /// Adds a subject to the message. 23 | /// 24 | /// The subject. 25 | /// BuildWithSubjectStep. 26 | public BuildWithSubjectStep Subject(string subject) 27 | { 28 | return new BuildWithSubjectStep(Context.WithSubject(subject)); 29 | } 30 | 31 | /// 32 | /// Specifies that this message should have an empty subject line. 33 | /// 34 | /// BuildWithSubjectStep. 35 | public BuildWithSubjectStep WithOutSubject() 36 | { 37 | return new BuildWithSubjectStep(Context); 38 | } 39 | 40 | /// 41 | /// Fluent message builder step for defining the message's subject. 42 | /// 43 | /// 44 | public class BuildWithSubjectStep : BuilderContext 45 | { 46 | /// 47 | /// Initializes a new instance of the class. 48 | /// 49 | /// The context. 50 | public BuildWithSubjectStep(MailerMessage context) : base(context) 51 | { 52 | } 53 | 54 | /// 55 | /// Advance to the next step in the fluent builder process 56 | /// 57 | /// The and. 58 | public BuildRecipientsStep And 59 | => new BuildRecipientsStep(Context); 60 | } 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/HistoryModel/IHistoryStoreSettings.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable once CheckNamespace 2 | 3 | namespace NullDesk.Extensions.Mailer.Core 4 | { 5 | /// 6 | /// History store settings 7 | /// 8 | public interface IHistoryStoreSettings 9 | { 10 | /// 11 | /// Indicates if delivery history is enabled. 12 | /// 13 | /// true if history is enabled; otherwise, false. 14 | bool IsEnabled { get; set; } 15 | 16 | /// 17 | /// Indicates whether to store attachment content with the delivery history. 18 | /// 19 | /// 20 | /// If false messages in history will not be resendable if the original had attachments. 21 | /// 22 | /// true if content of attachments should be included in history otherwise, false. 23 | bool StoreAttachmentContents { get; set; } 24 | 25 | /// 26 | /// The name of the application to be include in history. 27 | /// 28 | /// Use to give a name to the system recording history. 29 | /// The name of the delivery provider. 30 | string SourceApplicationName { get; set; } 31 | } 32 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/HistoryModel/StandardHistoryStoreSettings.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable once CheckNamespace 2 | 3 | namespace NullDesk.Extensions.Mailer.Core 4 | { 5 | /// 6 | /// Standard History Store Settings. 7 | /// 8 | /// 9 | public class StandardHistoryStoreSettings : IHistoryStoreSettings 10 | { 11 | /// 12 | /// Indicates if delivery history is enabled. Default is true. 13 | /// 14 | /// true if history is enabled; otherwise, false. 15 | public bool IsEnabled { get; set; } = true; 16 | 17 | 18 | /// 19 | /// Indicates whether to store attachment content with the delivery history. Default is false. 20 | /// 21 | /// true if content of attachments should be included in history otherwise, false. 22 | /// If false messages in history will not be resendable if the original had attachments. 23 | public bool StoreAttachmentContents { get; set; } = false; 24 | 25 | 26 | /// 27 | /// The name of the application to be include in history. 28 | /// 29 | /// The name of the delivery provider. 30 | /// Use to give a name to the system recording history. 31 | public string SourceApplicationName { get; set; } 32 | } 33 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/Infrastructure/AsyncLock.cs: -------------------------------------------------------------------------------- 1 | // Based on code from Stephen Toub 2 | // https://blogs.msdn.microsoft.com/pfxteam/2012/02/12/building-async-coordination-primitives-part-5-asyncsemaphore/ 3 | // https://blogs.msdn.microsoft.com/pfxteam/2012/02/12/building-async-coordination-primitives-part-6-asynclock/ 4 | 5 | using System; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | 9 | // ReSharper disable once CheckNamespace 10 | namespace NullDesk.Extensions.Mailer.Core 11 | { 12 | /// 13 | /// AsyncLock. 14 | /// 15 | public class AsyncLock 16 | { 17 | private readonly Task _mReleaser; 18 | private readonly AsyncSemaphore _mSemaphore; 19 | 20 | /// 21 | /// Initializes a new instance of the class. 22 | /// 23 | public AsyncLock() 24 | { 25 | _mSemaphore = new AsyncSemaphore(1); 26 | _mReleaser = Task.FromResult(new Releaser(this)); 27 | } 28 | 29 | /// 30 | /// Create an async lock. 31 | /// 32 | /// Task<Releaser>. 33 | public Task LockAsync() 34 | { 35 | var wait = _mSemaphore.WaitAsync(); 36 | return wait.IsCompleted 37 | ? _mReleaser 38 | : wait.ContinueWith((_, state) => new Releaser((AsyncLock) state), 39 | this, CancellationToken.None, 40 | TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default); 41 | } 42 | 43 | /// 44 | /// Struct Releaser 45 | /// 46 | /// 47 | public struct Releaser : IDisposable 48 | { 49 | private readonly AsyncLock _mToRelease; 50 | 51 | internal Releaser(AsyncLock toRelease) 52 | { 53 | _mToRelease = toRelease; 54 | } 55 | 56 | /// 57 | /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. 58 | /// 59 | public void Dispose() 60 | { 61 | _mToRelease?._mSemaphore.Release(); 62 | } 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/Infrastructure/AsyncSemaphore.cs: -------------------------------------------------------------------------------- 1 | // Based on code from Stephen Toub 2 | // https://blogs.msdn.microsoft.com/pfxteam/2012/02/12/building-async-coordination-primitives-part-5-asyncsemaphore/ 3 | // https://blogs.msdn.microsoft.com/pfxteam/2012/02/12/building-async-coordination-primitives-part-6-asynclock/ 4 | 5 | 6 | using System; 7 | using System.Collections.Generic; 8 | using System.Threading.Tasks; 9 | 10 | // ReSharper disable once CheckNamespace 11 | namespace NullDesk.Extensions.Mailer.Core 12 | { 13 | /// 14 | /// Class AsyncSemaphore. 15 | /// 16 | public class AsyncSemaphore 17 | { 18 | private static readonly Task SCompleted = Task.FromResult(true); 19 | private readonly Queue> _mWaiters = new Queue>(); 20 | private int _mCurrentCount; 21 | 22 | /// 23 | /// Initializes a new instance of the class. 24 | /// 25 | /// The initial count. 26 | /// initialCount 27 | public AsyncSemaphore(int initialCount) 28 | { 29 | if (initialCount < 0) 30 | { 31 | throw new ArgumentOutOfRangeException(nameof(initialCount)); 32 | } 33 | 34 | _mCurrentCount = initialCount; 35 | } 36 | 37 | /// 38 | /// Async wait. 39 | /// 40 | /// Task. 41 | public Task WaitAsync() 42 | { 43 | lock (_mWaiters) 44 | { 45 | if (_mCurrentCount > 0) 46 | { 47 | --_mCurrentCount; 48 | return SCompleted; 49 | } 50 | 51 | var waiter = new TaskCompletionSource(); 52 | _mWaiters.Enqueue(waiter); 53 | return waiter.Task; 54 | } 55 | } 56 | 57 | /// 58 | /// Releases this instance. 59 | /// 60 | public void Release() 61 | { 62 | TaskCompletionSource toRelease = null; 63 | lock (_mWaiters) 64 | { 65 | if (_mWaiters.Count > 0) 66 | { 67 | toRelease = _mWaiters.Dequeue(); 68 | } 69 | else 70 | { 71 | ++_mCurrentCount; 72 | } 73 | } 74 | 75 | toRelease?.SetResult(true); 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/MailerModel/IMailerFactory.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | 4 | // ReSharper disable once CheckNamespace 5 | namespace NullDesk.Extensions.Mailer.Core 6 | { 7 | /// 8 | /// Factory class for obtaining mailer instances. 9 | /// Factory class for obtaining mailer instances. 10 | /// 11 | public interface IMailerFactory 12 | { 13 | /// 14 | /// Gets a collection of registered mailer functions. 15 | /// 16 | /// The mailers. 17 | List> MailerRegistrations { get; } 18 | 19 | /// 20 | /// Gets an instance of the first registered standard mailer. 21 | /// 22 | /// IMailer. 23 | IMailer GetMailer(); 24 | 25 | 26 | /// 27 | /// Registers a function that can be use to create a configured mailer instance. 28 | /// 29 | /// 30 | /// The mailer function. 31 | void Register(Func mailerFunc) where T : class, IMailer; 32 | 33 | /// 34 | /// Gets an instance of a registered mailer for the specified type. 35 | /// 36 | /// The type of mailer instance you wish to create 37 | /// IMailer. 38 | /// If more than one function for the mailer type exists, will use the first matching function. 39 | IMailer GetMailer() where T : class, IMailer; 40 | } 41 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/MailerModel/IMailerSettings.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable once CheckNamespace 2 | 3 | namespace NullDesk.Extensions.Mailer.Core 4 | { 5 | /// 6 | /// Mailer settings marker interface 7 | /// 8 | public interface IMailerSettings 9 | { 10 | /// 11 | /// From Email Address 12 | /// 13 | /// 14 | string FromEmailAddress { get; set; } 15 | 16 | /// 17 | /// From display name. 18 | /// 19 | /// From display name. 20 | string FromDisplayName { get; set; } 21 | 22 | 23 | /// 24 | /// Reply to email address. 25 | /// 26 | /// The reply to email address. 27 | string ReplyToEmailAddress { get; set; } 28 | 29 | 30 | /// 31 | /// Reply to display name. 32 | /// 33 | /// The display name of the reply to address. 34 | string ReplyToDisplayName { get; set; } 35 | } 36 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/MailerModel/IProxyMailer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | // ReSharper disable once CheckNamespace 3 | 4 | namespace NullDesk.Extensions.Mailer.Core 5 | { 6 | /// 7 | /// Interface for safety mailer proxy types 8 | /// 9 | public interface IProxyMailer : IDisposable 10 | where TProxySettings : class, IProxyMailerSettings 11 | where TMailer : class, IMailer 12 | { 13 | /// 14 | /// Gets the underlying mailer instance wrapped by the proxy. 15 | /// 16 | /// The mailer. 17 | TMailer Mailer { get; } 18 | 19 | /// 20 | /// The settings for the proxy mailer. 21 | /// 22 | /// The settings. 23 | TProxySettings Settings { get; set; } 24 | } 25 | 26 | 27 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/MailerModel/IProxyMailerSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | // ReSharper disable once CheckNamespace 8 | namespace NullDesk.Extensions.Mailer.Core 9 | { 10 | /// 11 | /// Marker Interface for Proxy Mailer Settings 12 | /// 13 | public interface IProxyMailerSettings 14 | { 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/MailerModel/NullMailer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using Microsoft.Extensions.Logging; 5 | 6 | // ReSharper disable once CheckNamespace 7 | namespace NullDesk.Extensions.Mailer.Core 8 | { 9 | /// 10 | /// A mailer instance that does nothing. 11 | /// 12 | /// 13 | public class NullMailer : Mailer 14 | { 15 | /// 16 | /// Initializes a new instance of the class. 17 | /// 18 | /// The mailer settings. 19 | /// The logger. 20 | /// The history store. 21 | public NullMailer(NullMailerSettings settings, ILogger logger = null, 22 | IHistoryStore historyStore = null) : base(settings, logger, historyStore) 23 | { 24 | } 25 | 26 | /// 27 | /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. 28 | /// 29 | public override void Dispose() 30 | { 31 | //do nothing 32 | } 33 | 34 | /// 35 | /// When overridden in a derived class, uses the mailer's underlying mail delivery service to send the specified 36 | /// message . 37 | /// 38 | /// The delivery item containing the message you wish to send. 39 | /// if set to true automatically close connection affter sending the message. 40 | /// The cancellation token. 41 | /// Task<DeliveryItem>. 42 | /// The cancellation token. 43 | /// The implementor should return a provider specific ID value. 44 | protected override Task DeliverMessageAsync(DeliveryItem deliveryItem, 45 | bool autoCloseConnection = true, 46 | CancellationToken token = new CancellationToken()) 47 | { 48 | deliveryItem.IsSuccess = true; 49 | return Task.FromResult(Guid.NewGuid().ToString()); 50 | } 51 | 52 | /// 53 | /// Closes any active mail client connections. 54 | /// 55 | /// The token. 56 | /// Task. 57 | /// The cancellation token. 58 | /// Used to close connections if DeliverMessageAsync was used with autoCloseConnection set to false. 59 | protected override Task CloseMailClientConnectionAsync(CancellationToken token = new CancellationToken()) 60 | { 61 | return Task.CompletedTask; 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/MailerModel/NullMailerSettings.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable CheckNamespace 2 | 3 | namespace NullDesk.Extensions.Mailer.Core 4 | { 5 | /// 6 | /// Class NullMailerSettings. 7 | /// 8 | /// 9 | public class NullMailerSettings : IMailerSettings 10 | { 11 | /// 12 | /// Dummy From Email Address 13 | /// 14 | /// From email address. 15 | public string FromEmailAddress { get; set; } 16 | 17 | /// 18 | /// Dummy From display name. 19 | /// 20 | /// From display name. 21 | public string FromDisplayName { get; set; } 22 | 23 | /// 24 | /// Reply to email address. 25 | /// 26 | /// The reply to email address. 27 | public string ReplyToEmailAddress { get; set; } 28 | 29 | /// 30 | /// Reply to display name. 31 | /// 32 | /// The display name of the reply to address. 33 | public string ReplyToDisplayName { get; set; } 34 | } 35 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/MailerModel/SafetyMailerSettings.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable once CheckNamespace 2 | 3 | namespace NullDesk.Extensions.Mailer.Core 4 | { 5 | /// 6 | /// Settings for use with SafetyMailer. 7 | /// 8 | public class SafetyMailerSettings: IProxyMailerSettings 9 | { 10 | 11 | /// 12 | /// The safe recipient email address that will be used instead of the messages original recipient email address. 13 | /// 14 | /// The safe recipient email address. 15 | public string SafeRecipientEmailAddress { get; set; } 16 | 17 | 18 | /// 19 | /// Text to prepend to the recipient display name when safe recipient address has been overwritten; defaults to 20 | /// "(safe)". 21 | /// 22 | /// The prepend display name text. 23 | public string PrependDisplayNameWithText { get; set; } = "(safe)"; 24 | } 25 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/MailerModel/SmtpMailerSettings.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable once CheckNamespace 2 | 3 | namespace NullDesk.Extensions.Mailer.Core 4 | { 5 | /// 6 | /// Settings for SMTP Email Services. 7 | /// 8 | public class SmtpMailerSettings : IMailerSettings 9 | { 10 | /// 11 | /// The SMTP server host name. 12 | /// 13 | /// The SMTP server. 14 | public string SmtpServer { get; set; } 15 | 16 | /// 17 | /// SMTP server port number. 18 | /// 19 | /// The SMTP port. 20 | public int SmtpPort { get; set; } = 25; 21 | 22 | 23 | /// 24 | /// From email address. 25 | /// 26 | /// From email. 27 | public string FromEmailAddress { get; set; } 28 | 29 | /// 30 | /// From display name. 31 | /// 32 | /// From display name. 33 | public string FromDisplayName { get; set; } 34 | 35 | /// 36 | /// Reply to email address. 37 | /// 38 | /// The reply to email address. 39 | public string ReplyToEmailAddress { get; set; } 40 | 41 | /// 42 | /// Reply to display name. 43 | /// 44 | /// The display name of the reply to address. 45 | public string ReplyToDisplayName { get; set; } 46 | } 47 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/MessageModel/AttachmentStreamJsonConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.IO; 4 | using System.Linq; 5 | using Newtonsoft.Json; 6 | using NullDesk.Extensions.Mailer.Core.Extensions; 7 | 8 | // ReSharper disable once CheckNamespace 9 | namespace NullDesk.Extensions.Mailer.Core 10 | { 11 | /// 12 | /// Json converter for attachment stream dictionaries 13 | /// 14 | /// 15 | public class AttachmentStreamJsonConverter : JsonConverter 16 | { 17 | /// 18 | /// Determines whether this instance can convert the specified object type. 19 | /// 20 | /// Type of the object. 21 | /// true if this instance can convert the specified object type; otherwise, false. 22 | public override bool CanConvert(Type objectType) 23 | { 24 | var v = typeof(IDictionary).IsAssignableFrom(objectType); 25 | return v; 26 | } 27 | 28 | /// 29 | /// Reads the JSON representation of the object. 30 | /// 31 | /// The to read from. 32 | /// Type of the object. 33 | /// The existing value of object being read. 34 | /// The calling serializer. 35 | /// The object value. 36 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue, 37 | JsonSerializer serializer) 38 | { 39 | var dict = serializer.Deserialize>(reader); 40 | return dict.Select(i => 41 | new KeyValuePair( 42 | i.Key, 43 | i.Value == null ? null : new MemoryStream(Convert.FromBase64String(i.Value)))) 44 | .ToDictionary(k => k.Key, k => k.Value); 45 | } 46 | 47 | 48 | /// 49 | /// Writes the JSON representation of the object. 50 | /// 51 | /// The to write to. 52 | /// The value. 53 | /// The calling serializer. 54 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 55 | { 56 | var dict = (IDictionary) value; 57 | 58 | var converted = dict.Select(i => new KeyValuePair(i.Key, i.Value.ToBase64String())) 59 | .ToDictionary(k => k.Key, k => k.Value); 60 | 61 | serializer.Serialize(writer, converted); 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/MessageModel/ContentBody.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable CheckNamespace 2 | 3 | namespace NullDesk.Extensions.Mailer.Core 4 | { 5 | /// 6 | /// A message body containing html and/or plain text content 7 | /// 8 | public class ContentBody : IMessageBody 9 | { 10 | /// 11 | /// An HTML message body. 12 | /// 13 | /// 14 | /// If substitutions are provided, they will be used here. 15 | /// 16 | /// The content of the HTML. 17 | public string HtmlContent { get; set; } 18 | 19 | /// 20 | /// A plain text message body. 21 | /// 22 | /// 23 | /// If substitutions are provided, they will be used here. 24 | /// 25 | /// The content of the plain text. 26 | public string PlainTextContent { get; set; } 27 | 28 | /// 29 | /// Creates a message body. 30 | /// 31 | /// ContentBody. 32 | public static ContentBody Create() 33 | { 34 | return new ContentBody(); 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/MessageModel/IMessageAddress.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable CheckNamespace 2 | 3 | namespace NullDesk.Extensions.Mailer.Core 4 | { 5 | /// 6 | /// Interface IMailerAddress 7 | /// 8 | public interface IMessageAddress 9 | { 10 | /// 11 | /// Gets or sets the email address. 12 | /// 13 | /// The email address. 14 | string DisplayName { get; set; } 15 | 16 | /// 17 | /// Gets or sets the display name for the reply address. 18 | /// 19 | /// The display name. 20 | string EmailAddress { get; set; } 21 | } 22 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/MessageModel/IMessageBody.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable CheckNamespace 2 | 3 | namespace NullDesk.Extensions.Mailer.Core 4 | { 5 | /// 6 | /// Interface IMessageBody 7 | /// 8 | public interface IMessageBody 9 | { 10 | //marker interface 11 | } 12 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/MessageModel/MailerMessage.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Collections.ObjectModel; 3 | using System.IO; 4 | using System.Linq; 5 | 6 | // ReSharper disable CheckNamespace 7 | namespace NullDesk.Extensions.Mailer.Core 8 | { 9 | /// 10 | /// Represents an email message compatible with all NullDesk Mailers. 11 | /// 12 | public class MailerMessage 13 | { 14 | /// 15 | /// Gets or sets the message body. 16 | /// 17 | /// The body. 18 | public IMessageBody Body { get; set; } 19 | 20 | /// 21 | /// The reply to information for the message. 22 | /// 23 | /// From. 24 | public MessageSender From { get; set; } 25 | 26 | /// 27 | /// The message recipients. 28 | /// 29 | /// The recipients. 30 | public ICollection Recipients { get; set; } = new Collection(); 31 | 32 | /// 33 | /// The message subject. 34 | /// 35 | /// 36 | /// If substitutions are provided, they will be used here. Some services may ignore this value when using templates, 37 | /// others will use this value in place of any subject defined in the template. 38 | /// 39 | /// The subject. 40 | public string Subject { get; set; } 41 | 42 | /// 43 | /// A collection of tokens and replacement values to use with body contents, templates, and message subject. 44 | /// 45 | /// 46 | /// To override any of these values on a per-recipient basis, supply overriding values to the recipients' 47 | /// PersonalizedSubstitutions property 48 | /// 49 | /// The substitution tokens and replacement values. 50 | public IDictionary Substitutions { get; set; } = new Dictionary(); 51 | 52 | /// 53 | /// A collection of attachments to include with the message. 54 | /// 55 | /// The attachments. 56 | public IDictionary Attachments { get; set; } = new Dictionary(); 57 | 58 | /// 59 | /// Determines whether this instance is deliverable. 60 | /// 61 | /// true if this instance is deliverable; otherwise, false. 62 | public bool IsDeliverable => 63 | Recipients.Any() && From != null && Body != null; 64 | 65 | 66 | /// 67 | /// Creates a mailer message. 68 | /// 69 | /// MailerContentMessage. 70 | public static MailerMessage Create() 71 | { 72 | return new MailerMessage(); 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/MessageModel/MessageBodyJsonConverter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Newtonsoft.Json; 4 | using Newtonsoft.Json.Linq; 5 | 6 | // ReSharper disable once CheckNamespace 7 | namespace NullDesk.Extensions.Mailer.Core 8 | { 9 | /// 10 | /// Json converter for IMessageBody. 11 | /// 12 | /// 13 | public class MessageBodyJsonConverter : JsonConverter 14 | { 15 | /// 16 | /// Writes the JSON representation of the object. 17 | /// 18 | /// The to write to. 19 | /// The value. 20 | /// The calling serializer. 21 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 22 | { 23 | serializer.Serialize(writer, value); 24 | } 25 | 26 | /// 27 | /// Reads the JSON representation of the object. 28 | /// 29 | /// The to read from. 30 | /// Type of the object. 31 | /// The existing value of object being read. 32 | /// The calling serializer. 33 | /// The object value. 34 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue, 35 | JsonSerializer serializer) 36 | { 37 | IMessageBody body = null; 38 | var jbody = JObject.Load(reader); 39 | var hasTemplateName = jbody.Properties() 40 | .Any(p => p.Name.Equals("templatename", StringComparison.OrdinalIgnoreCase)); 41 | if (hasTemplateName) 42 | { 43 | body = jbody.ToObject(); 44 | } 45 | else 46 | { 47 | var hasContentProperties = jbody.Properties() 48 | .Any(p => p.Name.Equals("PlainTextContent", StringComparison.OrdinalIgnoreCase) || 49 | p.Name.Equals("HtmlContent", StringComparison.OrdinalIgnoreCase)); 50 | if (hasContentProperties) 51 | { 52 | body = jbody.ToObject(); 53 | } 54 | } 55 | 56 | return body; 57 | } 58 | 59 | /// 60 | /// Determines whether this instance can convert the specified object type. 61 | /// 62 | /// Type of the object. 63 | /// true if this instance can convert the specified object type; otherwise, false. 64 | public override bool CanConvert(Type objectType) 65 | { 66 | return objectType == typeof(IMessageBody); 67 | } 68 | } 69 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/MessageModel/MessageRecipient.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable CheckNamespace 2 | 3 | using System.Collections.Generic; 4 | 5 | namespace NullDesk.Extensions.Mailer.Core 6 | { 7 | /// 8 | /// The email recipient's address and information 9 | /// 10 | public class MessageRecipient : IMessageAddress 11 | { 12 | /// 13 | /// Optional collection of template substitution variables specific to the recipient. 14 | /// 15 | /// 16 | /// When sending email, the values specified here will be merged with, and override, any replacement variables defined 17 | /// on for message as a whole. Use this to supply replacment substitutions that vary from one recipient to another. 18 | /// 19 | /// Template substitutions to use for this recipient only. 20 | public IDictionary PersonalizedSubstitutions { get; set; } = new Dictionary(); 21 | 22 | /// 23 | /// Gets or sets the recipient's email address. 24 | /// 25 | /// The email address. 26 | public string EmailAddress { get; set; } 27 | 28 | 29 | /// 30 | /// Gets or sets the display name for the recipient. 31 | /// 32 | /// The display name. 33 | public string DisplayName { get; set; } 34 | } 35 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/MessageModel/MessageSender.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable CheckNamespace 2 | 3 | namespace NullDesk.Extensions.Mailer.Core 4 | { 5 | /// 6 | /// The email sender's address and information. 7 | /// 8 | public class MessageSender : IMessageAddress 9 | { 10 | /// 11 | /// The message reply to address. 12 | /// 13 | /// The reply to address. 14 | public string ReplyToEmailAddress { get; set; } 15 | 16 | /// 17 | /// The display name for the reply to address. 18 | /// 19 | /// The reply to display name. 20 | public string ReplyToDisplayName { get; set; } 21 | 22 | /// 23 | /// The email address for the message sender. 24 | /// 25 | /// The sender's email address. 26 | public string EmailAddress { get; set; } 27 | 28 | /// 29 | /// The display name for the sender . 30 | /// 31 | /// The sender's display name. 32 | public string DisplayName { get; set; } 33 | } 34 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/MessageModel/TemplateBody.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable CheckNamespace 2 | 3 | namespace NullDesk.Extensions.Mailer.Core 4 | { 5 | /// 6 | /// A message body that uses an external template. 7 | /// 8 | /// 9 | public class TemplateBody : IMessageBody 10 | { 11 | /// 12 | /// The name of the template to send. 13 | /// 14 | /// The template. 15 | public string TemplateName { get; set; } 16 | 17 | /// 18 | /// Creates a message body. 19 | /// 20 | /// TemplateBody. 21 | public static TemplateBody Create() 22 | { 23 | return new TemplateBody(); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.Core/NullDesk.Extensions.Mailer.Core.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | NullDesk Mailer Extensions base classes and abstractions for email messaging services 4 | 8.5.0 5 | Stephen M. Redd 6 | net8.0 7 | true 8 | true 9 | portable 10 | true 11 | NullDesk.Extensions.Mailer.Core 12 | NullDesk.Extensions.Mailer.Core 13 | email;nulldesk 14 | https://github.com/NullDesk/NullMailer 15 | MIT 16 | git 17 | https://github.com/NullDesk/NullMailer 18 | false 19 | false 20 | false 21 | Stephen M. Redd 2017 22 | true 23 | true 24 | snupkg 25 | README.md 26 | 27 | 28 | 29 | True 30 | \ 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer/Migrations/20170530063924_Initial.Designer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Infrastructure; 4 | using Microsoft.EntityFrameworkCore.Metadata; 5 | using Microsoft.EntityFrameworkCore.Migrations; 6 | 7 | namespace NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer.Migrations 8 | { 9 | 10 | [DbContext(typeof(SqlHistoryContext))] 11 | [Migration("20170530063924_Initial")] 12 | partial class Initial 13 | { 14 | #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member 15 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 16 | { 17 | modelBuilder 18 | .HasAnnotation("ProductVersion", "1.1.2") 19 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 20 | 21 | modelBuilder.Entity("NullDesk.Extensions.Mailer.History.EntityFramework.EntityHistoryDeliveryItem", b => 22 | { 23 | b.Property("Id") 24 | .ValueGeneratedOnAdd(); 25 | 26 | b.Property("AttachmentsJson"); 27 | 28 | b.Property("CreatedDate"); 29 | 30 | b.Property("DeliveryProvider") 31 | .HasMaxLength(100); 32 | 33 | b.Property("ExceptionMessage") 34 | .HasMaxLength(500); 35 | 36 | b.Property("FromDisplayName") 37 | .HasMaxLength(200); 38 | 39 | b.Property("FromEmailAddress") 40 | .HasMaxLength(200); 41 | 42 | b.Property("HtmlContent"); 43 | 44 | b.Property("IsSuccess"); 45 | 46 | b.Property("ProviderMessageId") 47 | .HasMaxLength(200); 48 | 49 | b.Property("ReplyToDisplayName") 50 | .HasMaxLength(200); 51 | 52 | b.Property("ReplyToEmailAddress") 53 | .HasMaxLength(200); 54 | 55 | b.Property("Subject") 56 | .HasMaxLength(200); 57 | 58 | b.Property("SubstitutionsJson"); 59 | 60 | b.Property("TemplateName") 61 | .HasMaxLength(255); 62 | 63 | b.Property("TextContent"); 64 | 65 | b.Property("ToDisplayName") 66 | .HasMaxLength(200); 67 | 68 | b.Property("ToEmailAddress") 69 | .HasMaxLength(200); 70 | 71 | b.HasKey("Id"); 72 | 73 | b.ToTable("MessageHistory"); 74 | }); 75 | } 76 | #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member 77 | 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer/Migrations/20170530063924_Initial.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore.Migrations; 3 | 4 | namespace NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer.Migrations 5 | { 6 | #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member 7 | 8 | public partial class Initial : Migration 9 | { 10 | protected override void Up(MigrationBuilder migrationBuilder) 11 | { 12 | migrationBuilder.CreateTable( 13 | "MessageHistory", 14 | table => new 15 | { 16 | Id = table.Column(nullable: false), 17 | AttachmentsJson = table.Column(nullable: true), 18 | CreatedDate = table.Column(nullable: false), 19 | DeliveryProvider = table.Column(maxLength: 100, nullable: true), 20 | ExceptionMessage = table.Column(maxLength: 500, nullable: true), 21 | FromDisplayName = table.Column(maxLength: 200, nullable: true), 22 | FromEmailAddress = table.Column(maxLength: 200, nullable: true), 23 | HtmlContent = table.Column(nullable: true), 24 | IsSuccess = table.Column(nullable: false), 25 | ProviderMessageId = table.Column(maxLength: 200, nullable: true), 26 | ReplyToDisplayName = table.Column(maxLength: 200, nullable: true), 27 | ReplyToEmailAddress = table.Column(maxLength: 200, nullable: true), 28 | Subject = table.Column(maxLength: 200, nullable: true), 29 | SubstitutionsJson = table.Column(nullable: true), 30 | TemplateName = table.Column(maxLength: 255, nullable: true), 31 | TextContent = table.Column(nullable: true), 32 | ToDisplayName = table.Column(maxLength: 200, nullable: true), 33 | ToEmailAddress = table.Column(maxLength: 200, nullable: true) 34 | }, 35 | constraints: table => { table.PrimaryKey("PK_MessageHistory", x => x.Id); }); 36 | } 37 | 38 | protected override void Down(MigrationBuilder migrationBuilder) 39 | { 40 | migrationBuilder.DropTable( 41 | "MessageHistory"); 42 | } 43 | } 44 | 45 | #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member 46 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer/Migrations/20170604221538_SourceAppName.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member 4 | 5 | namespace NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer.Migrations 6 | { 7 | public partial class SourceAppName : Migration 8 | { 9 | protected override void Up(MigrationBuilder migrationBuilder) 10 | { 11 | migrationBuilder.AddColumn( 12 | "SourceApplicationName", 13 | "MessageHistory", 14 | maxLength: 100, 15 | nullable: true); 16 | } 17 | 18 | protected override void Down(MigrationBuilder migrationBuilder) 19 | { 20 | migrationBuilder.DropColumn( 21 | "SourceApplicationName", 22 | "MessageHistory"); 23 | } 24 | } 25 | } 26 | 27 | #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer/Migrations/20170711052447_ResizeExceptionMessage.cs: -------------------------------------------------------------------------------- 1 |  2 | using Microsoft.EntityFrameworkCore.Migrations; 3 | #pragma warning disable CS1591 // Missing XML comment for publicly visible type or member 4 | 5 | namespace NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer.Migrations 6 | { 7 | 8 | public partial class ResizeExceptionMessage : Migration 9 | { 10 | protected override void Up(MigrationBuilder migrationBuilder) 11 | { 12 | migrationBuilder.AlterColumn( 13 | name: "ExceptionMessage", 14 | table: "MessageHistory", 15 | nullable: true, 16 | oldClrType: typeof(string), 17 | oldMaxLength: 500, 18 | oldNullable: true); 19 | } 20 | 21 | protected override void Down(MigrationBuilder migrationBuilder) 22 | { 23 | migrationBuilder.AlterColumn( 24 | name: "ExceptionMessage", 25 | table: "MessageHistory", 26 | maxLength: 500, 27 | nullable: true, 28 | oldClrType: typeof(string), 29 | oldNullable: true); 30 | } 31 | } 32 | } 33 | #pragma warning restore CS1591 // Missing XML comment for publicly visible type or member -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer/NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | NullDesk Mailer Extension for SQL Server email messsage and delivery history storage using EntityFramework Core 4 | 8.5.0 5 | Stephen M. Redd 6 | net8.0 7 | true 8 | true 9 | portable 10 | true 11 | NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer 12 | NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer 13 | email;nulldesk;entityframework;sqlserver 14 | https://github.com/NullDesk/NullMailer 15 | MIT 16 | git 17 | https://github.com/NullDesk/NullMailer 18 | false 19 | false 20 | false 21 | Stephen M. Redd 2017 22 | true 23 | snupkg 24 | README.md 25 | 26 | 27 | 28 | True 29 | \ 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | all 39 | runtime; build; native; contentfiles; analyzers 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer/SqlEntityHistoryStoreSettings.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using NullDesk.Extensions.Mailer.Core; 3 | 4 | namespace NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer 5 | { 6 | /// 7 | /// Settings for an entity framework history store using SQL Server. 8 | /// 9 | /// 10 | public class SqlEntityHistoryStoreSettings : StandardHistoryStoreSettings 11 | { 12 | /// 13 | /// The SQL connection string for the history context. 14 | /// 15 | /// The connection string. 16 | public string ConnectionString { get; set; } 17 | 18 | /// 19 | /// Indicates whether to automatically initialize the database on startup. 20 | /// 21 | /// true to automatically initialize database; otherwise, false. 22 | public bool AutoInitializeDatabase { get; } = true; 23 | 24 | /// 25 | /// Performs an implicit conversion from to 26 | /// . 27 | /// 28 | /// The d. 29 | /// The result of the conversion. 30 | public static implicit operator EntityHistoryStoreSettings(SqlEntityHistoryStoreSettings sqlSettings) 31 | { 32 | return new EntityHistoryStoreSettings 33 | { 34 | AutoInitializeDatabase = sqlSettings.AutoInitializeDatabase, 35 | IsEnabled = sqlSettings.IsEnabled, 36 | StoreAttachmentContents = sqlSettings.StoreAttachmentContents, 37 | SourceApplicationName = sqlSettings.SourceApplicationName, 38 | DbOptions = new DbContextOptionsBuilder() 39 | .UseSqlServer(sqlSettings.ConnectionString) 40 | .Options 41 | }; 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer/SqlHistoryContext.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | 3 | namespace NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer 4 | { 5 | /// 6 | /// SQL Server DbContext for Message History. 7 | /// 8 | /// 9 | public class SqlHistoryContext : HistoryContext 10 | { 11 | /// 12 | /// Initializes a new instance of the class. 13 | /// 14 | protected SqlHistoryContext() 15 | { 16 | } 17 | 18 | /// 19 | /// Initializes a new instance of the class. 20 | /// 21 | /// The options. 22 | public SqlHistoryContext(DbContextOptions options) : base(options) 23 | { 24 | } 25 | 26 | /// 27 | /// Initializes the database. 28 | /// 29 | /// Used to run migrations. 30 | public override void InitializeDatabase() 31 | { 32 | Database.Migrate(); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer/SqlHistoryContextFactory.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.EntityFrameworkCore.Design; 3 | 4 | namespace NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer 5 | { 6 | /// 7 | /// Class SqlHistoryContextFactory. 8 | /// 9 | public class SqlHistoryContextFactory : IDesignTimeDbContextFactory 10 | { 11 | /// 12 | /// Creates a new instance of the context. 13 | /// 14 | /// Arguments provided by the design-time service. 15 | /// Used by EF CLI tooling 16 | public SqlHistoryContext CreateDbContext(string[] args) 17 | { 18 | var builder = new DbContextOptionsBuilder(); 19 | 20 | builder.UseSqlServer( 21 | @"Server=(localdb)\MSSQLLocalDB;Database=MailerCliHistory;Trusted_Connection=True;"); 22 | return new SqlHistoryContext(builder.Options); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.History.EntityFramework/DependencyInjectionExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using NullDesk.Extensions.Mailer.Core; 4 | 5 | namespace NullDesk.Extensions.Mailer.History.EntityFramework 6 | { 7 | /// 8 | /// Class DependencyInjectionExtensions. 9 | /// 10 | public static class DependencyInjectionExtensions 11 | { 12 | /// 13 | /// Adds a mailer history store of the specified HistoryContext. 14 | /// 15 | /// The type of the History DbContext. 16 | /// The services collection. 17 | /// The entity history settings. 18 | /// IServiceCollection. 19 | public static IServiceCollection AddMailerHistory( 20 | this IServiceCollection services, 21 | EntityHistoryStoreSettings entityHistorySettings) 22 | where TContext : HistoryContext 23 | { 24 | services.AddSingleton(entityHistorySettings); 25 | services.AddSingleton>(); 26 | return services; 27 | } 28 | 29 | /// 30 | /// Adds a mailer history store of the specified HistoryContext. 31 | /// 32 | /// The type of the t context. 33 | /// The services. 34 | /// The history settings. 35 | /// IServiceCollection. 36 | public static IServiceCollection AddMailerHistory( 37 | this IServiceCollection services, 38 | Func historySettings) 39 | where TContext : HistoryContext 40 | { 41 | services.Add(new ServiceDescriptor(typeof(EntityHistoryStoreSettings), historySettings, 42 | ServiceLifetime.Singleton)); 43 | services.AddSingleton>(); 44 | return services; 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.History.EntityFramework/EntityHistoryStoreSettings.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using NullDesk.Extensions.Mailer.Core; 3 | 4 | namespace NullDesk.Extensions.Mailer.History.EntityFramework 5 | { 6 | /// 7 | /// Settings for Entity Framework History Stores. 8 | /// 9 | /// 10 | public class EntityHistoryStoreSettings : StandardHistoryStoreSettings 11 | { 12 | /// 13 | /// The database context options. 14 | /// 15 | /// The database context options. 16 | public DbContextOptions DbOptions { get; set; } 17 | 18 | /// 19 | /// Indicates whether to automaticly initialize the database on startup. 20 | /// 21 | /// true to automaticly initialize database; otherwise, false. 22 | public bool AutoInitializeDatabase { get; set; } = true; 23 | } 24 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.History.EntityFramework/HistoryContext.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | 3 | namespace NullDesk.Extensions.Mailer.History.EntityFramework 4 | { 5 | /// 6 | /// Base DbContext for Message History. 7 | /// 8 | /// 9 | public abstract class HistoryContext : DbContext 10 | { 11 | /// 12 | /// Initializes a new instance of the class. 13 | /// 14 | protected HistoryContext() 15 | { 16 | } 17 | 18 | /// 19 | /// Initializes a new instance of the class. 20 | /// 21 | /// The options. 22 | protected HistoryContext(DbContextOptions options) : base(options) 23 | { 24 | } 25 | 26 | /// 27 | /// Gets or sets the history items. 28 | /// 29 | /// The history items. 30 | public DbSet MessageHistory { get; set; } 31 | 32 | 33 | /// 34 | /// Initializes the database. 35 | /// 36 | /// Used to run migrations, provision schemas, setup document templates, etc. 37 | public abstract void InitializeDatabase(); 38 | } 39 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.History.EntityFramework/NullDesk.Extensions.Mailer.History.EntityFramework.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | NullDesk Mailer Extensions base implementation of messsage and delivery history storage with EntityFramework Core. 4 | 8.5.0 5 | Stephen M. Redd 6 | net8.0 7 | true 8 | true 9 | portable 10 | true 11 | NullDesk.Extensions.Mailer.History.EntityFramework 12 | NullDesk.Extensions.Mailer.History.EntityFramework 13 | email;nulldesk;entityframework 14 | https://github.com/NullDesk/NullMailer 15 | MIT 16 | git 17 | https://github.com/NullDesk/NullMailer 18 | false 19 | false 20 | false 21 | Stephen M. Redd 2017 22 | true 23 | snupkg 24 | README.md 25 | 26 | 27 | 28 | True 29 | \ 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.MailKit/Authentication/IMkSmtpAuthenticator.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | using MailKit.Net.Smtp; 4 | 5 | namespace NullDesk.Extensions.Mailer.MailKit.Authentication 6 | { 7 | /// 8 | /// Interface IMkSmtpAuthenticator 9 | /// 10 | public interface IMkSmtpAuthenticator 11 | { 12 | /// 13 | /// Authenticate with with the supplied client 14 | /// 15 | /// The client. 16 | /// The cancellation token. 17 | /// Task. 18 | Task Authenticate(SmtpClient client, CancellationToken token = default(CancellationToken)); 19 | } 20 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.MailKit/Authentication/MkSmtpAccessTokenAuthenticator.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using MailKit.Net.Smtp; 5 | 6 | namespace NullDesk.Extensions.Mailer.MailKit.Authentication 7 | { 8 | /// 9 | /// For oAuth and similar token based SMTP authentication 10 | /// 11 | public class MkSmtpAccessTokenAuthenticator : IMkSmtpAuthenticator 12 | { 13 | /// 14 | /// The username used to authenticate with the SMTP server 15 | /// 16 | /// The username 17 | public string UserName { get; set; } 18 | 19 | /// 20 | /// A func that can obtain a valid access token for authenticating with the SMTP server. 21 | /// 22 | /// The access token. 23 | public Func AccessTokenFactory { get; set; } 24 | 25 | /// 26 | /// Authenticate with with the supplied client 27 | /// 28 | /// The client. 29 | /// The cancellation token. 30 | /// Task. 31 | public async Task Authenticate(SmtpClient client, CancellationToken token = new CancellationToken()) 32 | { 33 | await client.AuthenticateAsync(UserName, AccessTokenFactory(), token); 34 | } 35 | } 36 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.MailKit/Authentication/MkSmtpBasicAuthenticator.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | using MailKit.Net.Smtp; 4 | 5 | namespace NullDesk.Extensions.Mailer.MailKit.Authentication 6 | { 7 | /// 8 | /// Basic authentication settings for MailKit SMTP mailers. 9 | /// 10 | public class MkSmtpBasicAuthenticator : IMkSmtpAuthenticator 11 | { 12 | /// 13 | /// If provided, specifies the username used to authenticate with the SMTP server 14 | /// 15 | /// The username 16 | public string UserName { get; set; } 17 | 18 | /// 19 | /// If provided, specifies the password used to authenticate with the SMTP server 20 | /// 21 | /// 22 | public string Password { get; set; } 23 | 24 | 25 | /// 26 | /// Authenticate SMTP connection with the supplied client 27 | /// 28 | /// The client. 29 | /// The cancellation token. 30 | /// Task. 31 | public async Task Authenticate(SmtpClient client, CancellationToken token) 32 | { 33 | client.AuthenticationMechanisms.Remove("XOAUTH2"); 34 | await client.AuthenticateAsync(UserName, Password, token); 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.MailKit/Authentication/MkSmtpCredentialsAuthenticator.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using MailKit.Net.Smtp; 5 | 6 | namespace NullDesk.Extensions.Mailer.MailKit.Authentication 7 | { 8 | /// 9 | /// System.Net.Credentials settings for SMTP authentication 10 | /// 11 | public class MkSmtpCredentialsAuthenticator : IMkSmtpAuthenticator 12 | { 13 | /// 14 | /// If provided, specifies the credentials used to autheticate with the SMTP server. 15 | /// 16 | /// 17 | /// Will be used instead of username and password if provided. 18 | /// 19 | /// 20 | public ICredentials Credentials { get; set; } 21 | 22 | /// 23 | /// Authenticate with with the supplied client 24 | /// 25 | /// The client. 26 | /// The cancellation token. 27 | /// Task. 28 | public async Task Authenticate(SmtpClient client, CancellationToken token = new CancellationToken()) 29 | { 30 | await client.AuthenticateAsync(Credentials, token); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.MailKit/Authentication/NullAuthenticator.cs: -------------------------------------------------------------------------------- 1 | using System.Threading; 2 | using System.Threading.Tasks; 3 | using MailKit.Net.Smtp; 4 | 5 | namespace NullDesk.Extensions.Mailer.MailKit.Authentication 6 | { 7 | /// 8 | /// Empty Authenticator used when no authentication is configured. 9 | /// 10 | /// 11 | public class NullAuthenticator : IMkSmtpAuthenticator 12 | { 13 | /// 14 | /// Authenticate with with the supplied client 15 | /// 16 | /// The client. 17 | /// The cancellation token. 18 | /// Task. 19 | public Task Authenticate(SmtpClient client, CancellationToken token = new CancellationToken()) 20 | { 21 | return Task.CompletedTask; 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.MailKit/MailerModel/MkFileTemplateSettings.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | // ReSharper disable once CheckNamespace 4 | namespace NullDesk.Extensions.Mailer.MailKit 5 | { 6 | /// 7 | /// File template settings for MailKit mailers. 8 | /// 9 | public class MkFileTemplateSettings 10 | { 11 | /// 12 | /// The folder path where templates are stored. 13 | /// 14 | /// The template path. 15 | public string TemplatePath { get; set; } 16 | 17 | /// 18 | /// Collection of possible HTML template file name extensions 19 | /// 20 | /// The HTML template file extensions. 21 | public IEnumerable HtmlTemplateFileExtensions { get; set; } = new[] {"htm", "html"}; 22 | 23 | /// 24 | /// Gets or sets the text template file extension. 25 | /// 26 | /// The text template file extension. 27 | public IEnumerable TextTemplateFileExtension { get; set; } = new[] {"txt"}; 28 | } 29 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.MailKit/MailerModel/MkSmtpAuthenticationSettings.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable once CheckNamespace 2 | 3 | using NullDesk.Extensions.Mailer.MailKit.Authentication; 4 | 5 | // ReSharper disable once CheckNamespace 6 | namespace NullDesk.Extensions.Mailer.MailKit 7 | { 8 | /// 9 | /// Authentication settings for MailKit SMTP mailers. 10 | /// 11 | public class MkSmtpAuthenticationSettings 12 | { 13 | private IMkSmtpAuthenticator _auth; 14 | 15 | /// 16 | /// An authenticator for the mailer, or a NullAuthenticator is no authentication is configured. 17 | /// 18 | /// The authenticator. 19 | public IMkSmtpAuthenticator Authenticator 20 | { 21 | get 22 | { 23 | 24 | if (_auth == null || _auth.GetType() == typeof(NullAuthenticator)) 25 | { 26 | _auth = 27 | !string.IsNullOrEmpty(UserName) 28 | && !string.IsNullOrEmpty(Password) 29 | ? (IMkSmtpAuthenticator)new MkSmtpBasicAuthenticator 30 | { 31 | UserName = UserName, 32 | Password = Password 33 | } 34 | : new NullAuthenticator(); 35 | } 36 | return _auth; 37 | } 38 | set => _auth = value; 39 | } 40 | 41 | /// 42 | /// The name of the user for basic authentication. 43 | /// 44 | /// The name of the user. 45 | public string UserName { get; set; } 46 | 47 | /// 48 | /// The password for basic authentication. 49 | /// 50 | /// The password. 51 | public string Password { get; set; } 52 | } 53 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.MailKit/MailerModel/MkSmtpMailerSettings.cs: -------------------------------------------------------------------------------- 1 | using NullDesk.Extensions.Mailer.Core; 2 | 3 | // ReSharper disable once CheckNamespace 4 | namespace NullDesk.Extensions.Mailer.MailKit 5 | { 6 | /// 7 | /// Mailkit SMTP mailer settings. 8 | /// 9 | /// 10 | public class MkSmtpMailerSettings : SmtpMailerSettings 11 | { 12 | /// 13 | /// Require SSL connection. 14 | /// 15 | /// When false, SSL may still be used if the SMTP server indicates that it supports it. 16 | /// true if using SSL; otherwise, false. 17 | public bool SmtpRequireSsl { get; set; } = false; 18 | 19 | /// 20 | /// Indicates if validation for server SSL certificates is used, set false for untrusted or self-signed 21 | /// certificates. 22 | /// 23 | /// true if [disable SSL server certificate validation]; otherwise, false. 24 | public bool EnableSslServerCertificateValidation { get; set; } = true; 25 | 26 | /// 27 | /// Gets or sets the template settings. 28 | /// 29 | /// The template settings. 30 | public MkFileTemplateSettings TemplateSettings { get; set; } 31 | 32 | /// 33 | /// Gets or sets the authentication settings. 34 | /// 35 | /// The authentication settings. 36 | public MkSmtpAuthenticationSettings AuthenticationSettings { get; set; } = new MkSmtpAuthenticationSettings(); 37 | } 38 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.MailKit/NullDesk.Extensions.Mailer.MailKit.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | NullDesk Mailer Extensions for SMTP Email messaging using MailKit 4 | 8.5.0 5 | Stephen M. Redd 6 | net8.0 7 | true 8 | true 9 | portable 10 | true 11 | NullDesk.Extensions.Mailer.MailKit 12 | NullDesk.Extensions.Mailer.MailKit 13 | email;nulldesk;mailkit 14 | https://github.com/NullDesk/NullMailer 15 | MIT 16 | git 17 | https://github.com/NullDesk/NullMailer 18 | false 19 | false 20 | false 21 | Stephen M. Redd 2017 22 | true 23 | snupkg 24 | README.md 25 | 26 | 27 | 28 | True 29 | \ 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.SendGrid/MailerModel/SendGridMailerSettings.cs: -------------------------------------------------------------------------------- 1 | using NullDesk.Extensions.Mailer.Core; 2 | 3 | // ReSharper disable once CheckNamespace 4 | namespace NullDesk.Extensions.Mailer.SendGrid 5 | { 6 | /// 7 | /// Settings for the SendGrid Mailer. 8 | /// 9 | /// 10 | public class SendGridMailerSettings : IMailerSettings 11 | { 12 | /// 13 | /// SendGrid API Key 14 | /// 15 | /// 16 | public string ApiKey { get; set; } 17 | 18 | /// 19 | /// Indicates if SendGrid should be used in SandBox mode 20 | /// 21 | /// 22 | public bool IsSandboxMode { get; set; } = true; 23 | 24 | /// 25 | /// From Email Address 26 | /// 27 | /// 28 | public string FromEmailAddress { get; set; } 29 | 30 | /// 31 | /// From display name. 32 | /// 33 | /// From display name. 34 | public string FromDisplayName { get; set; } 35 | 36 | /// 37 | /// Reply to email address. 38 | /// 39 | /// The reply to email address. 40 | public string ReplyToEmailAddress { get; set; } 41 | 42 | /// 43 | /// Reply to display name. 44 | /// 45 | /// The display name of the reply to address. 46 | public string ReplyToDisplayName { get; set; } 47 | } 48 | } -------------------------------------------------------------------------------- /src/NullDesk.Extensions.Mailer.SendGrid/NullDesk.Extensions.Mailer.SendGrid.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | NullDesk Mailer Extensions for Email messaging using SendGrid API services 4 | 8.5.0 5 | Stephen M. Redd 6 | net8.0 7 | true 8 | true 9 | portable 10 | true 11 | NullDesk.Extensions.Mailer.SendGrid 12 | NullDesk.Extensions.Mailer.SendGrid 13 | email;nulldesk;sendgrid 14 | https://github.com/NullDesk/NullMailer 15 | MIT 16 | git 17 | https://github.com/NullDesk/NullMailer 18 | false 19 | false 20 | false 21 | Stephen M. Redd 2017 22 | true 23 | snupkg 24 | README.md 25 | 26 | 27 | 28 | True 29 | \ 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.Core.Tests/Infrastructure/HistorySerializationFixture.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Extensions.DependencyInjection; 3 | 4 | namespace NullDesk.Extensions.Mailer.Core.Tests.Infrastructure 5 | { 6 | public class HistorySerializationFixture : IDisposable 7 | { 8 | public HistorySerializationFixture() 9 | { 10 | //setup the dependency injection service 11 | var services = new ServiceCollection(); 12 | 13 | services.AddSingleton( 14 | s => new InMemoryHistoryStore(new StandardHistoryStoreSettings 15 | { 16 | SourceApplicationName = "xunit", 17 | StoreAttachmentContents = true 18 | })); 19 | 20 | ServiceProvider = services.BuildServiceProvider(); 21 | } 22 | 23 | public IServiceProvider ServiceProvider { get; set; } 24 | 25 | public void Dispose() 26 | { 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.Core.Tests/MessageBuidler.BuildFromStep.BuildFromWithDisplayStep.Tests.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using NullDesk.Extensions.Mailer.Core.Fluent; 3 | using Xunit; 4 | 5 | namespace NullDesk.Extensions.Mailer.Core.Tests 6 | { 7 | public class BuildFromWithDisplayStepTests 8 | { 9 | [Fact] 10 | [Trait("TestType", "Unit")] 11 | public void BuildFromWithDisplayStep_And() 12 | { 13 | var stepBuilder = new MessageBuilder.BuildFromStep.BuildFromWithDisplayStep(new MailerMessage()); 14 | var subStep = stepBuilder.And; 15 | subStep 16 | .Should() 17 | .NotBeNull() 18 | .And.BeOfType(); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.Core.Tests/MessageBuidler.BuildFromStep.Tests.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using NullDesk.Extensions.Mailer.Core.Fluent; 3 | using NullDesk.Extensions.Mailer.Core.Fluent.Extensions; 4 | using Xunit; 5 | 6 | namespace NullDesk.Extensions.Mailer.Core.Tests 7 | { 8 | public class BuldFromStepTests 9 | { 10 | [Theory] 11 | [InlineData("Mr Toast")] 12 | [InlineData("")] 13 | [InlineData(null)] 14 | [Trait("TestType", "Unit")] 15 | public void BuldFromStep_WithDisplayName(string name) 16 | { 17 | var stepBuilder = new MessageBuilder.BuildFromStep(new MailerMessage().From("toast@toast.com")); 18 | var subStep = stepBuilder.WithDisplayName(name); 19 | subStep 20 | .Should() 21 | .NotBeNull() 22 | .And.BeOfType() 23 | .Which.As() 24 | .Message.From 25 | .Should() 26 | .NotBeNull() 27 | .And.BeOfType() 28 | .Which 29 | .DisplayName 30 | .Should() 31 | .Be(name) 32 | .And 33 | .BeEquivalentTo( 34 | stepBuilder.As() 35 | ? 36 | .Message? 37 | .From? 38 | .DisplayName); 39 | } 40 | 41 | [Fact] 42 | [Trait("TestType", "Unit")] 43 | public void BuldFromStep_And() 44 | { 45 | var stepBuilder = new MessageBuilder.BuildFromStep(new MailerMessage().From("toast@toast.com")); 46 | var subStep = stepBuilder.And; 47 | subStep 48 | .Should() 49 | .NotBeNull() 50 | .And.BeOfType(); 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.Core.Tests/MessageBuilder.BuildContentStep.BuildBodyStep.BuildBodyCompleteStep.Tests.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using NullDesk.Extensions.Mailer.Core.Fluent; 3 | using Xunit; 4 | 5 | namespace NullDesk.Extensions.Mailer.Core.Tests 6 | { 7 | public class BuildBodyCompleteStep 8 | { 9 | [Fact] 10 | [Trait("TestType", "Unit")] 11 | public void BuildBodyComplete_And() 12 | { 13 | var contentStep = 14 | new MessageBuilder.BuildContentStep.BuildBodyStep.BuildBodyCompleteStep(MailerMessage.Create()); 15 | contentStep.And 16 | .Should() 17 | .NotBeNull() 18 | .And.BeOfType(); 19 | } 20 | 21 | [Fact] 22 | [Trait("TestType", "Unit")] 23 | public void BuildBodyComplete_Build() 24 | { 25 | var contentStep = 26 | new MessageBuilder.BuildContentStep.BuildBodyStep.BuildBodyCompleteStep(MailerMessage.Create()); 27 | var message = contentStep.Build(); 28 | message 29 | .Should() 30 | .NotBeNull() 31 | .And.BeOfType(); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.Core.Tests/MessageBuilder.BuildContentStep.BuildBodyStep.BuildHtmlBodyStep.Tests.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using NullDesk.Extensions.Mailer.Core.Fluent; 3 | using NullDesk.Extensions.Mailer.Core.Fluent.Extensions; 4 | using Xunit; 5 | 6 | namespace NullDesk.Extensions.Mailer.Core.Tests 7 | { 8 | public class BuildHtmlBodyStepTests 9 | { 10 | [Theory] 11 | [InlineData("text content")] 12 | [InlineData("")] 13 | [InlineData(null)] 14 | [Trait("TestType", "Unit")] 15 | public void BuildHtmlBodyStep_AndPlainText(string text) 16 | { 17 | var body = new ContentBody().WithHtml("something"); 18 | var contentStep = 19 | new MessageBuilder.BuildContentStep.BuildBodyStep.BuildHtmlBodyStep( 20 | MailerMessage.Create().WithBody(body), body); 21 | var stepBuilder = contentStep.AndPlainText(text); 22 | stepBuilder 23 | .Should() 24 | .NotBeNull() 25 | .And.BeOfType() 26 | .Which.As() 27 | .Message.Body 28 | .As() 29 | .Should().BeEquivalentTo 30 | ( 31 | new ContentBody 32 | { 33 | HtmlContent = "something", 34 | PlainTextContent = text 35 | }, 36 | config => config 37 | .Including(b => b.HtmlContent) 38 | .Including(b => b.PlainTextContent)); 39 | } 40 | 41 | [Fact] 42 | [Trait("TestType", "Unit")] 43 | public void BuildHtmlBodyStep_And() 44 | { 45 | var contentStep = 46 | new MessageBuilder.BuildContentStep.BuildBodyStep.BuildHtmlBodyStep(MailerMessage.Create(), 47 | ContentBody.Create()); 48 | contentStep.And 49 | .Should() 50 | .NotBeNull() 51 | .And.BeOfType(); 52 | } 53 | 54 | [Fact] 55 | [Trait("TestType", "Unit")] 56 | public void BuildHtmlBodyStep_Build() 57 | { 58 | var body = new ContentBody().WithHtml("something"); 59 | var contentStep = 60 | new MessageBuilder.BuildContentStep.BuildBodyStep.BuildHtmlBodyStep( 61 | MailerMessage.Create().WithBody(body), body); 62 | var message = contentStep.Build(); 63 | message 64 | .Should() 65 | .NotBeNull() 66 | .And.BeOfType() 67 | .Which.Body.As() 68 | .HtmlContent 69 | .Should() 70 | .NotBeNullOrEmpty() 71 | .And.Be("something"); 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.Core.Tests/MessageBuilder.BuildContentStep.BuildBodyStep.BuildTextBodyStep.Tests.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using NullDesk.Extensions.Mailer.Core.Fluent; 3 | using NullDesk.Extensions.Mailer.Core.Fluent.Extensions; 4 | using Xunit; 5 | 6 | namespace NullDesk.Extensions.Mailer.Core.Tests 7 | { 8 | public class BuildTextBodyStepTests 9 | { 10 | [Theory] 11 | [InlineData("content")] 12 | [InlineData("")] 13 | [InlineData(null)] 14 | [Trait("TestType", "Unit")] 15 | public void BuildTextBody_AndHtml(string html) 16 | { 17 | var body = new ContentBody().WithPlainText("some text"); 18 | var contentStep = 19 | new MessageBuilder.BuildContentStep.BuildBodyStep.BuildTextBodyStep( 20 | MailerMessage.Create().WithBody(body), body); 21 | var stepBuilder = contentStep.AndHtml(html); 22 | stepBuilder 23 | .Should() 24 | .NotBeNull() 25 | .And.BeOfType() 26 | .Which.As() 27 | .Message.Body 28 | .As() 29 | .Should().BeEquivalentTo 30 | ( 31 | new ContentBody 32 | { 33 | HtmlContent = html, 34 | PlainTextContent = "some text" 35 | }, 36 | config => config 37 | .Including(b => b.HtmlContent) 38 | .Including(b => b.PlainTextContent)); 39 | } 40 | 41 | [Fact] 42 | [Trait("TestType", "Unit")] 43 | public void BuildTextBody_And() 44 | { 45 | var contentStep = 46 | new MessageBuilder.BuildContentStep.BuildBodyStep.BuildTextBodyStep(MailerMessage.Create(), 47 | ContentBody.Create()); 48 | contentStep.And 49 | .Should() 50 | .NotBeNull() 51 | .And.BeOfType(); 52 | } 53 | 54 | [Fact] 55 | [Trait("TestType", "Unit")] 56 | public void BuildTextBody_Build() 57 | { 58 | var body = new ContentBody().WithPlainText("some text"); 59 | var contentStep = 60 | new MessageBuilder.BuildContentStep.BuildBodyStep.BuildTextBodyStep( 61 | MailerMessage.Create().WithBody(body), body); 62 | 63 | var message = contentStep.Build(); 64 | message 65 | .Should() 66 | .NotBeNull() 67 | .And.BeOfType() 68 | .Which.Body.As() 69 | .PlainTextContent 70 | .Should() 71 | .NotBeNullOrEmpty() 72 | .And.Be("some text"); 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.Core.Tests/MessageBuilder.BuildContentStep.BuildBodyStep.Tests.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using NullDesk.Extensions.Mailer.Core.Fluent; 3 | using Xunit; 4 | 5 | namespace NullDesk.Extensions.Mailer.Core.Tests 6 | { 7 | public class BuildBodyStepTests 8 | { 9 | [Theory] 10 | [InlineData("content")] 11 | [InlineData("")] 12 | [InlineData(null)] 13 | [Trait("TestType", "Unit")] 14 | public void BuildBodyStep_WithHtml(string html) 15 | { 16 | var contentStep = new MessageBuilder.BuildContentStep.BuildBodyStep(MailerMessage.Create()); 17 | var stepBuilder = contentStep.WithHtml(html); 18 | stepBuilder 19 | .Should() 20 | .NotBeNull() 21 | .And.BeOfType() 22 | .Which.As() 23 | .Message.Body 24 | .As() 25 | .HtmlContent 26 | .Should() 27 | .Be(html); 28 | } 29 | 30 | [Theory] 31 | [InlineData("text content")] 32 | [InlineData("")] 33 | [InlineData(null)] 34 | [Trait("TestType", "Unit")] 35 | public void BuildBodyStep_WithPlainText(string text) 36 | { 37 | var contentStep = new MessageBuilder.BuildContentStep.BuildBodyStep(MailerMessage.Create()); 38 | var stepBuilder = contentStep.WithPlainText(text); 39 | stepBuilder 40 | .Should() 41 | .NotBeNull() 42 | .And.BeOfType() 43 | .Which.As() 44 | .Message.Body 45 | .As() 46 | .PlainTextContent 47 | .Should() 48 | .Be(text); 49 | } 50 | } 51 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.Core.Tests/MessageBuilder.BuildContentStep.BuildContentTemplateStep.Tests.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using NullDesk.Extensions.Mailer.Core.Fluent; 3 | using NullDesk.Extensions.Mailer.Core.Fluent.Extensions; 4 | using Xunit; 5 | 6 | namespace NullDesk.Extensions.Mailer.Core.Tests 7 | { 8 | public class BuildContentTemplateStepTests 9 | { 10 | [Fact] 11 | [Trait("TestType", "Unit")] 12 | public void BuildContentTemplate_Build() 13 | { 14 | var contentStep = 15 | new MessageBuilder.BuildContentStep.BuildContentTemplateStep( 16 | new MailerMessage().WithBody(b => b.TemplateName = "toast")); 17 | var message = contentStep.Build(); 18 | message 19 | .Should() 20 | .NotBeNull() 21 | .And.BeOfType() 22 | .Which.Body.As() 23 | .TemplateName 24 | .Should() 25 | .NotBeNullOrEmpty() 26 | .And.Be("toast"); 27 | } 28 | 29 | [Fact] 30 | [Trait("TestType", "Unit")] 31 | public void BuildContentTemplate_ForBody() 32 | { 33 | var contentStep = 34 | new MessageBuilder.BuildContentStep.BuildContentTemplateStep( 35 | new MailerMessage().WithBody(b => b.TemplateName = "toast")); 36 | var stepBuilder = contentStep.And; 37 | stepBuilder 38 | .Should() 39 | .NotBeNull() 40 | .And.BeOfType(); 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.Core.Tests/MessageBuilder.BuildContentStep.Tests.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using NullDesk.Extensions.Mailer.Core.Fluent; 3 | using Xunit; 4 | 5 | namespace NullDesk.Extensions.Mailer.Core.Tests 6 | { 7 | public class BuildContentStepTests 8 | { 9 | [Theory] 10 | [InlineData("toast@toast.com")] 11 | [InlineData("")] 12 | [InlineData(null)] 13 | [Trait("TestType", "Unit")] 14 | public void BuildContentStep_To(string address) 15 | { 16 | var contentStep = new MessageBuilder.BuildContentStep(MailerMessage.Create()); 17 | var stepBuilder = contentStep.To(address); 18 | 19 | stepBuilder 20 | .Should() 21 | .NotBeNull() 22 | .And.BeOfType() 23 | .Which.As() 24 | .Message.Recipients 25 | .Should() 26 | .NotBeNull() 27 | .And.NotBeEmpty() 28 | .And.AllBeAssignableTo() 29 | .And.Contain(r => r.EmailAddress == address); 30 | } 31 | 32 | [Theory] 33 | [InlineData("toast")] 34 | [InlineData("")] 35 | [InlineData(null)] 36 | [Trait("TestType", "Unit")] 37 | public void BuildContentStep_ForTemplate(string templateName) 38 | { 39 | var contentStep = new MessageBuilder.BuildContentStep(MailerMessage.Create()); 40 | var stepBuilder = contentStep.ForTemplate(templateName); 41 | stepBuilder 42 | .Should() 43 | .NotBeNull() 44 | .And.BeOfType() 45 | .Which.As() 46 | .Message.Body.As() 47 | .TemplateName 48 | .Should() 49 | .Be(templateName); 50 | } 51 | 52 | [Fact] 53 | [Trait("TestType", "Unit")] 54 | public void BuildContentStep_ForBody() 55 | { 56 | var contentStep = new MessageBuilder.BuildContentStep(MailerMessage.Create()); 57 | var stepBuilder = contentStep.ForBody(); 58 | stepBuilder 59 | .Should() 60 | .NotBeNull() 61 | .And.BeOfType(); 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.Core.Tests/MessageBuilder.BuildRecipientsStep.BuldToStep.BuildRecipientSubstitutionStep.Tests.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using NullDesk.Extensions.Mailer.Core.Fluent; 3 | using NullDesk.Extensions.Mailer.Core.Fluent.Extensions; 4 | using System; 5 | using Xunit; 6 | 7 | namespace NullDesk.Extensions.Mailer.Core.Tests 8 | { 9 | public class BuiltToWithDisplayStepTests 10 | { 11 | [Theory] 12 | [InlineData("toast@toast.com", "a", "b")] 13 | [InlineData("toast@toast.com", "", "d")] 14 | [InlineData("toast@toast.com", "e", "")] 15 | [InlineData("toast@toast.com", null, "g")] 16 | [InlineData("toast@toast.com", "h", null)] 17 | [Trait("TestType", "Unit")] 18 | public void BuiltToWithDisplayStep_WithPersonalizedSubstitution(string address, string token, string value) 19 | { 20 | var rec = new MessageRecipient().ToAddress(address); 21 | var toStep = 22 | new MessageBuilder.BuildRecipientsStep.BuildToStep.BuiltToWithDisplayStep(new MailerMessage().To(rec), 23 | rec); 24 | if (token == null) 25 | { 26 | toStep.Invoking(c => c.WithPersonalizedSubstitution(null, value)).Should().Throw(); 27 | } 28 | else 29 | { 30 | var stepBuilder = toStep.WithPersonalizedSubstitution(token, value); 31 | 32 | stepBuilder 33 | .Should() 34 | .NotBeNull() 35 | .And 36 | .BeOfType() 37 | .Which.As() 38 | .Message.Recipients 39 | .Should() 40 | .NotBeEmpty() 41 | .And.AllBeAssignableTo() 42 | .And.ContainSingle(r => r.EmailAddress == address) 43 | .Which.PersonalizedSubstitutions.Should() 44 | .ContainKey(token) 45 | .WhoseValue.Should() 46 | .Be(value); 47 | } 48 | } 49 | 50 | [Fact] 51 | [Trait("TestType", "Unit")] 52 | public void BuiltToWithDisplayStep_And() 53 | { 54 | var rec = new MessageRecipient().ToAddress("toast@toast.com"); 55 | var toStep = 56 | new MessageBuilder.BuildRecipientsStep.BuildToStep.BuiltToWithDisplayStep(new MailerMessage().To(rec), 57 | rec); 58 | toStep.And 59 | .Should() 60 | .NotBeNull() 61 | .And.BeOfType(); 62 | } 63 | } 64 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.Core.Tests/MessageBuilder.BuildRecipientsStep.BuldToStep.BuildRecipientWithDisplaySubstitutionStep.Tests.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using NullDesk.Extensions.Mailer.Core.Fluent; 3 | using NullDesk.Extensions.Mailer.Core.Fluent.Extensions; 4 | using System; 5 | using Xunit; 6 | 7 | namespace NullDesk.Extensions.Mailer.Core.Tests 8 | { 9 | public class BuildRecipientWithDisplaySubstitutionStepTests 10 | { 11 | [Theory] 12 | [InlineData("toast@toast.com", "a", "b")] 13 | [InlineData("toast@toast.com", "", "d")] 14 | [InlineData("toast@toast.com", "e", "")] 15 | [InlineData("toast@toast.com", null, "g")] 16 | [InlineData("toast@toast.com", "h", null)] 17 | [Trait("TestType", "Unit")] 18 | public void BuildRecipientWithDisplaySubstitutionStep_WithPersonalizedSubstitution(string address, string token, 19 | string value) 20 | { 21 | var rec = new MessageRecipient().ToAddress(address); 22 | var toStep = 23 | new MessageBuilder.BuildRecipientsStep.BuildToStep.BuildRecipientWithDisplaySubstitutionStep( 24 | new MailerMessage().To(rec), rec); 25 | if (token == null) 26 | { 27 | toStep.Invoking(c => c.WithPersonalizedSubstitution(null, value)).Should().Throw(); 28 | } 29 | else 30 | { 31 | var stepBuilder = toStep.WithPersonalizedSubstitution(token, value); 32 | 33 | stepBuilder 34 | .Should() 35 | .NotBeNull() 36 | .And 37 | .BeOfType() 38 | .Which.As() 39 | .Message.Recipients 40 | .Should() 41 | .NotBeEmpty() 42 | .And.AllBeAssignableTo() 43 | .And.ContainSingle(r => r.EmailAddress == address) 44 | .Which.PersonalizedSubstitutions.Should() 45 | .ContainKey(token) 46 | .WhoseValue.Should() 47 | .Be(value); 48 | } 49 | } 50 | 51 | [Fact] 52 | [Trait("TestType", "Unit")] 53 | public void BuildRecipientWithDisplaySubstitutionStep_And() 54 | { 55 | var rec = new MessageRecipient().ToAddress("toast@toast.com"); 56 | var toStep = 57 | new MessageBuilder.BuildRecipientsStep.BuildToStep.BuildRecipientWithDisplaySubstitutionStep( 58 | new MailerMessage().To(rec), rec); 59 | toStep.And 60 | .Should() 61 | .NotBeNull() 62 | .And.BeOfType(); 63 | } 64 | } 65 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.Core.Tests/MessageBuilder.BuildRecipientsStep.Tests.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using NullDesk.Extensions.Mailer.Core.Fluent; 3 | using Xunit; 4 | 5 | namespace NullDesk.Extensions.Mailer.Core.Tests 6 | { 7 | public class BuildRecipientsStepTests 8 | { 9 | [Theory] 10 | [InlineData("toast@toast.com")] 11 | [InlineData("")] 12 | [InlineData(null)] 13 | [Trait("TestType", "Unit")] 14 | public void BuildRecipientsStep_To(string address) 15 | { 16 | var recipientStep = new MessageBuilder.BuildRecipientsStep(new MailerMessage()); 17 | var stepBuilder = recipientStep.To(address); 18 | 19 | stepBuilder 20 | .Should() 21 | .NotBeNull() 22 | .And.BeOfType() 23 | .Which.As() 24 | .Message.Recipients 25 | .Should() 26 | .NotBeNull() 27 | .And.NotBeEmpty() 28 | .And.AllBeAssignableTo() 29 | .And.Contain(r => r.EmailAddress == address); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.Core.Tests/MessageBuilder.BuildSubjectStep.BuildWithSubjectStep.Tests.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using NullDesk.Extensions.Mailer.Core.Fluent; 3 | using Xunit; 4 | 5 | namespace NullDesk.Extensions.Mailer.Core.Tests 6 | { 7 | public class BuildWithSubjectStepTests 8 | { 9 | [Fact] 10 | [Trait("TestType", "Unit")] 11 | public void BuildWithSubjectStep_And() 12 | { 13 | var stepBuilder = new MessageBuilder.BuildSubjectStep.BuildWithSubjectStep(new MailerMessage()); 14 | var subStep = stepBuilder.And; 15 | subStep 16 | .Should() 17 | .NotBeNull() 18 | .And.BeOfType(); 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.Core.Tests/MessageBuilder.BuildSubjectStep.Tests.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using NullDesk.Extensions.Mailer.Core.Fluent; 3 | using Xunit; 4 | 5 | namespace NullDesk.Extensions.Mailer.Core.Tests 6 | { 7 | public class BuildSubjectStepTests 8 | { 9 | [Theory] 10 | [InlineData("Some Subject")] 11 | [InlineData("")] 12 | [InlineData(null)] 13 | [Trait("TestType", "Unit")] 14 | public void BuildSubjectStep_Subject(string subject) 15 | { 16 | var stepBuilder = new MessageBuilder.BuildSubjectStep(new MailerMessage()); 17 | var subStep = stepBuilder.Subject(subject); 18 | 19 | subStep 20 | .Should() 21 | .NotBeNull() 22 | .And.BeOfType() 23 | .Which.As() 24 | .Message.Subject 25 | .Should() 26 | .Be(subject); 27 | } 28 | 29 | [Fact] 30 | [Trait("TestType", "Unit")] 31 | public void BuildSubjectStep_WithoutSubject() 32 | { 33 | var stepBuilder = new MessageBuilder.BuildSubjectStep(new MailerMessage()); 34 | var subStep = stepBuilder.WithOutSubject(); 35 | subStep 36 | .Should() 37 | .NotBeNull() 38 | .And.BeOfType() 39 | .Which.As() 40 | .Message.Subject 41 | .Should() 42 | .BeNull(); 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.Core.Tests/MessageBuilder.Tests.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using NullDesk.Extensions.Mailer.Core.Fluent; 3 | using Xunit; 4 | 5 | namespace NullDesk.Extensions.Mailer.Core.Tests 6 | { 7 | public class MessageBuilderTests 8 | { 9 | [Theory] 10 | [InlineData("toast@toast.com")] 11 | [InlineData("")] 12 | [InlineData(null)] 13 | [Trait("TestType", "Unit")] 14 | public void MessageBuilder_From(string address) 15 | { 16 | var messageBuilder = new MessageBuilder(); 17 | var stepBuilder = messageBuilder.From(address); 18 | 19 | stepBuilder 20 | .Should() 21 | .NotBeNull() 22 | .And.BeOfType() 23 | .Which.As() 24 | .Message.From 25 | .Should() 26 | .NotBeNull() 27 | .And.BeOfType() 28 | .Which 29 | .EmailAddress 30 | .Should() 31 | .Be(address) 32 | .And 33 | .BeEquivalentTo( 34 | messageBuilder.As() 35 | ? 36 | .Message? 37 | .From? 38 | .EmailAddress); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.Core.Tests/MessageBuilderBuildPostContentStep.BuildAttachmentOrSubstitutionStep.Tests.cs: -------------------------------------------------------------------------------- 1 | using FluentAssertions; 2 | using NullDesk.Extensions.Mailer.Core.Fluent; 3 | using Xunit; 4 | 5 | namespace NullDesk.Extensions.Mailer.Core.Tests 6 | { 7 | public class BuildAttachmentOrSubstitutionStepTests 8 | { 9 | [Fact] 10 | [Trait("TestType", "Unit")] 11 | public void BuildAttachmentOrSubstitutionStep_And() 12 | { 13 | var contentStep = 14 | new MessageBuilder.BuildPostContentStep.BuildAttachmentOrSubstitutionStep(MailerMessage.Create()); 15 | contentStep.And 16 | .Should() 17 | .NotBeNull() 18 | .And.BeOfType(); 19 | } 20 | 21 | [Fact] 22 | [Trait("TestType", "Unit")] 23 | public void BuildAttachmentOrSubstitutionStep_Build() 24 | { 25 | var contentStep = 26 | new MessageBuilder.BuildPostContentStep.BuildAttachmentOrSubstitutionStep(MailerMessage.Create()); 27 | var message = contentStep.Build(); 28 | message 29 | .Should() 30 | .NotBeNull() 31 | .And.BeOfType(); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.Core.Tests/NullDesk.Extensions.Mailer.Core.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net9.0 5 | false 6 | 7 | 8 | 9 | 10 | PreserveNewest 11 | 12 | 13 | 14 | 15 | 16 | 17 | all 18 | runtime; build; native; contentfiles; analyzers; buildtransitive 19 | 20 | 21 | 22 | 23 | 24 | all 25 | runtime; build; native; contentfiles; analyzers; buildtransitive 26 | 27 | 28 | 29 | 30 | all 31 | runtime; build; native; contentfiles; analyzers; buildtransitive 32 | 33 | 34 | all 35 | runtime; build; native; contentfiles; analyzers 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.Core.Tests/xunit.runner.json: -------------------------------------------------------------------------------- 1 | { 2 | "methodDisplay": "method", 3 | "preEnumerateTheories": true 4 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer.Tests/Infrastructure/SqlIntegrationFixture.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.Extensions.DependencyInjection; 2 | using Microsoft.Extensions.Logging; 3 | using Microsoft.Extensions.Options; 4 | using NullDesk.Extensions.Mailer.Core; 5 | using System; 6 | 7 | namespace NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer.Tests.Infrastructure 8 | { 9 | public class SqlIntegrationFixture : IDisposable 10 | { 11 | public SqlIntegrationFixture() 12 | { 13 | //setup the dependency injection service 14 | var services = new ServiceCollection(); 15 | services.AddLogging(config => config.AddDebug().SetMinimumLevel(LogLevel.Debug)); 16 | services.AddOptions(); 17 | services.Configure(s => 18 | { 19 | s.FromDisplayName = "xunit"; 20 | s.FromEmailAddress = "xunit@nowhere.com"; 21 | }); 22 | 23 | 24 | services.AddMailerHistory(new SqlEntityHistoryStoreSettings 25 | { 26 | SourceApplicationName = "xunit", 27 | ConnectionString = 28 | @"Server=(localdb)\MSSQLLocalDB;Database=NullDeskMailerHistoryTests;Trusted_Connection=True;" 29 | }); 30 | 31 | services.AddNullMailer(s => s.GetService>().Value); 32 | 33 | ServiceProvider = services.BuildServiceProvider(); 34 | 35 | } 36 | 37 | public IServiceProvider ServiceProvider { get; set; } 38 | 39 | 40 | public void Dispose() 41 | { 42 | using (var context = 43 | ((EntityHistoryStore)ServiceProvider.GetService()) 44 | .GetHistoryContext()) 45 | { 46 | context.Database.EnsureDeleted(); 47 | } 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer.Tests/Infrastructure/TestSqlHistoryContext.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | 3 | namespace NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer.Tests.Infrastructure 4 | { 5 | public class TestSqlHistoryContext : SqlHistoryContext 6 | { 7 | public TestSqlHistoryContext(DbContextOptions options) : base(options) 8 | { 9 | } 10 | 11 | public override void InitializeDatabase() 12 | { 13 | Database.EnsureDeleted(); 14 | Database.EnsureCreated(); 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer.Tests/Infrastructure/TestSqlHistoryContextFactory.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | using Microsoft.EntityFrameworkCore.Design; 3 | 4 | namespace NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer.Tests.Infrastructure 5 | { 6 | /// 7 | /// Class TestSqlHistoryContextFactory. 8 | /// 9 | /// 10 | /// The connection details aren't that important, this a work around to allow ef tooling to function correctly from a 11 | /// class library. 12 | /// 13 | public class TestSqlHistoryContextFactory : IDesignTimeDbContextFactory 14 | { 15 | /// 16 | /// Creates a new instance of the context. 17 | /// 18 | /// Arguments provided by the design-time service. 19 | /// An instance of . 20 | /// Used by EF CLI tooling 21 | public TestSqlHistoryContext CreateDbContext(string[] args) 22 | { 23 | var builder = new DbContextOptionsBuilder(); 24 | 25 | builder.UseSqlServer( 26 | @"Server=(localdb)\MSSQLLocalDB;Database=NullMailerHistory;Trusted_Connection=True;"); 27 | return new TestSqlHistoryContext(builder.Options); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer.Tests/Migrations/20170314025003_Initial.Designer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Infrastructure; 4 | using Microsoft.EntityFrameworkCore.Metadata; 5 | using Microsoft.EntityFrameworkCore.Migrations; 6 | using NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer.Tests.Infrastructure; 7 | 8 | namespace NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer.Tests.Migrations 9 | { 10 | [DbContext(typeof(TestSqlHistoryContext))] 11 | [Migration("20170314025003_Initial")] 12 | partial class Initial 13 | { 14 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 15 | { 16 | modelBuilder 17 | .HasAnnotation("ProductVersion", "1.1.1") 18 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 19 | 20 | modelBuilder.Entity("NullDesk.Extensions.Mailer.History.EntityFramework.EntityHistoryDeliveryItem", b => 21 | { 22 | b.Property("Id") 23 | .ValueGeneratedOnAdd(); 24 | 25 | b.Property("AttachmentsJson"); 26 | 27 | b.Property("CreatedDate"); 28 | 29 | b.Property("DeliveryProvider") 30 | .HasMaxLength(100); 31 | 32 | b.Property("ExceptionMessage") 33 | .HasMaxLength(500); 34 | 35 | b.Property("FromDisplayName") 36 | .HasMaxLength(200); 37 | 38 | b.Property("FromEmailAddress") 39 | .HasMaxLength(200); 40 | 41 | b.Property("HtmlContent"); 42 | 43 | b.Property("IsSuccess"); 44 | 45 | b.Property("ProviderMessageId") 46 | .HasMaxLength(200); 47 | 48 | b.Property("Subject") 49 | .HasMaxLength(200); 50 | 51 | b.Property("SubstitutionsJson"); 52 | 53 | b.Property("TemplateName") 54 | .HasMaxLength(255); 55 | 56 | b.Property("TextContent"); 57 | 58 | b.Property("ToDisplayName") 59 | .HasMaxLength(200); 60 | 61 | b.Property("ToEmailAddress") 62 | .HasMaxLength(200); 63 | 64 | b.HasKey("Id"); 65 | 66 | b.ToTable("MessageHistory"); 67 | }); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer.Tests/Migrations/20170314025003_Initial.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore.Migrations; 3 | 4 | namespace NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer.Tests.Migrations 5 | { 6 | public partial class Initial : Migration 7 | { 8 | protected override void Up(MigrationBuilder migrationBuilder) 9 | { 10 | migrationBuilder.CreateTable( 11 | "MessageHistory", 12 | table => new 13 | { 14 | Id = table.Column(nullable: false), 15 | AttachmentsJson = table.Column(nullable: true), 16 | CreatedDate = table.Column(nullable: false), 17 | DeliveryProvider = table.Column(maxLength: 100, nullable: true), 18 | ExceptionMessage = table.Column(maxLength: 500, nullable: true), 19 | FromDisplayName = table.Column(maxLength: 200, nullable: true), 20 | FromEmailAddress = table.Column(maxLength: 200, nullable: true), 21 | HtmlContent = table.Column(nullable: true), 22 | IsSuccess = table.Column(nullable: false), 23 | ProviderMessageId = table.Column(maxLength: 200, nullable: true), 24 | Subject = table.Column(maxLength: 200, nullable: true), 25 | SubstitutionsJson = table.Column(nullable: true), 26 | TemplateName = table.Column(maxLength: 255, nullable: true), 27 | TextContent = table.Column(nullable: true), 28 | ToDisplayName = table.Column(maxLength: 200, nullable: true), 29 | ToEmailAddress = table.Column(maxLength: 200, nullable: true) 30 | }, 31 | constraints: table => { table.PrimaryKey("PK_MessageHistory", x => x.Id); }); 32 | } 33 | 34 | protected override void Down(MigrationBuilder migrationBuilder) 35 | { 36 | migrationBuilder.DropTable( 37 | "MessageHistory"); 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer.Tests/Migrations/20170528045718_ReplyTo.Designer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Infrastructure; 4 | using Microsoft.EntityFrameworkCore.Metadata; 5 | using Microsoft.EntityFrameworkCore.Migrations; 6 | using NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer.Tests.Infrastructure; 7 | 8 | namespace NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer.Tests.Migrations 9 | { 10 | [DbContext(typeof(TestSqlHistoryContext))] 11 | [Migration("20170528045718_ReplyTo")] 12 | partial class ReplyTo 13 | { 14 | protected override void BuildTargetModel(ModelBuilder modelBuilder) 15 | { 16 | modelBuilder 17 | .HasAnnotation("ProductVersion", "1.1.2") 18 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 19 | 20 | modelBuilder.Entity("NullDesk.Extensions.Mailer.History.EntityFramework.EntityHistoryDeliveryItem", b => 21 | { 22 | b.Property("Id") 23 | .ValueGeneratedOnAdd(); 24 | 25 | b.Property("AttachmentsJson"); 26 | 27 | b.Property("CreatedDate"); 28 | 29 | b.Property("DeliveryProvider") 30 | .HasMaxLength(100); 31 | 32 | b.Property("ExceptionMessage") 33 | .HasMaxLength(500); 34 | 35 | b.Property("FromDisplayName") 36 | .HasMaxLength(200); 37 | 38 | b.Property("FromEmailAddress") 39 | .HasMaxLength(200); 40 | 41 | b.Property("HtmlContent"); 42 | 43 | b.Property("IsSuccess"); 44 | 45 | b.Property("ProviderMessageId") 46 | .HasMaxLength(200); 47 | 48 | b.Property("ReplyToDisplayName") 49 | .HasMaxLength(200); 50 | 51 | b.Property("ReplyToEmailAddress") 52 | .HasMaxLength(200); 53 | 54 | b.Property("Subject") 55 | .HasMaxLength(200); 56 | 57 | b.Property("SubstitutionsJson"); 58 | 59 | b.Property("TemplateName") 60 | .HasMaxLength(255); 61 | 62 | b.Property("TextContent"); 63 | 64 | b.Property("ToDisplayName") 65 | .HasMaxLength(200); 66 | 67 | b.Property("ToEmailAddress") 68 | .HasMaxLength(200); 69 | 70 | b.HasKey("Id"); 71 | 72 | b.ToTable("MessageHistory"); 73 | }); 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer.Tests/Migrations/20170528045718_ReplyTo.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore.Migrations; 2 | 3 | namespace NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer.Tests.Migrations 4 | { 5 | public partial class ReplyTo : Migration 6 | { 7 | protected override void Up(MigrationBuilder migrationBuilder) 8 | { 9 | migrationBuilder.AddColumn( 10 | "ReplyToDisplayName", 11 | "MessageHistory", 12 | maxLength: 200, 13 | nullable: true); 14 | 15 | migrationBuilder.AddColumn( 16 | "ReplyToEmailAddress", 17 | "MessageHistory", 18 | maxLength: 200, 19 | nullable: true); 20 | } 21 | 22 | protected override void Down(MigrationBuilder migrationBuilder) 23 | { 24 | migrationBuilder.DropColumn( 25 | "ReplyToDisplayName", 26 | "MessageHistory"); 27 | 28 | migrationBuilder.DropColumn( 29 | "ReplyToEmailAddress", 30 | "MessageHistory"); 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer.Tests/Migrations/TestSqlHistoryContextModelSnapshot.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.EntityFrameworkCore.Infrastructure; 4 | using Microsoft.EntityFrameworkCore.Metadata; 5 | using NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer.Tests.Infrastructure; 6 | 7 | namespace NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer.Tests.Migrations 8 | { 9 | [DbContext(typeof(TestSqlHistoryContext))] 10 | internal class TestSqlHistoryContextModelSnapshot : ModelSnapshot 11 | { 12 | protected override void BuildModel(ModelBuilder modelBuilder) 13 | { 14 | modelBuilder 15 | .HasAnnotation("ProductVersion", "1.1.2") 16 | .HasAnnotation("SqlServer:ValueGenerationStrategy", SqlServerValueGenerationStrategy.IdentityColumn); 17 | 18 | modelBuilder.Entity("NullDesk.Extensions.Mailer.History.EntityFramework.EntityHistoryDeliveryItem", b => 19 | { 20 | b.Property("Id") 21 | .ValueGeneratedOnAdd(); 22 | 23 | b.Property("AttachmentsJson"); 24 | 25 | b.Property("CreatedDate"); 26 | 27 | b.Property("DeliveryProvider") 28 | .HasMaxLength(100); 29 | 30 | b.Property("ExceptionMessage") 31 | .HasMaxLength(500); 32 | 33 | b.Property("FromDisplayName") 34 | .HasMaxLength(200); 35 | 36 | b.Property("FromEmailAddress") 37 | .HasMaxLength(200); 38 | 39 | b.Property("HtmlContent"); 40 | 41 | b.Property("IsSuccess"); 42 | 43 | b.Property("ProviderMessageId") 44 | .HasMaxLength(200); 45 | 46 | b.Property("ReplyToDisplayName") 47 | .HasMaxLength(200); 48 | 49 | b.Property("ReplyToEmailAddress") 50 | .HasMaxLength(200); 51 | 52 | b.Property("Subject") 53 | .HasMaxLength(200); 54 | 55 | b.Property("SubstitutionsJson"); 56 | 57 | b.Property("TemplateName") 58 | .HasMaxLength(255); 59 | 60 | b.Property("TextContent"); 61 | 62 | b.Property("ToDisplayName") 63 | .HasMaxLength(200); 64 | 65 | b.Property("ToEmailAddress") 66 | .HasMaxLength(200); 67 | 68 | b.HasKey("Id"); 69 | 70 | b.ToTable("MessageHistory"); 71 | }); 72 | } 73 | } 74 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.History.EntityFramework.SqlServer.Tests/xunit.runner.json: -------------------------------------------------------------------------------- 1 | { 2 | "methodDisplay": "method", 3 | "preEnumerateTheories": true 4 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.History.EntityFramework.Tests/Infrastructure/MemoryEfFixture.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.EntityFrameworkCore; 3 | using Microsoft.Extensions.DependencyInjection; 4 | using Microsoft.Extensions.Logging; 5 | using Microsoft.Extensions.Options; 6 | using NullDesk.Extensions.Mailer.Core; 7 | 8 | namespace NullDesk.Extensions.Mailer.History.EntityFramework.Tests.Infrastructure 9 | { 10 | public class MemoryEfFixture : IDisposable 11 | { 12 | public MemoryEfFixture() 13 | { 14 | //setup the dependency injection service 15 | var services = new ServiceCollection(); 16 | services.AddLogging(config => config.AddDebug().SetMinimumLevel(LogLevel.Debug)); 17 | 18 | services.AddLogging(); 19 | services.AddOptions(); 20 | services.Configure(s => 21 | { 22 | s.FromDisplayName = "xunit"; 23 | s.FromEmailAddress = "xunit@nowhere.com"; 24 | }); 25 | 26 | var builder = new DbContextOptionsBuilder() 27 | .UseInMemoryDatabase("TestHistoryDb"); 28 | 29 | services.AddMailerHistory( 30 | s => new EntityHistoryStoreSettings {DbOptions = builder.Options}); 31 | services.AddNullMailer(s => s.GetService>().Value); 32 | 33 | ServiceProvider = services.BuildServiceProvider(); 34 | 35 | 36 | } 37 | 38 | public IServiceProvider ServiceProvider { get; set; } 39 | 40 | 41 | public void Dispose() 42 | { 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.History.EntityFramework.Tests/Infrastructure/TestHistoryContext.cs: -------------------------------------------------------------------------------- 1 | using Microsoft.EntityFrameworkCore; 2 | 3 | namespace NullDesk.Extensions.Mailer.History.EntityFramework.Tests.Infrastructure 4 | { 5 | public class TestHistoryContext : HistoryContext 6 | { 7 | public TestHistoryContext(DbContextOptions options) : base(options) 8 | { 9 | } 10 | 11 | public override void InitializeDatabase() 12 | { 13 | //do nothing 14 | } 15 | } 16 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.History.EntityFramework.Tests/xunit.runner.json: -------------------------------------------------------------------------------- 1 | { 2 | "methodDisplay": "method", 3 | "preEnumerateTheories": true 4 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.MailKit.Tests/Infrastructure/FactoryMailFixture.cs: -------------------------------------------------------------------------------- 1 | using MailKit.Net.Smtp; 2 | using Microsoft.Extensions.Logging; 3 | using Microsoft.Extensions.Logging.Debug; 4 | using MimeKit; 5 | using NSubstitute; 6 | using NullDesk.Extensions.Mailer.Core; 7 | using System; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | 11 | namespace NullDesk.Extensions.Mailer.MailKit.Tests.Infrastructure 12 | { 13 | public class FactoryMailFixture : MailFixture, IDisposable 14 | { 15 | public FactoryMailFixture() 16 | { 17 | var loggerFactory = new LoggerFactory(new[] { new DebugLoggerProvider() }, new LoggerFilterOptions() { MinLevel = LogLevel.Debug }); 18 | 19 | Mail = new MailerFactory(loggerFactory, Store); 20 | var mkSettings = SetupMailerOptions(out bool isMailServerAlive).Value; 21 | 22 | 23 | if (isMailServerAlive) 24 | { 25 | Mail.AddMkSmtpMailer(mkSettings); 26 | } 27 | else 28 | { 29 | SmtpClient GetClientFunc() 30 | { 31 | var c = Substitute.For(); 32 | c.SendAsync(Arg.Any(), Arg.Any()) 33 | .Returns(Task.FromResult(string.Empty)); 34 | return c; 35 | } 36 | 37 | Mail.AddMkSmtpMailer(GetClientFunc, mkSettings); 38 | } 39 | } 40 | 41 | public MailerFactory Mail { get; set; } 42 | 43 | public IHistoryStore Store { get; set; } = new InMemoryHistoryStore(); 44 | 45 | 46 | public void Dispose() 47 | { 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.MailKit.Tests/Infrastructure/FactorySafetyMailFixture.cs: -------------------------------------------------------------------------------- 1 | using MailKit.Net.Smtp; 2 | using Microsoft.Extensions.Logging; 3 | using Microsoft.Extensions.Logging.Debug; 4 | using MimeKit; 5 | using NSubstitute; 6 | using NullDesk.Extensions.Mailer.Core; 7 | using System; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | 11 | namespace NullDesk.Extensions.Mailer.MailKit.Tests.Infrastructure 12 | { 13 | public class FactorySafetyMailFixture : MailFixture, IDisposable 14 | { 15 | public FactorySafetyMailFixture() 16 | { 17 | var loggerFactory = new LoggerFactory(new[] { new DebugLoggerProvider() }, new LoggerFilterOptions() { MinLevel = LogLevel.Debug }); 18 | 19 | 20 | Mail = new MailerFactory(loggerFactory, Store); 21 | var mkSettings = SetupMailerOptions(out var isMailServerAlive).Value; 22 | 23 | if (isMailServerAlive) 24 | { 25 | Mail.AddSafetyMailer(new SafetyMailerSettings 26 | { 27 | SafeRecipientEmailAddress = "safe@nowhere.com" 28 | }, 29 | mkSettings); 30 | } 31 | else 32 | { 33 | SmtpClient GetClientFunc() 34 | { 35 | var c = Substitute.For(); 36 | c.SendAsync(Arg.Any(), Arg.Any()) 37 | .Returns(Task.FromResult(string.Empty)); 38 | return c; 39 | } 40 | 41 | Mail.AddSafetyMailer(new SafetyMailerSettings 42 | { 43 | SafeRecipientEmailAddress = "safe@nowhere.com" 44 | }, 45 | GetClientFunc, 46 | mkSettings); 47 | } 48 | } 49 | 50 | public MailerFactory Mail { get; set; } 51 | 52 | public IHistoryStore Store { get; set; } = new InMemoryHistoryStore(); 53 | 54 | 55 | public void Dispose() 56 | { 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.MailKit.Tests/Infrastructure/HistoryMailFixture.cs: -------------------------------------------------------------------------------- 1 | using MailKit.Net.Smtp; 2 | using Microsoft.Extensions.Logging; 3 | using Microsoft.Extensions.Logging.Debug; 4 | using MimeKit; 5 | using NSubstitute; 6 | using NullDesk.Extensions.Mailer.Core; 7 | using System; 8 | using System.Threading; 9 | using System.Threading.Tasks; 10 | 11 | namespace NullDesk.Extensions.Mailer.MailKit.Tests.Infrastructure 12 | { 13 | public class HistoryMailFixture : MailFixture, IDisposable 14 | { 15 | public HistoryMailFixture() 16 | { 17 | var loggerFactory = new LoggerFactory(new[] { new DebugLoggerProvider() }, new LoggerFilterOptions() { MinLevel = LogLevel.Debug }); 18 | 19 | 20 | // ReSharper disable once UnusedVariable 21 | var mkSettings = SetupMailerOptions(out bool isMailServerAlive).Value; 22 | 23 | SmtpClient GetClientFunc() 24 | { 25 | var c = Substitute.For(); 26 | c.SendAsync(Arg.Any(), Arg.Any()) 27 | .Returns(Task.FromResult(string.Empty)); 28 | return c; 29 | } 30 | 31 | var logger = loggerFactory.CreateLogger(); 32 | 33 | 34 | MailerFactoryForHistoryWithSerializableAttachments.AddMkSmtpMailer(GetClientFunc, mkSettings, logger, 35 | StoreWithSerializableAttachments); 36 | 37 | MailerFactoryForHistoryWithoutSerializableAttachments.AddMkSmtpMailer(GetClientFunc, mkSettings, logger, 38 | StoreWithoutSerializableAttachments); 39 | } 40 | 41 | public MailerFactory MailerFactoryForHistoryWithSerializableAttachments { get; } = new MailerFactory(); 42 | 43 | public MailerFactory MailerFactoryForHistoryWithoutSerializableAttachments { get; } = new MailerFactory(); 44 | 45 | 46 | public IHistoryStore StoreWithSerializableAttachments { get; set; } = 47 | new InMemoryHistoryStore( 48 | new StandardHistoryStoreSettings { StoreAttachmentContents = true, SourceApplicationName = "xunit" }); 49 | 50 | public IHistoryStore StoreWithoutSerializableAttachments { get; set; } = 51 | new InMemoryHistoryStore( 52 | new StandardHistoryStoreSettings { StoreAttachmentContents = false, SourceApplicationName = "xunit" }); 53 | 54 | 55 | public void Dispose() 56 | { 57 | } 58 | } 59 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.MailKit.Tests/Infrastructure/MailFixture.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Net.Sockets; 4 | using Microsoft.Extensions.Options; 5 | 6 | namespace NullDesk.Extensions.Mailer.MailKit.Tests.Infrastructure 7 | { 8 | public class MailFixture 9 | { 10 | protected OptionsWrapper SetupMailerOptions(out bool isMailServerAlive) 11 | { 12 | var mailOptions = new OptionsWrapper( 13 | new MkSmtpMailerSettings 14 | { 15 | FromDisplayName = "xunit", 16 | FromEmailAddress = "xunit@nowhere.com", 17 | ReplyToEmailAddress = "xunitreply@nowhere.com", 18 | ReplyToDisplayName = "Xunit - NoReply", 19 | SmtpServer = "localhost", 20 | SmtpPort = 25, 21 | SmtpRequireSsl = false, 22 | TemplateSettings = new MkFileTemplateSettings 23 | { 24 | TemplatePath = 25 | Path.GetFullPath(Path.Combine(AppContext.BaseDirectory, @"..\..\..\..\TestData\templates")) 26 | } 27 | }); 28 | 29 | isMailServerAlive = false; 30 | var tcp = new TcpClient(); 31 | try 32 | { 33 | tcp.ConnectAsync(mailOptions.Value.SmtpServer, mailOptions.Value.SmtpPort).Wait(); 34 | isMailServerAlive = tcp.Connected; 35 | } 36 | catch 37 | { 38 | // ignored 39 | } 40 | 41 | tcp.Dispose(); 42 | return mailOptions; 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.MailKit.Tests/Infrastructure/ReusableMailFixture.cs: -------------------------------------------------------------------------------- 1 | using MailKit.Net.Smtp; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using Microsoft.Extensions.Logging; 4 | using Microsoft.Extensions.Options; 5 | using MimeKit; 6 | using NSubstitute; 7 | using NullDesk.Extensions.Mailer.Core; 8 | using System; 9 | using System.Threading; 10 | using System.Threading.Tasks; 11 | 12 | namespace NullDesk.Extensions.Mailer.MailKit.Tests.Infrastructure 13 | { 14 | public class ReusableMailFixture : MailFixture, IDisposable 15 | { 16 | public ReusableMailFixture() 17 | { 18 | var services = new ServiceCollection(); 19 | services.AddLogging(config => config.AddDebug().SetMinimumLevel(LogLevel.Debug)); 20 | 21 | services.AddOptions(); 22 | 23 | services.AddSingleton(); 24 | 25 | var isMailServerAlive = false; 26 | var lazy = new Lazy>(() => SetupMailerOptions(out isMailServerAlive)); 27 | services.AddSingleton(s => 28 | { 29 | var options = lazy.Value; 30 | var client = Substitute.For(); 31 | client 32 | .SendAsync(Arg.Any(), Arg.Any()) 33 | .Returns(Task.FromResult(string.Empty)); 34 | return isMailServerAlive 35 | ? new MkSmtpMailer(options.Value, s.GetService>(), 36 | s.GetService()) 37 | : new MkSmtpMailer(client, options.Value, s.GetService>(), 38 | s.GetService()); 39 | }); 40 | 41 | ServiceProvider = services.BuildServiceProvider(); 42 | } 43 | 44 | public IServiceProvider ServiceProvider { get; set; } 45 | 46 | public void Dispose() 47 | { 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.MailKit.Tests/Infrastructure/StandardMailFixture.cs: -------------------------------------------------------------------------------- 1 | using MailKit.Net.Smtp; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using Microsoft.Extensions.Logging; 4 | using Microsoft.Extensions.Options; 5 | using MimeKit; 6 | using NSubstitute; 7 | using NullDesk.Extensions.Mailer.Core; 8 | using System; 9 | using System.Threading; 10 | using System.Threading.Tasks; 11 | 12 | namespace NullDesk.Extensions.Mailer.MailKit.Tests.Infrastructure 13 | { 14 | public class StandardMailFixture : MailFixture, IDisposable 15 | { 16 | public StandardMailFixture() 17 | { 18 | //setup the dependency injection service 19 | var services = new ServiceCollection(); 20 | services.AddLogging(config => config.AddDebug().SetMinimumLevel(LogLevel.Debug)); 21 | 22 | services.AddOptions(); 23 | 24 | services.AddSingleton(); 25 | 26 | var isMailServerAlive = false; 27 | var lazy = new Lazy>(() => SetupMailerOptions(out isMailServerAlive)); 28 | 29 | services.AddTransient(s => 30 | { 31 | var options = lazy.Value; 32 | var client = Substitute.For(); 33 | client 34 | .SendAsync(Arg.Any(), Arg.Any()) 35 | .Returns(Task.FromResult(string.Empty)); 36 | return isMailServerAlive 37 | ? new MkSmtpMailer(options.Value, s.GetService>(), 38 | s.GetService()) 39 | : new MkSmtpMailer(client, options.Value, s.GetService>(), 40 | s.GetService()); 41 | }); 42 | 43 | 44 | ServiceProvider = services.BuildServiceProvider(); 45 | 46 | } 47 | 48 | public IServiceProvider ServiceProvider { get; set; } 49 | 50 | 51 | public void Dispose() 52 | { 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.MailKit.Tests/MailKitGmailMailerTests.cs: -------------------------------------------------------------------------------- 1 | using NullDesk.Extensions.Mailer.MailKit.Tests.Infrastructure; 2 | using Xunit; 3 | 4 | namespace NullDesk.Extensions.Mailer.MailKit.Tests 5 | { 6 | public class MkGmailMailerTests : IClassFixture 7 | { 8 | public MkGmailMailerTests(GmailMailFixture fixture) 9 | { 10 | Fixture = fixture; 11 | } 12 | 13 | private GmailMailFixture Fixture { get; } 14 | // https://github.com/jstedfast/MailKit/blob/master/FAQ.md#GMailAccess 15 | 16 | //Setup user and password in fixture, then uncomment 17 | 18 | 19 | //[Fact] 20 | //[Trait("TestType", "Integration")] 21 | //public async Task MailKit_Gmail_Basic_SendAll() 22 | //{ 23 | 24 | //var mailer = Fixture.BasicAuthServiceProvider.GetService(); 25 | 26 | //var deliveryItems = 27 | // mailer.CreateMessage(b => b 28 | // .Subject($"xunit Test run: content body") 29 | // .And.To("abc@xyz.net") 30 | // .WithDisplayName("No One Important") 31 | // .And.ForBody() 32 | // .WithPlainText("nothing to see here") 33 | // .Build()); 34 | 35 | //var result = await mailer.SendAllAsync(CancellationToken.None); 36 | 37 | //result 38 | // .Should() 39 | // .NotBeNull() 40 | // .And.AllBeOfType() 41 | // .And.HaveSameCount(deliveryItems) 42 | // .And.OnlyContain(i => i.IsSuccess); 43 | //} 44 | 45 | //[Fact] 46 | //[Trait("TestType", "Integration")] 47 | //public async Task MailKit_Gmail_Token_SendAll() 48 | //{ 49 | 50 | //var mailer = Fixture.TokenAuthServiceProvider.GetService(); 51 | 52 | //var deliveryItems = 53 | // mailer.CreateMessage(b => b 54 | // .Subject($"xunit Test run: content body") 55 | // .And.To("abc@xyz.net") 56 | // .WithDisplayName("No One Important") 57 | // .And.ForBody() 58 | // .WithPlainText("nothing to see here") 59 | // .Build()); 60 | 61 | //var result = await mailer.SendAllAsync(CancellationToken.None); 62 | 63 | //result 64 | // .Should() 65 | // .NotBeNull() 66 | // .And.AllBeOfType() 67 | // .And.HaveSameCount(deliveryItems) 68 | // .And.OnlyContain(i => i.IsSuccess); 69 | //} 70 | } 71 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.MailKit.Tests/appsettings.json: -------------------------------------------------------------------------------- 1 | { 2 | "NoAuthMailSettings": { 3 | "ActiveMailService": "MailKit", 4 | "MkSmtpMailerSettings": { 5 | "FromEmailAddress": "test@test.com", 6 | "FromDisplayName": "Sample Mailer CLI - MailKit", 7 | "SmtpServer": "localhost", 8 | "SmtpPort": 25, 9 | "SmtpRequireSsl": false, 10 | "TemplateSettings": { 11 | "TemplatePath": "./App_Data/Templates", 12 | "HtmlTemplateFileExtensions": [ "html" ], 13 | "TextTemplateFileExtension": [ "txt" ] 14 | } 15 | } 16 | }, 17 | "EmptyAuthMailSettings": { 18 | "ActiveMailService": "MailKit", 19 | "MkSmtpMailerSettings": { 20 | "FromEmailAddress": "test@test.com", 21 | "FromDisplayName": "Sample Mailer CLI - MailKit", 22 | "SmtpServer": "localhost", 23 | "SmtpPort": 25, 24 | "SmtpRequireSsl": false, 25 | "AuthenticationSettings": { 26 | }, 27 | "TemplateSettings": { 28 | "TemplatePath": "./App_Data/Templates", 29 | "HtmlTemplateFileExtensions": [ "html" ], 30 | "TextTemplateFileExtension": [ "txt" ] 31 | } 32 | } 33 | }, 34 | "BasicAuthMailSettings": { 35 | "ActiveMailService": "MailKit", 36 | "MkSmtpMailerSettings": { 37 | "FromEmailAddress": "test@test.com", 38 | "FromDisplayName": "Sample Mailer CLI - MailKit", 39 | "SmtpServer": "localhost", 40 | "SmtpPort": 25, 41 | "SmtpRequireSsl": false, 42 | "AuthenticationSettings": { 43 | "UserName": "toast@toast.com", 44 | "Password": "xyz" 45 | }, 46 | "TemplateSettings": { 47 | "TemplatePath": "./App_Data/Templates", 48 | "HtmlTemplateFileExtensions": [ "html" ], 49 | "TextTemplateFileExtension": [ "txt" ] 50 | } 51 | } 52 | }, 53 | "TokenAuthMailSettings": { 54 | "ActiveMailService": "MailKit", 55 | "MkSmtpMailerSettings": { 56 | "FromEmailAddress": "test@test.com", 57 | "FromDisplayName": "Sample Mailer CLI - MailKit", 58 | "SmtpServer": "localhost", 59 | "SmtpPort": 25, 60 | "SmtpRequireSsl": false, 61 | "EnableSslServerCertificateValidation": false, 62 | "AuthenticationSettings": { 63 | "UserName": "toast@toast.com" 64 | 65 | }, 66 | "TemplateSettings": { 67 | "TemplatePath": "./App_Data/Templates", 68 | "HtmlTemplateFileExtensions": [ "html" ], 69 | "TextTemplateFileExtension": [ "txt" ] 70 | } 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.MailKit.Tests/xunit.runner.json: -------------------------------------------------------------------------------- 1 | { 2 | "methodDisplay": "method", 3 | "preEnumerateTheories": true 4 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.SendGrid.Tests/Infrastructure/FactoryMailFixture.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Extensions.Logging; 3 | using Microsoft.Extensions.Logging.Debug; 4 | using Microsoft.Extensions.Options; 5 | using NullDesk.Extensions.Mailer.Core; 6 | 7 | namespace NullDesk.Extensions.Mailer.SendGrid.Tests.Infrastructure 8 | { 9 | public class FactoryMailFixture : IDisposable 10 | { 11 | public FactoryMailFixture() 12 | { 13 | var loggerFactory = new LoggerFactory(new[] { new DebugLoggerProvider() }, new LoggerFilterOptions() { MinLevel = LogLevel.Debug }); 14 | 15 | 16 | var sendGridSettings = new SendGridMailerSettings 17 | { 18 | ApiKey = "abc", 19 | FromDisplayName = "xunit", 20 | FromEmailAddress = "xunit@nowhere.com" 21 | }; 22 | 23 | var logger = loggerFactory.CreateLogger(); 24 | 25 | Mail.Register(() => new SendGridMailerFake( 26 | new OptionsWrapper(sendGridSettings), 27 | logger, 28 | Store)); 29 | } 30 | 31 | public MailerFactory Mail { get; } = new MailerFactory(); 32 | 33 | 34 | public IHistoryStore Store { get; set; } = new InMemoryHistoryStore(); 35 | 36 | 37 | public void Dispose() 38 | { 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.SendGrid.Tests/Infrastructure/HistoryMailFixture.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Extensions.Logging; 3 | using Microsoft.Extensions.Logging.Debug; 4 | using Microsoft.Extensions.Options; 5 | using NullDesk.Extensions.Mailer.Core; 6 | 7 | namespace NullDesk.Extensions.Mailer.SendGrid.Tests.Infrastructure 8 | { 9 | public class HistoryMailFixture : IDisposable 10 | { 11 | public HistoryMailFixture() 12 | { 13 | var loggerFactory = new LoggerFactory(new[] { new DebugLoggerProvider() }, new LoggerFilterOptions() { MinLevel = LogLevel.Debug }); 14 | 15 | 16 | var sendGridSettings = new SendGridMailerSettings 17 | { 18 | ApiKey = "abc", 19 | FromDisplayName = "xunit", 20 | FromEmailAddress = "xunit@nowhere.com" 21 | }; 22 | 23 | var logger = loggerFactory.CreateLogger(); 24 | 25 | MailerFactoryForHistoryWithSerializableAttachments.Register(() => new SendGridMailerFake( 26 | new OptionsWrapper(sendGridSettings), 27 | logger, 28 | StoreWithSerializableAttachments)); 29 | 30 | MailerFactoryForHistoryWithoutSerializableAttachments.Register(() => new SendGridMailerFake( 31 | new OptionsWrapper(sendGridSettings), 32 | logger, 33 | StoreWithoutSerializableAttachments)); 34 | } 35 | 36 | public MailerFactory MailerFactoryForHistoryWithSerializableAttachments { get; } = new MailerFactory(); 37 | 38 | public MailerFactory MailerFactoryForHistoryWithoutSerializableAttachments { get; } = new MailerFactory(); 39 | 40 | 41 | public IHistoryStore StoreWithSerializableAttachments { get; set; } = 42 | new InMemoryHistoryStore(new StandardHistoryStoreSettings {StoreAttachmentContents = true}); 43 | 44 | public IHistoryStore StoreWithoutSerializableAttachments { get; set; } = 45 | new InMemoryHistoryStore(new StandardHistoryStoreSettings {StoreAttachmentContents = false}); 46 | 47 | 48 | public void Dispose() 49 | { 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.SendGrid.Tests/Infrastructure/ReusableMailFixture.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using Microsoft.Extensions.Logging; 4 | using NullDesk.Extensions.Mailer.Core; 5 | 6 | namespace NullDesk.Extensions.Mailer.SendGrid.Tests.Infrastructure 7 | { 8 | public class ReusableMailFixture : IDisposable 9 | { 10 | public ReusableMailFixture() 11 | { 12 | //setup the dependency injection service 13 | var services = new ServiceCollection(); 14 | services.AddLogging(config => config.AddDebug().SetMinimumLevel(LogLevel.Debug)); 15 | 16 | services.AddLogging(); 17 | services.AddOptions(); 18 | services.AddSingleton(); 19 | 20 | services.Configure(s => 21 | { 22 | s.ApiKey = "abc"; 23 | s.FromDisplayName = "xunit"; 24 | s.FromEmailAddress = "xunit@nowhere.com"; 25 | } 26 | ); 27 | services.AddSingleton(); 28 | 29 | services.AddSingleton(s => s.GetService()); 30 | 31 | 32 | ServiceProvider = services.BuildServiceProvider(); 33 | 34 | } 35 | 36 | public IServiceProvider ServiceProvider { get; set; } 37 | 38 | 39 | public void Dispose() 40 | { 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.SendGrid.Tests/Infrastructure/SendGridMailerFakes.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using Microsoft.Extensions.Logging; 5 | using Microsoft.Extensions.Options; 6 | using NullDesk.Extensions.Mailer.Core; 7 | using SendGrid; 8 | using SendGrid.Helpers.Mail; 9 | 10 | namespace NullDesk.Extensions.Mailer.SendGrid.Tests.Infrastructure 11 | { 12 | public class SendGridMailerFake : SendGridMailer 13 | { 14 | public SendGridMailerFake(SendGridClient client, IOptions settings, 15 | ILogger logger = null, IHistoryStore historyStore = null) 16 | : base(client, settings.Value, logger, historyStore) 17 | { 18 | } 19 | 20 | public SendGridMailerFake(IOptions settings, ILogger logger = null, 21 | IHistoryStore historyStore = null) : base(settings.Value, logger, historyStore) 22 | { 23 | } 24 | 25 | protected override Task SendToApiAsync(SendGridMessage message, 26 | CancellationToken token = default(CancellationToken)) 27 | { 28 | return Task.FromResult(new Response(HttpStatusCode.Accepted, null, null)); 29 | } 30 | } 31 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.SendGrid.Tests/Infrastructure/StandardMailFixture.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Extensions.DependencyInjection; 3 | using Microsoft.Extensions.Logging; 4 | using NullDesk.Extensions.Mailer.Core; 5 | 6 | namespace NullDesk.Extensions.Mailer.SendGrid.Tests.Infrastructure 7 | { 8 | public class StandardMailFixture : IDisposable 9 | { 10 | public StandardMailFixture() 11 | { 12 | //setup the dependency injection service 13 | var services = new ServiceCollection(); 14 | services.AddLogging(config => config.AddDebug().SetMinimumLevel(LogLevel.Debug)); 15 | 16 | services.AddOptions(); 17 | 18 | services.AddSingleton(); 19 | services.Configure(s => 20 | { 21 | s.ApiKey = "abc"; 22 | s.FromDisplayName = "xunit"; 23 | s.FromEmailAddress = "xunit@nowhere.com"; 24 | s.ReplyToEmailAddress = "xunitreply@nowhere.com"; 25 | s.ReplyToDisplayName = "Xunit - NoReply"; 26 | } 27 | ); 28 | 29 | services.AddTransient(); 30 | 31 | services.AddTransient(s => s.GetService()); 32 | 33 | ServiceProvider = services.BuildServiceProvider(); 34 | 35 | 36 | } 37 | 38 | public IServiceProvider ServiceProvider { get; set; } 39 | 40 | 41 | public void Dispose() 42 | { 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.SendGrid.Tests/NullDesk.Extensions.Mailer.SendGrid.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | net9.0 5 | false 6 | 7 | 8 | 9 | 10 | 11 | PreserveNewest 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | all 23 | runtime; build; native; contentfiles; analyzers; buildtransitive 24 | 25 | 26 | all 27 | runtime; build; native; contentfiles; analyzers; buildtransitive 28 | 29 | 30 | all 31 | runtime; build; native; contentfiles; analyzers; buildtransitive 32 | 33 | 34 | 35 | 36 | all 37 | runtime; build; native; contentfiles; analyzers 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.SendGrid.Tests/xunit.runner.json: -------------------------------------------------------------------------------- 1 | { 2 | "methodDisplay": "method", 3 | "preEnumerateTheories": true 4 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.Tests.Common/NullDesk.Extensions.Mailer.Tests.Common.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Provides common implementations for mailer testing 5 | Stephen M. Redd 6 | netstandard2.0 7 | NullDesk.Extensions.Mailer.Tests.Common 8 | NullDesk.Extensions.Mailer.Tests.Common 9 | false 10 | false 11 | false 12 | false 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.Tests.Common/StandardMailerTestData.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | 4 | namespace NullDesk.Extensions.Mailer.Tests.Common 5 | { 6 | public class StandardMailerTestData : IEnumerable 7 | { 8 | private const string HtmlBody = 9 | "TestMessage

Hello %name%,

This is a test html message from xUnit.

Thanks,

Bot

" 10 | ; 11 | 12 | private const string TextBody = 13 | "Hello %name%,\n\nThis is a test plain text message from xUnit.\n\nThanks,\n\nBot\n\n"; 14 | 15 | private readonly List _data = new List 16 | { 17 | new object[] {HtmlBody, TextBody, new string[] { }}, 18 | new object[] {HtmlBody, TextBody, new[] {@"..\..\..\..\TestData\attachments\testFile.1.txt"}}, 19 | new object[] 20 | { 21 | HtmlBody, TextBody, 22 | new[] 23 | { 24 | @"..\..\..\..\TestData\attachments\testFile.1.txt", 25 | @"..\..\..\..\TestData\attachments\testFile.2.txt" 26 | } 27 | }, 28 | new object[] {null, TextBody, new[] {@"..\..\..\..\TestData\attachments\testFile.1.txt"}}, 29 | new object[] {HtmlBody, null, null} 30 | }; 31 | 32 | public IEnumerator GetEnumerator() 33 | { 34 | return _data.GetEnumerator(); 35 | } 36 | 37 | IEnumerator IEnumerable.GetEnumerator() 38 | { 39 | return GetEnumerator(); 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.Tests.Common/TemplateMailerTestData.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | 4 | namespace NullDesk.Extensions.Mailer.Tests.Common 5 | { 6 | public class TemplateMailerTestData : IEnumerable 7 | { 8 | private readonly List _data = new List 9 | { 10 | new object[] {"template1", new string[] { }}, 11 | new object[] {"template1", new[] {@"..\..\..\..\TestData\attachments\testFile.1.txt"}}, 12 | new object[] 13 | { 14 | "template1", 15 | new[] 16 | { 17 | @"..\..\..\..\TestData\attachments\testFile.1.txt", 18 | @"..\..\..\..\TestData\attachments\testFile.2.txt" 19 | } 20 | }, 21 | new object[] {"template2", new[] {@"..\..\..\..\TestData\attachments\testFile.1.txt"}}, 22 | new object[] {"template2", null} 23 | }; 24 | 25 | public IEnumerator GetEnumerator() 26 | { 27 | return _data.GetEnumerator(); 28 | } 29 | 30 | IEnumerator IEnumerable.GetEnumerator() 31 | { 32 | return GetEnumerator(); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /test/NullDesk.Extensions.Mailer.Tests.Common/TestParallelMailMessage.cs: -------------------------------------------------------------------------------- 1 | namespace NullDesk.Extensions.Mailer.Tests.Common 2 | { 3 | public class TestParallelMailMessage 4 | { 5 | public string From = "toast@toast.com"; 6 | 7 | public string To { get; set; } 8 | public string ToDisplay { get; set; } 9 | public string Subject { get; set; } 10 | public string Html { get; set; } 11 | public string Text { get; set; } 12 | } 13 | } -------------------------------------------------------------------------------- /test/TestData/attachments/testFile.1.txt: -------------------------------------------------------------------------------- 1 | This is a test file -------------------------------------------------------------------------------- /test/TestData/attachments/testFile.2.txt: -------------------------------------------------------------------------------- 1 | This is another test file -------------------------------------------------------------------------------- /test/TestData/templates/template1.htm: -------------------------------------------------------------------------------- 1 | Test Message

Hello %name%,

This is a test html message from xUnit the automated test runner included with the NullDesk Mailer Extensions.

Thanks,

Bot

-------------------------------------------------------------------------------- /test/TestData/templates/template1.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | Hello %name%, 4 | 5 | This is a test message from the NullDesk Mailer Extensions. This 6 | message was sent via SMTP using a file template. 7 | 8 | Thanks, 9 | 10 | Bot 11 | -------------------------------------------------------------------------------- /test/TestData/templates/template2.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | Hello %name%, 4 | 5 | This is a test plain text message from xUnit the automated test runner included with the NullDesk Mailer Extensions. There was no html template for this message, so this should be uuuuuugly. 6 | 7 | Thanks, 8 | 9 | Bot 10 | --------------------------------------------------------------------------------