├── .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 |
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 MessageHello,
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