From ab6e020e7dd68aabc96335aed00d620d19cce0f2 Mon Sep 17 00:00:00 2001 From: Mitchel Sellers Date: Wed, 20 Mar 2024 23:10:13 -0500 Subject: [PATCH] Adjusted project to use Async Properly Fixes #28 --- .github/workflows/ci-build.yml | 67 +--- .github/workflows/release-build.yml | 1 + README.md | 8 +- ...Core.Utilities.Email.SendGrid.Tests.csproj | 10 +- .../SmtpServiceTests.cs | 44 +-- .../NetCore.Utilities.Email.SendGrid.csproj | 4 +- .../SendGridSender.cs | 41 ++- .../SendGridService.cs | 311 +++++++++--------- 8 files changed, 222 insertions(+), 264 deletions(-) diff --git a/.github/workflows/ci-build.yml b/.github/workflows/ci-build.yml index c2c6ea0..deac3d5 100644 --- a/.github/workflows/ci-build.yml +++ b/.github/workflows/ci-build.yml @@ -37,61 +37,14 @@ jobs: - name: Build run: dotnet build "${{ env.solution-path }}" --no-restore --configuration Release -p:version=${{ steps.gitversion.outputs.majorMinorPatch }} - name: Test - run: dotnet test "${{ env.solution-path }}" --no-build --configuration Release - - - code-quality: - if: github.actor != 'dependabot[bot]' - runs-on: windows-latest - name: Analyze Code Quality - env: - solution-path: './src/NetCore.Utilities.Email.SendGrid.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 + run: dotnet test "${{ env.solution-path }}" --no-build --configuration Release --collect "XPlat Code Coverage" -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=opencover --logger "trx;LogFileName=unittests.trx" - - 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.sendgrid" /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 }} - dotnet test "${{ env.solution-path }}" --no-build --configuration Release --collect "XPlat Code Coverage" -- DataCollectionRunSettings.DataCollectors.DataCollector.Configuration.Format=opencover --logger "trx;LogFileName=unittests.trx" - .\.sonar\scanner\dotnet-sonarscanner end /d:sonar.login="${{ secrets.SONAR_TOKEN }}" + - name: Push Coverage to Codacy + shell: bash + env: + CODACY_ORGANIZATION_PROVIDER: ${{ secrets.CODACY_ORGANIZATION_PROVIDER }} + CODACY_USERNAME: ${{ secrets.CODACY_USERNAME }} + CODACY_PROJECT_NAME: ${{ secrets.CODACY_PROJECT_NAME }} + CODACY_API_TOKEN: ${{ secrets.CODACY_API_TOKEN }} + run: | + bash <(curl -Ls https://coverage.codacy.com/get.sh) report $(find . -name '*.opencover.xml' -printf '-r %p ') \ No newline at end of file diff --git a/.github/workflows/release-build.yml b/.github/workflows/release-build.yml index 4d864f2..cd1f1b0 100644 --- a/.github/workflows/release-build.yml +++ b/.github/workflows/release-build.yml @@ -33,6 +33,7 @@ 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 }} diff --git a/README.md b/README.md index eb57343..a105a35 100644 --- a/README.md +++ b/README.md @@ -8,13 +8,9 @@ This library provides an easy to use implementation of SendGrid based email deli This package depends on the ICG.NetCore.Utilities.Email project for template implementation -## SonarCloud Analysis - -[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=IowaComputerGurus_netcore.utilities.email.sendgrid&metric=alert_status)](https://sonarcloud.io/dashboard?id=IowaComputerGurus_netcore.utilities.email.sendgrid) -[![Coverage](https://sonarcloud.io/api/project_badges/measure?project=IowaComputerGurus_netcore.utilities.email.sendgrid&metric=coverage)](https://sonarcloud.io/dashboard?id=IowaComputerGurus_netcore.utilities.email.sendgrid) -[![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=IowaComputerGurus_netcore.utilities.email.sendgrid&metric=security_rating)](https://sonarcloud.io/dashboard?id=IowaComputerGurus_netcore.utilities.email.sendgrid) -[![Technical Debt](https://sonarcloud.io/api/project_badges/measure?project=IowaComputerGurus_netcore.utilities.email.sendgrid&metric=sqale_index)](https://sonarcloud.io/dashboard?id=IowaComputerGurus_netcore.utilities.email.sendgrid) +## Breaking Changes +Version 7.0 has a breaking change transitioning to Async for all methods! ## Dependencies The following additional NuGet packages are installed with this extension. diff --git a/src/NetCore.Utilities.Email.SendGrid.Tests/NetCore.Utilities.Email.SendGrid.Tests.csproj b/src/NetCore.Utilities.Email.SendGrid.Tests/NetCore.Utilities.Email.SendGrid.Tests.csproj index dff563d..f6dda77 100644 --- a/src/NetCore.Utilities.Email.SendGrid.Tests/NetCore.Utilities.Email.SendGrid.Tests.csproj +++ b/src/NetCore.Utilities.Email.SendGrid.Tests/NetCore.Utilities.Email.SendGrid.Tests.csproj @@ -7,17 +7,17 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive - - - - + + + + all runtime; build; native; contentfiles; analyzers diff --git a/src/NetCore.Utilities.Email.SendGrid.Tests/SmtpServiceTests.cs b/src/NetCore.Utilities.Email.SendGrid.Tests/SmtpServiceTests.cs index ef84f79..c048638 100644 --- a/src/NetCore.Utilities.Email.SendGrid.Tests/SmtpServiceTests.cs +++ b/src/NetCore.Utilities.Email.SendGrid.Tests/SmtpServiceTests.cs @@ -84,20 +84,20 @@ public void AdminName_ShouldReturnNullWhenNoConfiguration() } [Fact] - public void SendToAdministrator_ShouldSend_DefaultingFromAndToAddress() + public void SendToAdministratorAsync_ShouldSend_DefaultingFromAndToAddress() { //Arrange var subject = "Test"; var message = "Message"; //Act - _service.SendMessageToAdministrator(subject, message); + _service.SendMessageToAdministratorAsync(subject, message); //Verify } [Fact] - public void SendToAdministrator_ShouldSend_DefaultingFromAndToAddress_WithCCRecipients() + public void SendToAdministratorAsync_ShouldSend_DefaultingFromAndToAddress_WithCCRecipients() { //Arrange var subject = "Test"; @@ -105,13 +105,13 @@ public void SendToAdministrator_ShouldSend_DefaultingFromAndToAddress_WithCCReci var cc = new List {"recipient@test.com"}; //Act - _service.SendMessageToAdministrator(cc, subject, message); + _service.SendMessageToAdministratorAsync(cc, subject, message); //Verify } [Fact] - public void SendMessage_WithoutCCRecipients_ShouldSend_DefaultingFromAddress() + public void SendMessageAsync_WithoutCCRecipients_ShouldSend_DefaultingFromAddress() { //Arrange var to = "tester@test.com"; @@ -119,13 +119,13 @@ public void SendMessage_WithoutCCRecipients_ShouldSend_DefaultingFromAddress() var message = "message"; //Act - _service.SendMessage(to, subject, message); + _service.SendMessageAsync(to, subject, message); //Verify } [Fact] - public void SendMessage_WithCCRecipients_ShouldSend_DefaultingFromAddress() + public void SendMessageAsync_WithCCRecipients_ShouldSend_DefaultingFromAddress() { //Arrange var to = "tester@test.com"; @@ -134,13 +134,13 @@ public void SendMessage_WithCCRecipients_ShouldSend_DefaultingFromAddress() var message = "message"; //Act - _service.SendMessage(to, cc, subject, message); + _service.SendMessageAsync(to, cc, subject, message); //Verify } [Fact] - public void SendMessageWithAttachment_ShouldSend_DefaultingFromAddress() + public void SendMessageWithAttachmentAsync_ShouldSend_DefaultingFromAddress() { //Arrange var to = "tester@test.com"; @@ -151,13 +151,13 @@ public void SendMessageWithAttachment_ShouldSend_DefaultingFromAddress() var message = "message"; //Act - _service.SendMessageWithAttachment(to, cc, subject, fileContent, fileName, message, null); + _service.SendMessageWithAttachmentAsync(to, cc, subject, fileContent, fileName, message, null); //Assets } [Fact] - public void SendMessage_ShouldPassOptionalTemplateName_ToMessageMethods() + public void SendMessageAsync_ShouldPassOptionalTemplateName_ToMessageMethods() { //Arrange var to = "tester@test.com"; @@ -167,13 +167,13 @@ public void SendMessage_ShouldPassOptionalTemplateName_ToMessageMethods() var requestedTemplate = "Test"; //Act - _service.SendMessage(to, cc, subject, message, null, requestedTemplate); + _service.SendMessageAsync(to, cc, subject, message, null, requestedTemplate); //Assets } [Fact] - public void SendMessageWithAttachment_ShouldPassOptionalTemplateName_ToMessageMethods() + public void SendMessageWithAttachmentAsync_ShouldPassOptionalTemplateName_ToMessageMethods() { //Arrange var to = "tester@test.com"; @@ -185,13 +185,13 @@ public void SendMessageWithAttachment_ShouldPassOptionalTemplateName_ToMessageMe var requestedTemplate = "Test"; //Act - _service.SendMessageWithAttachment(to, cc, subject, fileContent, fileName, message, null, requestedTemplate); + _service.SendMessageWithAttachmentAsync(to, cc, subject, fileContent, fileName, message, null, requestedTemplate); //Assets } [Fact] - public void SendWithReplyTo_ShouldThrowArgumentException_WhenReplyToMissing() + public async void SendWithReplyToAsync_ShouldThrowArgumentException_WhenReplyToMissing() { //Arrange var to = "tester@test.com"; @@ -199,11 +199,11 @@ public void SendWithReplyTo_ShouldThrowArgumentException_WhenReplyToMissing() var message = "message"; //Act/Assert - Assert.Throws(() => _service.SendWithReplyTo("", "", to, subject, message)); + var result = await Assert.ThrowsAsync(() => _service.SendWithReplyToAsync("", "", to, subject, message)); } [Fact] - public void SendWithReplyTo_WithoutCCRecipients_ShouldSend_DefaultingFromAddress() + public void SendWithReplyToAsync_WithoutCCRecipients_ShouldSend_DefaultingFromAddress() { //Arrange var replyTo = "sender@sendy.com"; @@ -216,13 +216,13 @@ public void SendWithReplyTo_WithoutCCRecipients_ShouldSend_DefaultingFromAddress "")).Returns(returnMessage).Verifiable(); //Act - _service.SendWithReplyTo(replyTo, "", to, subject, message); + _service.SendWithReplyToAsync(replyTo, "", to, subject, message); //Verify } [Fact] - public void SendWithReplyTo_WithCCRecipients_ShouldSend_DefaultingFromAddress() + public void SendWithReplyToAsync_WithCCRecipients_ShouldSend_DefaultingFromAddress() { //Arrange var replyTo = "sender@sendy.com"; @@ -235,14 +235,14 @@ public void SendWithReplyTo_WithCCRecipients_ShouldSend_DefaultingFromAddress() .Setup(s => s.CreateMessage(_options.AdminEmail, _options.AdminName, to, cc, subject, message, "")).Returns(returnMessage).Verifiable(); //Act - _service.SendWithReplyTo(replyTo, "", to, cc, subject, message); + _service.SendWithReplyToAsync(replyTo, "", to, cc, subject, message); //Verify _sendGridMessageBuilderMock.Verify(); } [Fact] - public void SendWithReplyTo_ShouldPassOptionalTemplateName_ToMessageMethods() + public void SendWithReplyToAsync_ShouldPassOptionalTemplateName_ToMessageMethods() { //Arrange var replyTo = "sender@sendy.com"; @@ -257,7 +257,7 @@ public void SendWithReplyTo_ShouldPassOptionalTemplateName_ToMessageMethods() requestedTemplate)).Returns(returnMessage).Verifiable(); //Act - _service.SendWithReplyTo(replyTo, "", to, cc, subject, message, null, requestedTemplate); + _service.SendWithReplyToAsync(replyTo, "", to, cc, subject, message, null, requestedTemplate); //Assets _sendGridMessageBuilderMock.Verify(); diff --git a/src/NetCore.Utilities.Email.SendGrid/NetCore.Utilities.Email.SendGrid.csproj b/src/NetCore.Utilities.Email.SendGrid/NetCore.Utilities.Email.SendGrid.csproj index 549d30e..826e4e9 100644 --- a/src/NetCore.Utilities.Email.SendGrid/NetCore.Utilities.Email.SendGrid.csproj +++ b/src/NetCore.Utilities.Email.SendGrid/NetCore.Utilities.Email.SendGrid.csproj @@ -34,7 +34,7 @@ - + @@ -44,7 +44,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/src/NetCore.Utilities.Email.SendGrid/SendGridSender.cs b/src/NetCore.Utilities.Email.SendGrid/SendGridSender.cs index 2baf8eb..4bcdb1a 100644 --- a/src/NetCore.Utilities.Email.SendGrid/SendGridSender.cs +++ b/src/NetCore.Utilities.Email.SendGrid/SendGridSender.cs @@ -2,32 +2,31 @@ using SendGrid; using SendGrid.Helpers.Mail; -namespace ICG.NetCore.Utilities.Email.SendGrid +namespace ICG.NetCore.Utilities.Email.SendGrid; + +/// +/// Internal service to abstract the actual SendGrid implementation to allow for proper unit testing of the remainder +/// of the project. Not intended for external usage +/// +public interface ISendGridSender { /// - /// Internal service to abstract the actual SendGrid implementation to allow for proper unit testing of the remainder - /// of the project. Not intended for external usage + /// Sends a mail message using the provided API key /// - public interface ISendGridSender - { - /// - /// Sends a mail message using the provided API key - /// - /// - /// - /// - Task SendMessage(string apiKey, SendGridMessage message); - } + /// + /// + /// + Task SendMessage(string apiKey, SendGridMessage message); +} +/// +public class SendGridSender : ISendGridSender +{ /// - public class SendGridSender : ISendGridSender + public async Task SendMessage(string apiKey, SendGridMessage message) { - /// - public async Task SendMessage(string apiKey, SendGridMessage message) - { - var client = new SendGridClient(apiKey); - var result = await client.SendEmailAsync(message); - return result.IsSuccessStatusCode; - } + var client = new SendGridClient(apiKey); + var result = await client.SendEmailAsync(message); + return result.IsSuccessStatusCode; } } \ No newline at end of file diff --git a/src/NetCore.Utilities.Email.SendGrid/SendGridService.cs b/src/NetCore.Utilities.Email.SendGrid/SendGridService.cs index 27da7ba..fecdf93 100644 --- a/src/NetCore.Utilities.Email.SendGrid/SendGridService.cs +++ b/src/NetCore.Utilities.Email.SendGrid/SendGridService.cs @@ -1,179 +1,188 @@ using System; using System.Collections.Generic; +using System.Threading.Tasks; using Microsoft.Extensions.Options; using SendGrid.Helpers.Mail; -namespace ICG.NetCore.Utilities.Email.SendGrid +namespace ICG.NetCore.Utilities.Email.SendGrid; + +/// +public class SendGridService : IEmailService { + private readonly ISendGridMessageBuilder _messageBuilder; + private readonly ISendGridSender _sender; + private readonly SendGridServiceOptions _serviceOptions; + + /// + /// DI Capable Constructor for SendGrid message delivery using MimeKit/MailKit + /// + /// + /// + /// + public SendGridService(IOptions serviceOptions, ISendGridMessageBuilder messageBuilder, + ISendGridSender sender) + { + _messageBuilder = messageBuilder; + _sender = sender; + _serviceOptions = serviceOptions.Value; + } + + /// + public string AdminEmail => _serviceOptions?.AdminEmail; + + /// + public string AdminName => _serviceOptions?.AdminName; + /// - public class SendGridService : IEmailService + public Task SendMessageToAdministratorAsync(string subject, string bodyHtml) { - private readonly SendGridServiceOptions _serviceOptions; - private readonly ISendGridMessageBuilder _messageBuilder; - private readonly ISendGridSender _sender; - - /// - public string AdminEmail => _serviceOptions?.AdminEmail; - - /// - public string AdminName => _serviceOptions?.AdminName; - - /// - /// DI Capable Constructor for SendGrid message delivery using MimeKit/MailKit - /// - /// - /// - /// - public SendGridService(IOptions serviceOptions, ISendGridMessageBuilder messageBuilder, ISendGridSender sender) - { - _messageBuilder = messageBuilder; - _sender = sender; - _serviceOptions = serviceOptions.Value; - } + //Force to address + return SendMessageAsync(_serviceOptions.AdminEmail, null, subject, bodyHtml); + } - /// - public bool SendMessageToAdministrator(string subject, string bodyHtml) - { - //Force to address - return SendMessage(_serviceOptions.AdminEmail, null, subject, bodyHtml); - } + /// + public Task SendMessageToAdministratorAsync(IEnumerable ccAddressList, string subject, + string bodyHtml) + { + return SendMessageAsync(_serviceOptions.AdminEmail, ccAddressList, subject, bodyHtml); + } - /// - public bool SendMessageToAdministrator(IEnumerable ccAddressList, string subject, string bodyHtml) - { - return SendMessage(_serviceOptions.AdminEmail, ccAddressList, subject, bodyHtml); - } + /// + public Task SendMessageAsync(string toAddress, string subject, string bodyHtml) + { + //Call full overload + return SendMessageAsync(toAddress, null, subject, bodyHtml); + } - /// - public bool SendMessage(string toAddress, string subject, string bodyHtml) - { - //Call full overload - return SendMessage(toAddress, null, subject, bodyHtml); - } + /// + public Task SendMessageAsync(string toAddress, string subject, string bodyHtml, + List> tokens) + { + return SendMessageAsync(toAddress, null, subject, bodyHtml, null, ""); + } - /// - public bool SendMessage(string toAddress, string subject, string bodyHtml, List> tokens) - { - return SendMessage(toAddress, null, subject, bodyHtml, null, ""); - } + /// + public Task SendMessageAsync(string toAddress, IEnumerable ccAddressList, string subject, + string bodyHtml) + { + return SendMessageAsync(toAddress, ccAddressList, subject, bodyHtml, null, ""); + } - /// - public bool SendMessage(string toAddress, IEnumerable ccAddressList, string subject, string bodyHtml) - { - return SendMessage(toAddress, ccAddressList, subject, bodyHtml, null, ""); - } + /// + public Task SendMessageAsync(string toAddress, IEnumerable ccAddressList, string subject, + string bodyHtml, List> tokens) + { + return SendMessageAsync(toAddress, ccAddressList, subject, bodyHtml, tokens, ""); + } - /// - public bool SendMessage(string toAddress, IEnumerable ccAddressList, string subject, string bodyHtml, List> tokens) - { - return SendMessage(toAddress, ccAddressList, subject, bodyHtml, tokens, ""); - } - - /// - public bool SendMessage(string toAddress, IEnumerable ccAddressList, string subject, string bodyHtml, - List> tokens, - string templateName, string senderKeyName = "") - { - if (tokens != null) - { - foreach (var item in tokens) - { - bodyHtml = bodyHtml.Replace(item.Key, item.Value); - } - } - - //Get the message to send - var toSend = _messageBuilder.CreateMessage(_serviceOptions.AdminEmail, _serviceOptions.AdminName, toAddress, ccAddressList, subject, - bodyHtml, templateName); - - //Determine the key to use - var apiKey = _serviceOptions.SendGridApiKey; - if (!string.IsNullOrEmpty(senderKeyName)) - apiKey = _serviceOptions.AdditionalApiKeys[senderKeyName]; - - //Send - return _sender.SendMessage(apiKey, toSend).GetAwaiter().GetResult(); - } + /// + public Task SendMessageAsync(string toAddress, IEnumerable ccAddressList, string subject, + string bodyHtml, + List> tokens, + string templateName, string senderKeyName = "") + { + if (tokens != null) + foreach (var item in tokens) + bodyHtml = bodyHtml.Replace(item.Key, item.Value); + + //Get the message to send + var toSend = _messageBuilder.CreateMessage(_serviceOptions.AdminEmail, _serviceOptions.AdminName, toAddress, + ccAddressList, subject, + bodyHtml, templateName); + + //Determine the key to use + var apiKey = _serviceOptions.SendGridApiKey; + if (!string.IsNullOrEmpty(senderKeyName)) + apiKey = _serviceOptions.AdditionalApiKeys[senderKeyName]; + + //Send + return _sender.SendMessage(apiKey, toSend); + } - /// - public bool SendWithReplyTo(string replyToAddress, string replyToName, string toAddress, string subject, string bodyHtml) - { - //Call full overload - return SendWithReplyTo(replyToAddress, replyToName, toAddress, null, subject, bodyHtml); - } + /// + public Task SendWithReplyToAsync(string replyToAddress, string replyToName, string toAddress, string subject, + string bodyHtml) + { + //Call full overload + return SendWithReplyToAsync(replyToAddress, replyToName, toAddress, null, subject, bodyHtml); + } - /// - public bool SendWithReplyTo(string replyToAddress, string replyToName, string toAddress, string subject, string bodyHtml, List> tokens) - { - return SendWithReplyTo(replyToAddress, replyToName, toAddress, null, subject, bodyHtml, null, ""); - } + /// + public Task SendWithReplyToAsync(string replyToAddress, string replyToName, string toAddress, string subject, + string bodyHtml, List> tokens) + { + return SendWithReplyToAsync(replyToAddress, replyToName, toAddress, null, subject, bodyHtml, null, ""); + } - /// - public bool SendWithReplyTo(string replyToAddress, string replyToName, string toAddress, IEnumerable ccAddressList, string subject, string bodyHtml) - { - return SendWithReplyTo(replyToAddress, replyToName, toAddress, ccAddressList, subject, bodyHtml, null, ""); - } + /// + public Task SendWithReplyToAsync(string replyToAddress, string replyToName, string toAddress, + IEnumerable ccAddressList, string subject, string bodyHtml) + { + return SendWithReplyToAsync(replyToAddress, replyToName, toAddress, ccAddressList, subject, bodyHtml, null, ""); + } + + /// + public Task SendWithReplyToAsync(string replyToAddress, string replyToName, string toAddress, + IEnumerable ccAddressList, string subject, string bodyHtml, List> tokens) + { + return SendWithReplyToAsync(replyToAddress, replyToName, toAddress, ccAddressList, subject, bodyHtml, tokens, + ""); + } - /// - public bool SendWithReplyTo(string replyToAddress, string replyToName, string toAddress, IEnumerable ccAddressList, string subject, string bodyHtml, List> tokens) - { - return SendWithReplyTo(replyToAddress, replyToName, toAddress, ccAddressList, subject, bodyHtml, tokens, ""); - } + /// + public Task SendWithReplyToAsync(string replyToAddress, string replyToName, string toAddress, + IEnumerable ccAddressList, string subject, string bodyHtml, + List> tokens, + string templateName, string senderKeyName = "") + { + if (string.IsNullOrEmpty(replyToAddress)) + throw new ArgumentNullException(nameof(replyToAddress)); + + if (tokens != null) + foreach (var item in tokens) + bodyHtml = bodyHtml.Replace(item.Key, item.Value); - /// - public bool SendWithReplyTo(string replyToAddress, string replyToName, string toAddress, IEnumerable ccAddressList, string subject, string bodyHtml, - List> tokens, - string templateName, string senderKeyName = "") + //Get the message to send + var toSend = _messageBuilder.CreateMessage(_serviceOptions.AdminEmail, _serviceOptions.AdminName, toAddress, + ccAddressList, subject, + bodyHtml, templateName); + + if (!string.IsNullOrEmpty(replyToAddress)) { - if (string.IsNullOrEmpty(replyToAddress)) - throw new ArgumentNullException(nameof(replyToAddress)); - - if (tokens != null) - { - foreach (var item in tokens) - { - bodyHtml = bodyHtml.Replace(item.Key, item.Value); - } - } - - //Get the message to send - var toSend = _messageBuilder.CreateMessage(_serviceOptions.AdminEmail, _serviceOptions.AdminName, toAddress, ccAddressList, subject, - bodyHtml, templateName); - - if (!string.IsNullOrEmpty(replyToAddress)) - { - var replyTo = new EmailAddress(replyToAddress); - if (!string.IsNullOrEmpty(replyToName)) - replyTo.Name = replyToName; - toSend.ReplyTo = replyTo; - } - - //Determine the key to use - var apiKey = _serviceOptions.SendGridApiKey; - if (!string.IsNullOrEmpty(senderKeyName)) - apiKey = _serviceOptions.AdditionalApiKeys[senderKeyName]; - - //Send - return _sender.SendMessage(apiKey, toSend).GetAwaiter().GetResult(); + var replyTo = new EmailAddress(replyToAddress); + if (!string.IsNullOrEmpty(replyToName)) + replyTo.Name = replyToName; + toSend.ReplyTo = replyTo; } - /// - public bool SendMessageWithAttachment(string toAddress, IEnumerable ccAddressList, string subject, - byte[] fileContent, string fileName, string bodyHtml, List> tokens, string templateName = "", string senderKeyName = "") - { - //Get the message to send - var toSend = _messageBuilder.CreateMessageWithAttachment(_serviceOptions.AdminEmail, _serviceOptions.AdminName, toAddress, - ccAddressList, fileContent, fileName, subject, bodyHtml, templateName); + //Determine the key to use + var apiKey = _serviceOptions.SendGridApiKey; + if (!string.IsNullOrEmpty(senderKeyName)) + apiKey = _serviceOptions.AdditionalApiKeys[senderKeyName]; - //Determine the key to use - var apiKey = _serviceOptions.SendGridApiKey; - if (!string.IsNullOrEmpty(senderKeyName)) - apiKey = _serviceOptions.AdditionalApiKeys[senderKeyName]; + //Send + return _sender.SendMessage(apiKey, toSend); + } - //Send - return _sender.SendMessage(apiKey, toSend).GetAwaiter().GetResult(); - } + /// + public Task SendMessageWithAttachmentAsync(string toAddress, IEnumerable ccAddressList, + string subject, + byte[] fileContent, string fileName, string bodyHtml, List> tokens, + string templateName = "", string senderKeyName = "") + { + //Get the message to send + var toSend = _messageBuilder.CreateMessageWithAttachment(_serviceOptions.AdminEmail, _serviceOptions.AdminName, + toAddress, + ccAddressList, fileContent, fileName, subject, bodyHtml, templateName); + + //Determine the key to use + var apiKey = _serviceOptions.SendGridApiKey; + if (!string.IsNullOrEmpty(senderKeyName)) + apiKey = _serviceOptions.AdditionalApiKeys[senderKeyName]; + + //Send + return _sender.SendMessage(apiKey, toSend); } } \ No newline at end of file