diff --git a/src/Directory.Build.props b/src/Directory.Build.props
index 7471980..270e904 100644
--- a/src/Directory.Build.props
+++ b/src/Directory.Build.props
@@ -1,7 +1,7 @@
- net8.0;net9.0
+ net8.0;net9.0;netstandard2.0
Luke Lowrey;Ben Cull;Github Contributors;John Campion
email;smtp;fluent;fluentemail
https://raw.githubusercontent.com/lukencode/FluentEmail/master/assets/fluentemail_logo_64x64.png
@@ -39,6 +39,7 @@
+
diff --git a/src/FluentEmail.Core/FluentEmail.Core.csproj b/src/FluentEmail.Core/FluentEmail.Core.csproj
index abab3a9..daf073a 100644
--- a/src/FluentEmail.Core/FluentEmail.Core.csproj
+++ b/src/FluentEmail.Core/FluentEmail.Core.csproj
@@ -19,12 +19,12 @@
-
+
-
+
diff --git a/src/Renderers/FluentEmail.Bootstrap/FluentEmail.Bootstrap.csproj b/src/Renderers/FluentEmail.Bootstrap/FluentEmail.Bootstrap.csproj
index 65bf82f..b7e2cca 100644
--- a/src/Renderers/FluentEmail.Bootstrap/FluentEmail.Bootstrap.csproj
+++ b/src/Renderers/FluentEmail.Bootstrap/FluentEmail.Bootstrap.csproj
@@ -1,6 +1,7 @@
+ net8.0;net9.0
Process the FluentEmail templates through UnDotNet.BootstrapEmail. Allows for simpler templates.
Fluent Email - Bootstrap
John Campion
@@ -24,7 +25,7 @@
-
+
diff --git a/src/Renderers/FluentEmail.Liquid/FluentEmail.Liquid.csproj b/src/Renderers/FluentEmail.Liquid/FluentEmail.Liquid.csproj
index c5ad765..1878dbc 100644
--- a/src/Renderers/FluentEmail.Liquid/FluentEmail.Liquid.csproj
+++ b/src/Renderers/FluentEmail.Liquid/FluentEmail.Liquid.csproj
@@ -13,21 +13,13 @@
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -35,9 +27,4 @@
-
-
-
-
-
diff --git a/src/Renderers/FluentEmail.Razor/FluentEmail.Razor.csproj b/src/Renderers/FluentEmail.Razor/FluentEmail.Razor.csproj
index 16da77d..1751f4f 100644
--- a/src/Renderers/FluentEmail.Razor/FluentEmail.Razor.csproj
+++ b/src/Renderers/FluentEmail.Razor/FluentEmail.Razor.csproj
@@ -1,6 +1,7 @@
+ net8.0;net9.0
Generate emails using Razor templates. Anything you can do in ASP.NET is possible here. Uses the RazorLight project under the hood.
Fluent Email - Razor
$(PackageTags);razor
@@ -10,18 +11,9 @@
jcamp.$(AssemblyName)
-
-
-
-
-
-
-
-
-
-
+
@@ -33,7 +25,7 @@
-
+
diff --git a/src/Senders/FluentEmail.Azure.Email/FluentEmail.Azure.Email.csproj b/src/Senders/FluentEmail.Azure.Email/FluentEmail.Azure.Email.csproj
index d13fb37..0b3c66c 100644
--- a/src/Senders/FluentEmail.Azure.Email/FluentEmail.Azure.Email.csproj
+++ b/src/Senders/FluentEmail.Azure.Email/FluentEmail.Azure.Email.csproj
@@ -19,10 +19,11 @@
+
-
+
diff --git a/src/Senders/FluentEmail.Graph/ClientAuthHandler.cs b/src/Senders/FluentEmail.Graph/ClientAuthHandler.cs
new file mode 100644
index 0000000..1e114a8
--- /dev/null
+++ b/src/Senders/FluentEmail.Graph/ClientAuthHandler.cs
@@ -0,0 +1,49 @@
+using Azure.Core;
+using Microsoft.Graph.Auth;
+using Microsoft.Identity.Client;
+using Microsoft.Kiota.Abstractions;
+using Microsoft.Kiota.Abstractions.Authentication;
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace FluentEmail.Graph
+{
+ internal class ClientAuthHandler : TokenCredential
+ {
+ private readonly IConfidentialClientApplication _clientApp;
+
+ public ClientAuthHandler(string appId, string tenantId, string graphSecret)
+ {
+ var builder = ConfidentialClientApplicationBuilder
+ .Create(appId)
+ .WithTenantId(tenantId)
+ .WithClientSecret(graphSecret);
+
+ _clientApp = builder.Build();
+ }
+
+ public override async ValueTask GetTokenAsync(TokenRequestContext requestContext, CancellationToken cancellationToken)
+ {
+ var result = await _clientApp
+ .AcquireTokenForClient(requestContext.Scopes)
+ .ExecuteAsync(cancellationToken)
+ .ConfigureAwait(false);
+
+ return new AccessToken(result.AccessToken, result.ExpiresOn);
+ }
+
+ public override AccessToken GetToken(TokenRequestContext requestContext, CancellationToken cancellationToken)
+ {
+ var result = _clientApp
+ .AcquireTokenForClient(requestContext.Scopes)
+ .ExecuteAsync(cancellationToken)
+ .GetAwaiter()
+ .GetResult();
+
+ return new AccessToken(result.AccessToken, result.ExpiresOn);
+ }
+ }
+}
diff --git a/src/Senders/FluentEmail.Graph/FluentEmail.Graph.csproj b/src/Senders/FluentEmail.Graph/FluentEmail.Graph.csproj
index c40499d..de89810 100644
--- a/src/Senders/FluentEmail.Graph/FluentEmail.Graph.csproj
+++ b/src/Senders/FluentEmail.Graph/FluentEmail.Graph.csproj
@@ -10,21 +10,12 @@
-
+
-
+
-
-
-
-
-
-
-
-
-
-
-
+
+
@@ -36,7 +27,7 @@
-
+
diff --git a/src/Senders/FluentEmail.Graph/GraphSender.cs b/src/Senders/FluentEmail.Graph/GraphSender.cs
index 963ee65..a5bf990 100644
--- a/src/Senders/FluentEmail.Graph/GraphSender.cs
+++ b/src/Senders/FluentEmail.Graph/GraphSender.cs
@@ -1,56 +1,153 @@
-using FluentEmail.Core;
+using Azure.Core;
+using FluentEmail.Core;
using FluentEmail.Core.Interfaces;
using FluentEmail.Core.Models;
using Microsoft.Graph;
-using Microsoft.Graph.Auth;
-using Microsoft.Identity.Client;
+using Microsoft.Graph.Models;
+using Microsoft.Kiota.Abstractions.Authentication;
using System;
using System.Collections.Generic;
using System.IO;
+using System.Linq;
using System.Threading;
using System.Threading.Tasks;
+#nullable enable
+
namespace FluentEmail.Graph
{
- public class GraphSender : ISender
+ public class GraphSender(GraphServiceClient graphClient, bool saveSentItems) : ISender
{
- private readonly string _appId;
- private readonly string _tenantId;
- private readonly string _graphSecret;
- private bool _saveSent;
+ public static readonly bool DefaultSaveSentItems = true;
+
+ private readonly bool _saveSent = saveSentItems;
+ private readonly GraphServiceClient _graphClient = graphClient;
+
+ public GraphSender(GraphServiceClient graphClient)
+ : this(graphClient, DefaultSaveSentItems)
+ { }
+
+ public GraphSender(
+ IAuthenticationProvider authProvider,
+ bool saveSentItems)
+ : this(authProvider, saveSentItems, null)
+ {
+ }
+
+ public GraphSender(IAuthenticationProvider authProvider, bool saveSentItems, string? baseUrl)
+ : this(
+ new GraphServiceClient(authProvider, baseUrl),
+ saveSentItems
+ )
+ {
+ }
+
+ public GraphSender(
+ TokenCredential tokenCredential,
+ bool SaveSentItems,
+ IEnumerable scopes,
+ string? baseUrl
+ ) : this(
+ new Microsoft.Graph.Authentication.AzureIdentityAuthenticationProvider(tokenCredential, null, null, true, scopes?.ToArray() ?? []),
+ SaveSentItems,
+ baseUrl
+ )
+ {
+ }
- private ClientCredentialProvider _authProvider;
- private GraphServiceClient _graphClient;
- private IConfidentialClientApplication _clientApp;
+ public GraphSender(
+ TokenCredential tokenCredential,
+ bool SaveSentItems,
+ IEnumerable scopes
+ ) : this(
+ tokenCredential,
+ SaveSentItems,
+ scopes,
+ null
+ )
+ {
+ }
+
+ public GraphSender(
+ TokenCredential tokenCredential,
+ bool SaveSentItems
+ ) : this(
+ new Microsoft.Graph.Authentication.AzureIdentityAuthenticationProvider(tokenCredential, null, null, true, Array.Empty()),
+ SaveSentItems,
+ null
+ )
+ {
+ }
public GraphSender(
string GraphEmailAppId,
string GraphEmailTenantId,
string GraphEmailSecret,
- bool SaveSentItems)
+ bool SaveSentItems,
+ IEnumerable scopes,
+ string? baseUrl)
+ : this(new ClientAuthHandler(GraphEmailAppId, GraphEmailTenantId, GraphEmailSecret), SaveSentItems, scopes, baseUrl)
{
- _appId = GraphEmailAppId;
- _tenantId = GraphEmailTenantId;
- _graphSecret = GraphEmailSecret;
- _saveSent = SaveSentItems;
+ }
- _clientApp = ConfidentialClientApplicationBuilder
- .Create(_appId)
- .WithTenantId(_tenantId)
- .WithClientSecret(_graphSecret)
- .Build();
+ public GraphSender(
+ string GraphEmailAppId,
+ string GraphEmailTenantId,
+ string GraphEmailSecret,
+ bool SaveSentItems)
+ : this(new ClientAuthHandler(GraphEmailAppId, GraphEmailTenantId, GraphEmailSecret), SaveSentItems)
+ {
+ }
- _authProvider = new ClientCredentialProvider(_clientApp);
+ public GraphSender(
+ string GraphEmailAppId,
+ string GraphEmailTenantId,
+ string GraphEmailSecret,
+ bool SaveSentItems,
+ IEnumerable scopes)
+ : this(new ClientAuthHandler(GraphEmailAppId, GraphEmailTenantId, GraphEmailSecret), SaveSentItems, scopes, null)
+ {
+ }
- _graphClient = new GraphServiceClient(_authProvider);
+ private static Recipient? CreateRecipient(Address address)
+ {
+ if (address == null || string.IsNullOrWhiteSpace(address.EmailAddress))
+ {
+ return null;
+ }
+ return new Recipient
+ {
+ EmailAddress = new EmailAddress
+ {
+ Address = address.EmailAddress,
+ Name = address.Name
+ }
+ };
}
- public SendResponse Send(IFluentEmail email, CancellationToken? token = null)
+ private static List? CreateRecipients(IList recipients)
{
- return SendAsync(email, token).GetAwaiter().GetResult();
+ if (recipients.Count == 0)
+ {
+ return null;
+ }
+ var result = new List();
+ foreach (var r in recipients)
+ {
+ var recipient = CreateRecipient(r);
+ if (recipient != null)
+ {
+ result.Add(recipient);
+ }
+ }
+ if (result.Count == 0)
+ {
+ return null;
+ }
+ return result;
}
- public async Task SendAsync(IFluentEmail email, CancellationToken? token = null)
+ protected virtual Message CreateMessage(IFluentEmail email)
{
var message = new Message
{
@@ -58,127 +155,146 @@ public async Task SendAsync(IFluentEmail email, CancellationToken?
Body = new ItemBody
{
Content = email.Data.Body,
- ContentType = email.Data.IsHtml ? BodyType.Html : BodyType.Text
- },
- From = new Recipient
- {
- EmailAddress = new EmailAddress
- {
- Address = email.Data.FromAddress.EmailAddress,
- Name = email.Data.FromAddress.Name
- }
+ ContentType = email.Data.IsHtml ? BodyType.Html : BodyType.Text,
}
};
- if(email.Data.ToAddresses != null && email.Data.ToAddresses.Count > 0)
+ if (CreateRecipient(email.Data.FromAddress) is { } f)
+ {
+ message.From = f;
+ }
+ if (CreateRecipients(email.Data.ReplyToAddresses) is { } replyTos)
+ {
+ message.ReplyTo = replyTos;
+ }
+ if (CreateRecipients(email.Data.ToAddresses) is { } toRecipients)
{
- var toRecipients = new List();
-
- email.Data.ToAddresses.ForEach(r => toRecipients.Add(new Recipient
- {
- EmailAddress = new EmailAddress
- {
- Address = r.EmailAddress.ToString(),
- Name = r.Name
- }
- }));
-
message.ToRecipients = toRecipients;
}
-
- if(email.Data.BccAddresses != null && email.Data.BccAddresses.Count > 0)
+ if (CreateRecipients(email.Data.BccAddresses) is { } bccRecipients)
{
- var bccRecipients = new List();
-
- email.Data.BccAddresses.ForEach(r => bccRecipients.Add(new Recipient
- {
- EmailAddress = new EmailAddress
- {
- Address = r.EmailAddress.ToString(),
- Name = r.Name
- }
- }));
-
message.BccRecipients = bccRecipients;
}
-
- if (email.Data.CcAddresses != null && email.Data.CcAddresses.Count > 0)
+ if (CreateRecipients(email.Data.CcAddresses) is { } ccRecipients)
{
- var ccRecipients = new List();
-
- email.Data.CcAddresses.ForEach(r => ccRecipients.Add(new Recipient
- {
- EmailAddress = new EmailAddress
- {
- Address = r.EmailAddress.ToString(),
- Name = r.Name
- }
- }));
-
message.CcRecipients = ccRecipients;
}
- if(email.Data.Attachments != null && email.Data.Attachments.Count > 0)
+ if (email.Data.Attachments is { Count: > 0 })
{
- message.Attachments = new MessageAttachmentsCollectionPage();
-
- email.Data.Attachments.ForEach(a =>
+ message.Attachments = [];
+ foreach(var a in email.Data.Attachments)
{
var attachment = new FileAttachment
{
Name = a.Filename,
ContentType = a.ContentType,
+ ContentId = a.ContentId,
+ IsInline = a.IsInline,
ContentBytes = GetAttachmentBytes(a.Data)
};
-
message.Attachments.Add(attachment);
- });
+ }
}
- switch(email.Data.Priority)
- {
- case Priority.High:
- message.Importance = Importance.High;
- break;
- case Priority.Normal:
- message.Importance = Importance.Normal;
- break;
- case Priority.Low:
- message.Importance = Importance.Low;
- break;
- default:
- message.Importance = Importance.Normal;
- break;
+ message.Importance = email.Data.Priority switch
+ {
+ Priority.High => (Importance?)Importance.High,
+ Priority.Normal => (Importance?)Importance.Normal,
+ Priority.Low => (Importance?)Importance.Low,
+ _ => (Importance?)Importance.Normal,
+ };
+
+ if (email.Data.Headers.Any())
+ {
+ var headers = email.Data.Headers
+ .Select(header => new InternetMessageHeader { Name = header.Key, Value = header.Value })
+ .ToList();
+ message.InternetMessageHeaders = headers;
}
- try
+ return message;
+ }
+
+ Task ISender.SendAsync(IFluentEmail email, CancellationToken? token)
+ {
+ return SendAsync(email, token);
+ }
+
+ public SendResponse Send(IFluentEmail email, CancellationToken? token = null)
+ {
+ return SendAsync(email, token).GetAwaiter().GetResult();
+ }
+
+ public Task SendAsync(IFluentEmail email, CancellationToken? token)
+ {
+ if (token.HasValue)
+ {
+ return SendAsync(email, token.Value);
+ }
+ else
{
- await _graphClient.Users[email.Data.FromAddress.EmailAddress]
- .SendMail(message, _saveSent)
- .Request()
- .PostAsync();
+ return SendAsync(email, CancellationToken.None);
+ }
+ }
- return new SendResponse
+ public Task SendAsync(IFluentEmail email)
+ => SendAsync(email, CancellationToken.None);
+
+ public async Task SendAsync(IFluentEmail email, CancellationToken cancellationToken)
+ {
+ try
+ {
+ var message = CreateMessage(email);
+ if (email is { Data.FromAddress.EmailAddress: { Length: > 0 } addr})
{
- MessageId = message.Id
- };
+ var builder = _graphClient.Users[addr].SendMail;
+ await builder.PostAsync(
+ new()
+ {
+ Message = message,
+ SaveToSentItems = _saveSent
+ },
+ default,
+ cancellationToken
+ );
+ return new SendResponse
+ {
+ MessageId = message.Id
+ };
+ }
+ else
+ {
+ var builder = _graphClient.Me.SendMail;
+ await builder.PostAsync(
+ new()
+ {
+ Message = message,
+ SaveToSentItems = _saveSent
+ },
+ default,
+ cancellationToken
+ );
+ return new SendResponse
+ {
+ MessageId = message.Id
+ };
+ }
}
catch (Exception ex)
{
return new SendResponse
{
- ErrorMessages = new List { ex.Message }
+ ErrorMessages = [ ex.Message ]
};
}
}
private static byte[] GetAttachmentBytes(Stream stream)
{
- using(MemoryStream m = new MemoryStream())
- {
- stream.CopyTo(m);
- return m.ToArray();
- }
+ using var m = new MemoryStream();
+ stream.CopyTo(m);
+ return m.ToArray();
}
}
}
diff --git a/src/Senders/FluentEmail.MailKit/FluentEmail.MailKit.csproj b/src/Senders/FluentEmail.MailKit/FluentEmail.MailKit.csproj
index d46b82b..7ed347d 100644
--- a/src/Senders/FluentEmail.MailKit/FluentEmail.MailKit.csproj
+++ b/src/Senders/FluentEmail.MailKit/FluentEmail.MailKit.csproj
@@ -19,23 +19,9 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
diff --git a/src/Senders/FluentEmail.MailPace/FluentEmail.MailPace.csproj b/src/Senders/FluentEmail.MailPace/FluentEmail.MailPace.csproj
index 5574657..6951988 100644
--- a/src/Senders/FluentEmail.MailPace/FluentEmail.MailPace.csproj
+++ b/src/Senders/FluentEmail.MailPace/FluentEmail.MailPace.csproj
@@ -10,6 +10,7 @@
+
@@ -21,7 +22,7 @@
-
+
\ No newline at end of file
diff --git a/src/Senders/FluentEmail.MailPace/StreamExtensions.cs b/src/Senders/FluentEmail.MailPace/StreamExtensions.cs
index 964af47..4631933 100644
--- a/src/Senders/FluentEmail.MailPace/StreamExtensions.cs
+++ b/src/Senders/FluentEmail.MailPace/StreamExtensions.cs
@@ -1,4 +1,6 @@
using System;
+using System.Buffers;
+using System.Diagnostics;
using System.IO;
namespace FluentEmail.MailPace;
@@ -20,4 +22,55 @@ public static string ConvertToBase64(this Stream stream)
return Convert.ToBase64String(bytes);
}
+
+#if NETSTANDARD
+ private static void ReadExactly(this Stream s, byte[] buffer, int offset, int count)
+ {
+ _ = s.ReadAtLeastCore(buffer.AsSpan(offset, count), count, throwOnEndOfStream: true);
+ }
+
+ private static int Read(this Stream s, Span buffer)
+ {
+ byte[] sharedBuffer = ArrayPool.Shared.Rent(buffer.Length);
+ try
+ {
+ int numRead = s.Read(sharedBuffer, 0, buffer.Length);
+ if ((uint)numRead > (uint)buffer.Length)
+ {
+ throw new IOException("IO_StreamTooLong");
+ }
+
+ new ReadOnlySpan(sharedBuffer, 0, numRead).CopyTo(buffer);
+ return numRead;
+ }
+ finally
+ {
+ ArrayPool.Shared.Return(sharedBuffer);
+ }
+ }
+
+ private static int ReadAtLeastCore(this Stream s, Span buffer, int minimumBytes, bool throwOnEndOfStream)
+ {
+ Debug.Assert(minimumBytes <= buffer.Length);
+
+ int totalRead = 0;
+ while (totalRead < minimumBytes)
+ {
+ int read = s.Read(buffer.Slice(totalRead));
+ if (read == 0)
+ {
+ if (throwOnEndOfStream)
+ {
+ throw new EndOfStreamException();
+ }
+
+ return totalRead;
+ }
+
+ totalRead += read;
+ }
+
+ return totalRead;
+ }
+#endif
}
\ No newline at end of file
diff --git a/src/Senders/FluentEmail.Mailgun/FluentEmail.Mailgun.csproj b/src/Senders/FluentEmail.Mailgun/FluentEmail.Mailgun.csproj
index 528c52c..9ae4cc9 100644
--- a/src/Senders/FluentEmail.Mailgun/FluentEmail.Mailgun.csproj
+++ b/src/Senders/FluentEmail.Mailgun/FluentEmail.Mailgun.csproj
@@ -21,7 +21,7 @@
-
+
diff --git a/src/Senders/FluentEmail.Mailtrap/FluentEmail.Mailtrap.csproj b/src/Senders/FluentEmail.Mailtrap/FluentEmail.Mailtrap.csproj
index d3b0ef2..6952127 100644
--- a/src/Senders/FluentEmail.Mailtrap/FluentEmail.Mailtrap.csproj
+++ b/src/Senders/FluentEmail.Mailtrap/FluentEmail.Mailtrap.csproj
@@ -18,7 +18,11 @@
-
+
+
+
+
+
diff --git a/src/Senders/FluentEmail.Mailtrap/HttpHelpers/HttpClientHelpers.cs b/src/Senders/FluentEmail.Mailtrap/HttpHelpers/HttpClientHelpers.cs
index 6a38db8..6dc79a1 100644
--- a/src/Senders/FluentEmail.Mailtrap/HttpHelpers/HttpClientHelpers.cs
+++ b/src/Senders/FluentEmail.Mailtrap/HttpHelpers/HttpClientHelpers.cs
@@ -6,8 +6,6 @@
using System.Text;
using System.Threading.Tasks;
using System.Text.Json;
-using FluentEmail.Core;
-using System.Net.Http.Headers;
namespace FluentEmail.Mailtrap.HttpHelpers
{
diff --git a/src/Senders/FluentEmail.Postmark/FluentEmail.Postmark.csproj b/src/Senders/FluentEmail.Postmark/FluentEmail.Postmark.csproj
index fd0a358..7f1dbdc 100644
--- a/src/Senders/FluentEmail.Postmark/FluentEmail.Postmark.csproj
+++ b/src/Senders/FluentEmail.Postmark/FluentEmail.Postmark.csproj
@@ -10,25 +10,16 @@
-
+
+
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/src/Senders/FluentEmail.SendGrid/FluentEmail.SendGrid.csproj b/src/Senders/FluentEmail.SendGrid/FluentEmail.SendGrid.csproj
index 9bd4ac7..d133d61 100644
--- a/src/Senders/FluentEmail.SendGrid/FluentEmail.SendGrid.csproj
+++ b/src/Senders/FluentEmail.SendGrid/FluentEmail.SendGrid.csproj
@@ -18,11 +18,12 @@
+
-
+
diff --git a/src/Senders/FluentEmail.Smtp/FluentEmail.Smtp.csproj b/src/Senders/FluentEmail.Smtp/FluentEmail.Smtp.csproj
index 071f0ee..13d792a 100644
--- a/src/Senders/FluentEmail.Smtp/FluentEmail.Smtp.csproj
+++ b/src/Senders/FluentEmail.Smtp/FluentEmail.Smtp.csproj
@@ -18,7 +18,7 @@
-
+
diff --git a/test/FluentEmail.Bootstrap.Tests/FluentEmail.Bootstrap.Tests.csproj b/test/FluentEmail.Bootstrap.Tests/FluentEmail.Bootstrap.Tests.csproj
index 0a3b6ee..7f57c59 100644
--- a/test/FluentEmail.Bootstrap.Tests/FluentEmail.Bootstrap.Tests.csproj
+++ b/test/FluentEmail.Bootstrap.Tests/FluentEmail.Bootstrap.Tests.csproj
@@ -10,21 +10,14 @@
-
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/test/FluentEmail.Core.Tests/FluentEmail.Core.Tests.csproj b/test/FluentEmail.Core.Tests/FluentEmail.Core.Tests.csproj
index 581497f..04641f6 100644
--- a/test/FluentEmail.Core.Tests/FluentEmail.Core.Tests.csproj
+++ b/test/FluentEmail.Core.Tests/FluentEmail.Core.Tests.csproj
@@ -25,4 +25,10 @@
+
+
+
+
+
+
diff --git a/test/FluentEmail.Liquid.Tests/FluentEmail.Liquid.Tests.csproj b/test/FluentEmail.Liquid.Tests/FluentEmail.Liquid.Tests.csproj
index 5cd74fd..4d42ed9 100644
--- a/test/FluentEmail.Liquid.Tests/FluentEmail.Liquid.Tests.csproj
+++ b/test/FluentEmail.Liquid.Tests/FluentEmail.Liquid.Tests.csproj
@@ -17,17 +17,15 @@
-
-
-
-
-
-
-
+
+
+
-
-
-
+
+
+
+
+
diff --git a/test/FluentEmail.Razor.Tests/FluentEmail.Razor.Tests.csproj b/test/FluentEmail.Razor.Tests/FluentEmail.Razor.Tests.csproj
index 51fd01a..1dd2436 100644
--- a/test/FluentEmail.Razor.Tests/FluentEmail.Razor.Tests.csproj
+++ b/test/FluentEmail.Razor.Tests/FluentEmail.Razor.Tests.csproj
@@ -17,16 +17,6 @@
-
-
-
-
-
-
-
-
-
-
@@ -36,4 +26,11 @@
+
+
+
+
+
+
+
diff --git a/test/FluentEmail.ThirdParty.Tests/FluentEmail.ThirdParty.Tests.csproj b/test/FluentEmail.ThirdParty.Tests/FluentEmail.ThirdParty.Tests.csproj
index 72a60dd..843b4bd 100644
--- a/test/FluentEmail.ThirdParty.Tests/FluentEmail.ThirdParty.Tests.csproj
+++ b/test/FluentEmail.ThirdParty.Tests/FluentEmail.ThirdParty.Tests.csproj
@@ -19,7 +19,7 @@
PreserveNewest
-
+
PreserveNewest
@@ -34,4 +34,10 @@
+
+
+
+
+
+