Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SMTP.SendEmail - Added AcceptAllCerts parameter #26

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Frends.SMTP.SendEmail/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
# Changelog

## [1.3.0] - 2024-09-30
### Added
- [Breaking] Added parameter AcceptAllCerts which will make the Task to accept all server certifications.
RikuVirtanen marked this conversation as resolved.
Show resolved Hide resolved

## [1.2.1] - 2024-01-02
### Fixed
- Fixed issue with connecting to SMTP servers which do not support authentication.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Include="Moq" Version="4.20.72" />
</ItemGroup>

<ItemGroup>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
using NUnit.Framework;
using Moq;
using System;
using System.IO;
using System.Threading.Tasks;
using Frends.SMTP.SendEmail.Definitions;
using MailKit.Net.Smtp;
using MailKit.Security;
using System.Net.Security;
using System.Threading;

namespace Frends.SMTP.SendEmail.Tests;

Expand Down Expand Up @@ -75,7 +80,8 @@ public void EmailTestSetup()
SMTPServer = SMTPADDRESS,
Port = PORT,
UseOAuth2 = false,
SecureSocket = SecureSocketOption.None
SecureSocket = SecureSocketOption.None,
AcceptAllCerts = false
};

}
Expand All @@ -97,6 +103,19 @@ public async Task SendEmailWithPlainText()
Assert.IsTrue(result.EmailSent);
}

[Test]
public async Task EmailTestAcceptAllCertifications()
{
_options.SecureSocket = SecureSocketOption.StartTls;
_options.AcceptAllCerts = true;

var input = _input;
input.Subject = "Email test - PlainText";

var result = await SMTP.SendEmail(input, null, _options, default);
Assert.IsTrue(result.EmailSent);
}
RikuVirtanen marked this conversation as resolved.
Show resolved Hide resolved

[Test]
public async Task SendEmailWithFileAttachment()
{
Expand Down Expand Up @@ -190,4 +209,41 @@ public void TrySendingEmailWithNoFileAttachmentFoundException()
var ex = Assert.ThrowsAsync<FileNotFoundException>(async () => await SMTP.SendEmail(input, Attachments, _options, default));
Assert.AreEqual(@$"The given filepath '{attachment.FilePath}' had no matching files", ex.Message);
}

[Test]
public async Task TestAcceptAllCerts()
{
var options = new Options
{
AcceptAllCerts = true,
SMTPServer = "smtp.example.com",
Port = 587,
SecureSocket = SecureSocketOption.StartTls,
UseOAuth2 = false,
};

var mockSmtpClient = new Mock<SmtpClient> { CallBase = true };

mockSmtpClient.Setup(client => client.ConnectAsync(
It.IsAny<string>(),
It.IsAny<int>(),
It.IsAny<SecureSocketOptions>(),
It.IsAny<CancellationToken>())).Returns(Task.CompletedTask);

mockSmtpClient.Setup(client => client.AuthenticateAsync(
It.IsAny<SaslMechanism>(),
It.IsAny<CancellationToken>())).Returns(Task.CompletedTask);

await SMTP.InitializeSmtpClient(options, default, mockSmtpClient.Object);

// Assert
mockSmtpClient.Verify(client => client.ConnectAsync(
options.SMTPServer,
options.Port,
SecureSocketOptions.StartTls,
default), Times.Once);

Assert.IsNotNull(mockSmtpClient.Object.ServerCertificateValidationCallback);
Assert.IsTrue(mockSmtpClient.Object.ServerCertificateValidationCallback.Invoke(null, null, null, SslPolicyErrors.None));
}
RikuVirtanen marked this conversation as resolved.
Show resolved Hide resolved
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,13 @@ public class Options
[DefaultValue(SecureSocketOption.Auto)]
public SecureSocketOption SecureSocket { get; set; }

/// <summary>
/// Should the task accept all certificates from IMAP server, including invalid ones?
/// </summary>
/// <example>true</example>
[DefaultValue(false)]
public bool AcceptAllCerts { get; set; }

/// <summary>
/// Set this true if SMTP server expectes OAuth token.
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<Version>1.2.1</Version>
<Version>1.3.0</Version>
<LangVersion>latest</LangVersion>
<Authors>Frends</Authors>
<Company>Frends</Company>
Expand Down Expand Up @@ -32,4 +32,10 @@
</None>
</ItemGroup>

<ItemGroup>
<AssemblyAttribute Include="System.Runtime.CompilerServices.InternalsVisibleTo">
<_Parameter1>$(MSBuildProjectName).Tests</_Parameter1>
</AssemblyAttribute>
</ItemGroup>

</Project>
26 changes: 18 additions & 8 deletions Frends.SMTP.SendEmail/Frends.Smtp.SendEmail/SendEmailTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
using System.Threading;
using System.Threading.Tasks;
using Frends.SMTP.SendEmail.Definitions;
using System.Runtime.CompilerServices;

[assembly: InternalsVisibleTo("Frends.SMTP.Tests")]
namespace Frends.SMTP.SendEmail;
/// <summary>
/// Main class of the Task.
Expand Down Expand Up @@ -96,11 +98,19 @@ public static async Task<Result> SendEmail([PropertyTab] Input input, [PropertyT
/// <summary>
/// Initializes new SmtpClient with given parameters.
/// </summary>
private static async Task<SmtpClient> InitializeSmtpClient(Options settings, CancellationToken cancellationToken)
internal static async Task<SmtpClient> InitializeSmtpClient(Options options, CancellationToken cancellationToken, SmtpClient client = null)
{
var client = new SmtpClient();
client ??= new SmtpClient();

var secureSocketOption = settings.SecureSocket switch
// Accept all certs?
if (options.AcceptAllCerts)
{
#pragma warning disable S4830 // Server certificates should be verified during SSL/TLS connections
client.ServerCertificateValidationCallback = (s, x509certificate, x590chain, sslPolicyErrors) => true;
#pragma warning restore S4830 // Server certificates should be verified during SSL/TLS connections
}
RikuVirtanen marked this conversation as resolved.
Show resolved Hide resolved

var secureSocketOption = options.SecureSocket switch
{
SecureSocketOption.None => SecureSocketOptions.None,
SecureSocketOption.SslOnConnect => SecureSocketOptions.SslOnConnect,
Expand All @@ -109,16 +119,16 @@ private static async Task<SmtpClient> InitializeSmtpClient(Options settings, Can
_ => SecureSocketOptions.Auto,
};

await client.ConnectAsync(settings.SMTPServer, settings.Port, secureSocketOption, cancellationToken);
await client.ConnectAsync(options.SMTPServer, options.Port, secureSocketOption, cancellationToken);

SaslMechanism mechanism;

if (settings.UseOAuth2)
mechanism = new SaslMechanismOAuth2(settings.UserName, settings.Token);
else if (string.IsNullOrEmpty(settings.Password))
if (options.UseOAuth2)
mechanism = new SaslMechanismOAuth2(options.UserName, options.Token);
else if (string.IsNullOrEmpty(options.Password))
return client;
else
mechanism = new SaslMechanismLogin(new NetworkCredential(settings.UserName, settings.Password));
mechanism = new SaslMechanismLogin(new NetworkCredential(options.UserName, options.Password));

await client.AuthenticateAsync(mechanism, cancellationToken);

Expand Down
Loading