diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml
index 5275651..c874e74 100644
--- a/.github/workflows/ci-build.yml
+++ b/.github/workflows/ci-build.yml
@@ -34,60 +34,6 @@ jobs:
- name: Restore Packages
run: dotnet restore "${{ env.solution-path }}"
+
- name: Build
- run: dotnet build "${{ env.solution-path }}" --no-restore --configuration Release -p:version=${{ steps.gitversion.outputs.majorMinorPatch }}
-
- code-quality:
- if: github.actor != 'dependabot[bot]'
- runs-on: windows-latest
- name: Analyze Code Quality
- env:
- solution-path: './src/NetCore Utilities Email.sln'
- steps:
- - name: Set up JDK 11
- uses: actions/setup-java@v3
- with:
- java-version: 11
- distribution: zulu
- - uses: actions/checkout@v4
- with:
- fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- - name: Cache SonarCloud packages
- uses: actions/cache@v3.3.2
- with:
- path: ~\sonar\cache
- key: ${{ runner.os }}-sonar
- restore-keys: ${{ runner.os }}-sonar
- - name: Cache SonarCloud scanner
- id: cache-sonar-scanner
- uses: actions/cache@v3.3.2
- with:
- path: .\.sonar\scanner
- key: ${{ runner.os }}-sonar-scanner
- restore-keys: ${{ runner.os }}-sonar-scanner
- - name: Install SonarCloud scanner
- if: steps.cache-sonar-scanner.outputs.cache-hit != 'true'
- shell: powershell
- run: |
- New-Item -Path .\.sonar\scanner -ItemType Directory
- dotnet tool update dotnet-sonarscanner --tool-path .\.sonar\scanner
-
- - name: Install GitVersion
- run: dotnet tool install --global GitVersion.Tool
-
- - name: Determine Version
- id: gitversion
- uses: gittools/actions/gitversion/execute@v0.10.2
- with:
- useConfigFile: true
-
- - name: Build and analyze
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
- SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
- shell: powershell
- run: |
- .\.sonar\scanner\dotnet-sonarscanner begin /k:"IowaComputerGurus_netcore.utilities.email" /o:"iowacomputergurus-github" /d:sonar.login="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io"
- dotnet restore "${{ env.solution-path }}"
- dotnet build "${{ env.solution-path }}" --no-restore --configuration Release -p:version=${{ steps.gitversion.outputs.majorMinorPatch }}
- .\.sonar\scanner\dotnet-sonarscanner end /d:sonar.login="${{ secrets.SONAR_TOKEN }}"
+ run: dotnet build "${{ env.solution-path }}" --no-restore --configuration Release -p:version=${{ steps.gitversion.outputs.majorMinorPatch }}
\ No newline at end of file
diff --git a/.github/workflows/release-build.yml b/.github/workflows/release-build.yml
index f5f0033..8db2b69 100644
--- a/.github/workflows/release-build.yml
+++ b/.github/workflows/release-build.yml
@@ -5,61 +5,7 @@ on:
tags:
- 'v*'
-jobs:
- code-quality:
- runs-on: windows-latest
- name: Analyze Code Quality
- env:
- solution-path: './src/NetCore Utilities Email.sln'
- steps:
- - name: Set up JDK 11
- uses: actions/setup-java@v3
- with:
- java-version: 11
- distribution: zulu
- - uses: actions/checkout@v4
- with:
- fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis
- - name: Cache SonarCloud packages
- uses: actions/cache@v3.3.2
- with:
- path: ~\sonar\cache
- key: ${{ runner.os }}-sonar
- restore-keys: ${{ runner.os }}-sonar
- - name: Cache SonarCloud scanner
- id: cache-sonar-scanner
- uses: actions/cache@v3.3.2
- with:
- path: .\.sonar\scanner
- key: ${{ runner.os }}-sonar-scanner
- restore-keys: ${{ runner.os }}-sonar-scanner
- - name: Install SonarCloud scanner
- if: steps.cache-sonar-scanner.outputs.cache-hit != 'true'
- shell: powershell
- run: |
- New-Item -Path .\.sonar\scanner -ItemType Directory
- dotnet tool update dotnet-sonarscanner --tool-path .\.sonar\scanner
-
- - name: Install GitVersion
- run: dotnet tool install --global GitVersion.Tool
-
- - name: Determine Version
- id: gitversion
- uses: gittools/actions/gitversion/execute@v0.10.2
- with:
- useConfigFile: true
-
- - name: Build and analyze
- env:
- GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # Needed to get PR information, if any
- SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}
- shell: powershell
- run: |
- .\.sonar\scanner\dotnet-sonarscanner begin /k:"IowaComputerGurus_netcore.utilities.email" /o:"iowacomputergurus-github" /d:sonar.login="${{ secrets.SONAR_TOKEN }}" /d:sonar.host.url="https://sonarcloud.io"
- dotnet restore "${{ env.solution-path }}"
- dotnet build "${{ env.solution-path }}" --no-restore --configuration Release -p:version=${{ steps.gitversion.outputs.majorMinorPatch }}
- .\.sonar\scanner\dotnet-sonarscanner end /d:sonar.login="${{ secrets.SONAR_TOKEN }}"
-
+jobs:
build:
runs-on: ubuntu-latest
name: Build & Publish to NuGet
diff --git a/GitVersion.yml b/GitVersion.yml
index a59d151..8b402e5 100644
--- a/GitVersion.yml
+++ b/GitVersion.yml
@@ -1,5 +1,5 @@
mode: ContinuousDeployment
-next-version: 5.1.4
+next-version: 7.0.0
branches:
develop:
regex: develop
diff --git a/README.md b/README.md
index f097463..f6746d4 100644
--- a/README.md
+++ b/README.md
@@ -6,7 +6,9 @@
This is a base library to provide utilities for working with email in .NET 6. This project is used by more concrete implementations such as NetCore.Utilities.Email.Smtp.
-## Usage
+## Breaking Changes (Version 7.0)
+
+Starting with version 7.0, all `IEmailService` methods have been converted to asynchronous operations.
## Installation
Standard installation via NuGet Package Manager
diff --git a/src/NetCore.Utilities.Email/EmailTemplateFactory.cs b/src/NetCore.Utilities.Email/EmailTemplateFactory.cs
index 448f777..f7a819a 100644
--- a/src/NetCore.Utilities.Email/EmailTemplateFactory.cs
+++ b/src/NetCore.Utilities.Email/EmailTemplateFactory.cs
@@ -4,72 +4,86 @@
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Options;
-namespace ICG.NetCore.Utilities.Email
+namespace ICG.NetCore.Utilities.Email;
+
+///
+/// Factory class for creating email content, using templates.
+///
+public interface IEmailTemplateFactory
{
///
- /// Factory class for creating email content, using templates.
+ /// Creates HTML email content utilizing a template
///
- public interface IEmailTemplateFactory
+ /// The desired subject of the email
+ /// The desired content of the email, HTML formatted.
+ ///
+ /// An optional preview textual email content element, replaced in the template for more advanced
+ /// control
+ ///
+ /// The name of the template to use, rather than the initial template.
+ /// The updated content wrapped in the template
+ /// Thrown for missing subject or content
+ /// Thrown if requesting a template that is not defined
+ /// Thrown if the defined template file does not exist
+ string BuildEmailContent(string subject, string content, string preview = "", string templateName = "");
+}
+
+///
+public class EmailTemplateFactory : IEmailTemplateFactory
+{
+ private readonly IHostEnvironment _hostingEnvironment;
+ private readonly IOptions _templateSettings;
+
+ ///
+ /// Default constructor with injected dependencies
+ ///
+ ///
+ ///
+ public EmailTemplateFactory(IOptions templateSettings, IHostEnvironment hostingEnvironment)
{
- ///
- /// Creates HTML email content utilizing a template
- ///
- /// The desired subject of the email
- /// The desired content of the email, HTML formatted.
- ///
- /// An optional preview textual email content element, replaced in the template for more advanced
- /// control
- ///
- /// The name of the template to use, rather than the initial template.
- /// The updated content wrapped in the template
- /// Thrown for missing subject or content
- /// Thrown if requesting a template that is not defined
- /// Thrown if the defined template file does not exist
- string BuildEmailContent(string subject, string content, string preview = "", string templateName = "");
+ _templateSettings = templateSettings;
+ _hostingEnvironment = hostingEnvironment;
}
-
- public class EmailTemplateFactory : IEmailTemplateFactory
+ ///
+ public string BuildEmailContent(string subject, string content, string preview = "", string templateName = "")
{
- private readonly IHostEnvironment _hostingEnvironment;
- private readonly IOptions _templateSettings;
+ //Validate inputs
+ if (string.IsNullOrEmpty(subject))
+ {
+ throw new ArgumentNullException(nameof(subject));
+ }
- public EmailTemplateFactory(IOptions templateSettings,
- IHostEnvironment hostingEnvironment)
+ if (string.IsNullOrEmpty(content))
{
- _templateSettings = templateSettings;
- _hostingEnvironment = hostingEnvironment;
+ throw new ArgumentNullException(nameof(content));
}
- public string BuildEmailContent(string subject, string content, string preview = "", string templateName = "")
+ if (!string.IsNullOrEmpty(templateName) &&
+ !_templateSettings.Value.AdditionalTemplates.ContainsKey(templateName))
{
- //Validate inputs
- if (string.IsNullOrEmpty(subject))
- throw new ArgumentNullException(nameof(subject));
- if (string.IsNullOrEmpty(content))
- throw new ArgumentNullException(nameof(content));
- if (!string.IsNullOrEmpty(templateName) &&
- !_templateSettings.Value.AdditionalTemplates.ContainsKey(templateName))
- throw new ArgumentException($"Requested template {templateName} was not found in configuration",
- nameof(templateName));
+ throw new ArgumentException($"Requested template {templateName} was not found in configuration",
+ nameof(templateName));
+ }
- //Get the template
- var templatePath = string.IsNullOrEmpty(templateName)
- ? _templateSettings.Value.DefaultTemplatePath
- : _templateSettings.Value.AdditionalTemplates[templateName];
- var fullTemplatePath = Path.Combine(_hostingEnvironment.ContentRootPath, templatePath);
- if (!File.Exists(fullTemplatePath))
- throw new FileNotFoundException("Unable to find template file", fullTemplatePath);
+ //Get the template
+ var templatePath = string.IsNullOrEmpty(templateName)
+ ? _templateSettings.Value.DefaultTemplatePath
+ : _templateSettings.Value.AdditionalTemplates[templateName];
+ var fullTemplatePath = Path.Combine(_hostingEnvironment.ContentRootPath, templatePath);
+ if (!File.Exists(fullTemplatePath))
+ {
+ throw new FileNotFoundException("Unable to find template file", fullTemplatePath);
+ }
- //Replace the content
- var templateBuilder =
- new StringBuilder(File.ReadAllText(Path.Combine(_hostingEnvironment.ContentRootPath, templatePath)));
- templateBuilder.Replace("[SUBJECT]", subject);
- templateBuilder.Replace("[PREVIEW]", preview);
- templateBuilder.Replace("[CONTENT]", content);
+ //Replace the content
+ var templateBuilder =
+ new StringBuilder(File.ReadAllText(fullTemplatePath));
+ templateBuilder.Replace("[SUBJECT]", subject);
+ templateBuilder.Replace("[PREVIEW]", preview);
+ templateBuilder.Replace("[CONTENT]", content);
- //Return message content
- return templateBuilder.ToString();
- }
+ //Return message content
+ return templateBuilder.ToString();
}
}
\ No newline at end of file
diff --git a/src/NetCore.Utilities.Email/EmailTemplateSettings.cs b/src/NetCore.Utilities.Email/EmailTemplateSettings.cs
index a1f7a44..a5639d1 100644
--- a/src/NetCore.Utilities.Email/EmailTemplateSettings.cs
+++ b/src/NetCore.Utilities.Email/EmailTemplateSettings.cs
@@ -1,10 +1,19 @@
using System.Collections.Generic;
-namespace ICG.NetCore.Utilities.Email
+namespace ICG.NetCore.Utilities.Email;
+
+///
+/// Setting object for email templates
+///
+public class EmailTemplateSettings
{
- public class EmailTemplateSettings
- {
- public string DefaultTemplatePath { get; set; }
- public Dictionary AdditionalTemplates { get; set; }
- }
+ ///
+ /// The application relative file path to the default template file
+ ///
+ public string DefaultTemplatePath { get; set; }
+
+ ///
+ /// A collection of additional templates with a "name" and "path" for each one
+ ///
+ public Dictionary AdditionalTemplates { get; set; }
}
\ No newline at end of file
diff --git a/src/NetCore.Utilities.Email/IEmailService.cs b/src/NetCore.Utilities.Email/IEmailService.cs
index 5044dec..c953fe8 100644
--- a/src/NetCore.Utilities.Email/IEmailService.cs
+++ b/src/NetCore.Utilities.Email/IEmailService.cs
@@ -1,160 +1,169 @@
using System.Collections.Generic;
+using System.Threading.Tasks;
-namespace ICG.NetCore.Utilities.Email
+namespace ICG.NetCore.Utilities.Email;
+
+///
+/// Represents a service that can deliver email messages to the recipients. This is utilized by all downstream
+/// implementations of ICG.NetCore.Utilities.Email applications allowing easy switching between providers & options.
+///
+public interface IEmailService
{
///
- /// Represents a service that can deliver email messages to the recipients. This is utilized by all downstream
- /// implementations of ICG.NetCore.Utilities.Email applications allowing easy switching between providers & options.
+ /// Returns the configured administrator email for the service
+ ///
+ string AdminEmail { get; }
+
+ ///
+ /// Returns the configured administrator name for outbound emails
+ ///
+ string AdminName { get; }
+
+ ///
+ /// Shortcut for sending an email to the administrator, only requiring the subject and body.
+ ///
+ /// The message subject
+ /// The message body
+ Task SendMessageToAdministratorAsync(string subject, string bodyHtml);
+
+ ///
+ /// Sends a message to the administrator as well as the additional contacts provided.
+ ///
+ /// Additional email addresses to add to the CC line
+ /// The email subject
+ /// The HTML content of the email
+ Task SendMessageToAdministratorAsync(IEnumerable ccAddressList, string subject, string bodyHtml);
+
+ ///
+ /// Sends a message to the specified recipient, with the supplied subject and body
+ ///
+ /// Who is receiving the email
+ /// The message subject
+ /// The message body
+ Task SendMessageAsync(string toAddress, string subject, string bodyHtml);
+
+ ///
+ /// Sends a message to the specified recipient, with the supplied subject and body
+ ///
+ /// Who is receiving the email
+ /// The message subject
+ /// The message body
+ /// A list of tokens that should be replaced within the email message
+ Task SendMessageAsync(string toAddress, string subject, string bodyHtml,
+ List> tokens);
+
+ ///
+ /// Sends a message to the specified recipient, with the supplied subject and body
+ ///
+ /// Who is receiving the email
+ /// Additional CC'ed emails
+ /// The message subject
+ /// The message body
+ Task SendMessageAsync(string toAddress, IEnumerable ccAddressList, string subject, string bodyHtml);
+
+ ///
+ /// Sends a message to the specified recipient, with the supplied subject and body
+ ///
+ /// Who is receiving the email
+ /// Additional CC'ed emails
+ /// The message subject
+ /// The message body
+ /// A list of tokens that should be replaced within the email message
+ Task SendMessageAsync(string toAddress, IEnumerable ccAddressList, string subject, string bodyHtml,
+ List> tokens);
+
+ ///
+ /// Sends a message to the specified recipient, and CC's with the supplied subject and body
+ ///
+ /// Who is receiving the email
+ /// Additional CC'ed emails
+ /// The message subject
+ /// The message body
+ /// A list of tokens that should be replaced within the email message
+ /// The optional custom template to override with
+ /// The a custom key for identifying a sender
+ Task SendMessageAsync(string toAddress, IEnumerable ccAddressList, string subject, string bodyHtml,
+ List> tokens,
+ string templateName, string senderKeyName = "");
+
+ ///
+ /// Sends a message to the specified recipient, with the supplied subject and body
+ ///
+ /// The address to be used as a reply to
+ /// The address to be used as a reply to
+ /// Who is receiving the email
+ /// The message subject
+ /// The message body
+ Task SendWithReplyToAsync(string replyToAddress, string replyToName, string toAddress, string subject,
+ string bodyHtml);
+
+ ///
+ /// Sends a message to the specified recipient, with the supplied subject and body
+ ///
+ /// The address to be used as a reply to
+ /// The address to be used as a reply to
+ /// Who is receiving the email
+ /// The message subject
+ /// The message body
+ /// A list of tokens that should be replaced within the email message
+ Task SendWithReplyToAsync(string replyToAddress, string replyToName, string toAddress, string subject,
+ string bodyHtml, List> tokens);
+
+ ///
+ /// Sends a message to the specified recipient, with the supplied subject and body
+ ///
+ /// The address to be used as a reply to
+ /// The address to be used as a reply to
+ /// Who is receiving the email
+ /// Additional CC'ed emails
+ /// The message subject
+ /// The message body
+ Task SendWithReplyToAsync(string replyToAddress, string replyToName, string toAddress,
+ IEnumerable ccAddressList, string subject, string bodyHtml);
+
+ ///
+ /// Sends a message to the specified recipient, with the supplied subject and body
+ ///
+ /// The address to be used as a reply to
+ /// The address to be used as a reply to
+ /// Who is receiving the email
+ /// Additional CC'ed emails
+ /// The message subject
+ /// The message body
+ /// A list of tokens that should be replaced within the email message
+ Task SendWithReplyToAsync(string replyToAddress, string replyToName, string toAddress,
+ IEnumerable ccAddressList, string subject, string bodyHtml, List> tokens);
+
+ ///
+ /// Sends a message to the specified recipient, and CC's with the supplied subject and body
+ ///
+ /// The address to be used as a reply to
+ /// The address to be used as a reply to
+ /// Who is receiving the email
+ /// Additional CC'ed emails
+ /// The message subject
+ /// The message body
+ /// A list of tokens that should be replaced within the email message
+ /// The optional custom template to override with
+ /// The a custom key for identifying a sender
+ Task SendWithReplyToAsync(string replyToAddress, string replyToName, string toAddress,
+ IEnumerable ccAddressList, string subject, string bodyHtml, List> tokens,
+ string templateName, string senderKeyName = "");
+
+ ///
+ /// Creates a message with an attachment
///
- public interface IEmailService
- {
- ///
- /// Returns the configured administrator email for the service
- ///
- string AdminEmail { get; }
-
- ///
- /// Returns the configured administrator name for outbound emails
- ///
- string AdminName { get; }
-
- ///
- /// Shortcut for sending an email to the administrator, only requiring the subject and body.
- ///
- /// The message subject
- /// The message body
- bool SendMessageToAdministrator(string subject, string bodyHtml);
-
- ///
- /// Sends a message to the administrator as well as the additional contacts provided.
- ///
- /// Additional email addresses to add to the CC line
- /// The email subject
- /// The HTML content of the email
- bool SendMessageToAdministrator(IEnumerable ccAddressList, string subject, string bodyHtml);
-
- ///
- /// Sends a message to the specified recipient, with the supplied subject and body
- ///
- /// Who is receiving the email
- /// The message subject
- /// The message body
- bool SendMessage(string toAddress, string subject, string bodyHtml);
-
- ///
- /// Sends a message to the specified recipient, with the supplied subject and body
- ///
- /// Who is receiving the email
- /// The message subject
- /// The message body
- /// A list of tokens that should be replaced within the email message
- bool SendMessage(string toAddress, string subject, string bodyHtml, List> tokens);
-
- ///
- /// Sends a message to the specified recipient, with the supplied subject and body
- ///
- /// Who is receiving the email
- /// Additional CC'ed emails
- /// The message subject
- /// The message body
- bool SendMessage(string toAddress, IEnumerable ccAddressList, string subject, string bodyHtml);
-
- ///
- /// Sends a message to the specified recipient, with the supplied subject and body
- ///
- /// Who is receiving the email
- /// Additional CC'ed emails
- /// The message subject
- /// The message body
- /// A list of tokens that should be replaced within the email message
- bool SendMessage(string toAddress, IEnumerable ccAddressList, string subject, string bodyHtml, List> tokens);
-
- ///
- /// Sends a message to the specified recipient, and CC's with the supplied subject and body
- ///
- /// Who is receiving the email
- /// Additional CC'ed emails
- /// The message subject
- /// The message body
- /// A list of tokens that should be replaced within the email message
- /// The optional custom template to override with
- /// The a custom key for identifying a sender
- bool SendMessage(string toAddress, IEnumerable ccAddressList, string subject, string bodyHtml, List> tokens,
- string templateName, string senderKeyName = "");
-
- ///
- /// Sends a message to the specified recipient, with the supplied subject and body
- ///
- /// The address to be used as a reply to
- /// The address to be used as a reply to
- /// Who is receiving the email
- /// The message subject
- /// The message body
- bool SendWithReplyTo(string replyToAddress, string replyToName, string toAddress, string subject, string bodyHtml);
-
- ///
- /// Sends a message to the specified recipient, with the supplied subject and body
- ///
- /// The address to be used as a reply to
- /// The address to be used as a reply to
- /// Who is receiving the email
- /// The message subject
- /// The message body
- /// A list of tokens that should be replaced within the email message
- bool SendWithReplyTo(string replyToAddress, string replyToName, string toAddress, string subject, string bodyHtml, List> tokens);
-
- ///
- /// Sends a message to the specified recipient, with the supplied subject and body
- ///
- /// The address to be used as a reply to
- /// The address to be used as a reply to
- /// Who is receiving the email
- /// Additional CC'ed emails
- /// The message subject
- /// The message body
- bool SendWithReplyTo(string replyToAddress, string replyToName, string toAddress, IEnumerable ccAddressList, string subject, string bodyHtml);
-
- ///
- /// Sends a message to the specified recipient, with the supplied subject and body
- ///
- /// The address to be used as a reply to
- /// The address to be used as a reply to
- /// Who is receiving the email
- /// Additional CC'ed emails
- /// The message subject
- /// The message body
- /// A list of tokens that should be replaced within the email message
- bool SendWithReplyTo(string replyToAddress, string replyToName, string toAddress, IEnumerable ccAddressList, string subject, string bodyHtml, List> tokens);
-
- ///
- /// Sends a message to the specified recipient, and CC's with the supplied subject and body
- ///
- /// The address to be used as a reply to
- /// The address to be used as a reply to
- /// Who is receiving the email
- /// Additional CC'ed emails
- /// The message subject
- /// The message body
- /// A list of tokens that should be replaced within the email message
- /// The optional custom template to override with
- /// The a custom key for identifying a sender
- bool SendWithReplyTo(string replyToAddress, string replyToName, string toAddress, IEnumerable ccAddressList, string subject, string bodyHtml, List> tokens,
- string templateName, string senderKeyName = "");
-
- ///
- /// Creates a message with an attachment
- ///
- /// The to address for the message
- /// The address(ses) to add a CC's
- /// The subject of the message
- /// Attachment Content
- /// Attachment file name
- /// The HTML body contents
- /// A list of tokens that should be replaced within the email message
- /// The optional custom template to override with
- /// The a custom key for identifying a sender
- ///
- bool SendMessageWithAttachment(string toAddress, IEnumerable ccAddressList, string subject,
- byte[] fileContent, string fileName, string bodyHtml, List> tokens, string templateName = "", string senderKeyName = "");
- }
+ /// The to address for the message
+ /// The address(ses) to add a CC's
+ /// The subject of the message
+ /// Attachment Content
+ /// Attachment file name
+ /// The HTML body contents
+ /// A list of tokens that should be replaced within the email message
+ /// The optional custom template to override with
+ /// The a custom key for identifying a sender
+ ///
+ Task SendMessageWithAttachmentAsync(string toAddress, IEnumerable ccAddressList, string subject,
+ byte[] fileContent, string fileName, string bodyHtml, List> tokens,
+ string templateName = "", string senderKeyName = "");
}
\ No newline at end of file