diff --git a/src/libraries/System.Net.Mail/ref/System.Net.Mail.cs b/src/libraries/System.Net.Mail/ref/System.Net.Mail.cs index f531d503da81b3..66a663d05940de 100644 --- a/src/libraries/System.Net.Mail/ref/System.Net.Mail.cs +++ b/src/libraries/System.Net.Mail/ref/System.Net.Mail.cs @@ -181,7 +181,6 @@ public SmtpClient(string? host, int port) { } public string? PickupDirectoryLocation { get { throw null; } set { } } public int Port { get { throw null; } set { } } public System.Net.ServicePoint ServicePoint { get { throw null; } } - public System.Net.Security.SslClientAuthenticationOptions SslOptions { get { throw null; } set { } } public string? TargetName { get { throw null; } set { } } public int Timeout { get { throw null; } set { } } public bool UseDefaultCredentials { get { throw null; } set { } } diff --git a/src/libraries/System.Net.Mail/ref/System.Net.Mail.csproj b/src/libraries/System.Net.Mail/ref/System.Net.Mail.csproj index 2d68e1d7bf609c..26e17b8b347788 100644 --- a/src/libraries/System.Net.Mail/ref/System.Net.Mail.csproj +++ b/src/libraries/System.Net.Mail/ref/System.Net.Mail.csproj @@ -12,7 +12,6 @@ - diff --git a/src/libraries/System.Net.Mail/src/System.Net.Mail.csproj b/src/libraries/System.Net.Mail/src/System.Net.Mail.csproj index 7e835fc2971978..46fc41705f60cb 100644 --- a/src/libraries/System.Net.Mail/src/System.Net.Mail.csproj +++ b/src/libraries/System.Net.Mail/src/System.Net.Mail.csproj @@ -106,8 +106,6 @@ - diff --git a/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpClient.Wasm.cs b/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpClient.Wasm.cs index d6851d215ed39c..b8b9c08b4cd65f 100644 --- a/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpClient.Wasm.cs +++ b/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpClient.Wasm.cs @@ -4,7 +4,6 @@ using System; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; -using System.Net.Security; using System.Runtime.Versioning; using System.Security.Cryptography.X509Certificates; using System.Threading; @@ -117,13 +116,6 @@ public bool EnableSsl set => throw new PlatformNotSupportedException(); } - /// Gets or sets the options used to establish a TLS connection. - public SslClientAuthenticationOptions SslOptions - { - get => throw new PlatformNotSupportedException(); - set => throw new PlatformNotSupportedException(); - } - /// /// Certificates used by the client for establishing an SSL connection with the server. /// diff --git a/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpClient.cs b/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpClient.cs index 4818f4b5e8eb1a..372fd2b06ce932 100644 --- a/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpClient.cs +++ b/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpClient.cs @@ -7,7 +7,6 @@ using System.Globalization; using System.IO; using System.Net.NetworkInformation; -using System.Net.Security; using System.Runtime.ExceptionServices; using System.Runtime.Versioning; using System.Security; @@ -342,41 +341,9 @@ public bool EnableSsl } } - /// Gets or sets the options used to establish a TLS connection. - /// The TLS client authentication options. The default is a new instance. - /// - /// These options are used only when is . - /// When is , - /// the current is used without modifying the options. - /// Changing this object in place, including its nested objects such as - /// , does not invalidate an existing connection. - /// To ensure changes are used for the next send, assign this property again, even to the same instance. - /// Assignment invalidates the cached connection so that the next send establishes a new connection. - /// Do not modify the options or their nested objects while a send is in progress. - /// - /// The value is . - /// A send operation is in progress. - public SslClientAuthenticationOptions SslOptions - { - get => _transport.SslOptions; - set - { - ArgumentNullException.ThrowIfNull(value); - - if (_inCall) - { - throw new InvalidOperationException(SR.SmtpInvalidOperationDuringSend); - } - - _transport.SslOptions = value; - } - } - - /// Gets the certificates used by the client to establish a TLS connection with the server. - /// - /// Returns from , - /// initializing an empty collection if necessary. Modifying the collection does not invalidate an existing connection. - /// + /// + /// Certificates used by the client for establishing an SSL connection with the server. + /// public X509CertificateCollection ClientCertificates { get diff --git a/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpConnection.cs b/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpConnection.cs index f2bee927815dd8..5744d9faceea55 100644 --- a/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpConnection.cs +++ b/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpConnection.cs @@ -9,7 +9,9 @@ using System.Net.Security; using System.Net.Sockets; using System.Runtime.ExceptionServices; +using System.Security.Authentication; using System.Security.Authentication.ExtendedProtection; +using System.Security.Cryptography.X509Certificates; using System.Security.Principal; using System.Threading; using System.Threading.Tasks; @@ -31,6 +33,8 @@ internal sealed partial class SmtpConnection private readonly ICredentialsByHost? _credentials; private string[]? _extensions; + private bool _enableSsl; + private X509CertificateCollection? _clientCertificates; internal SmtpConnection(SmtpTransport parent, SmtpClient client, ICredentialsByHost? credentials, ISmtpAuthenticationModule[] authenticationModules) { @@ -50,7 +54,29 @@ internal SmtpConnection(SmtpTransport parent, SmtpClient client, ICredentialsByH internal SmtpReplyReaderFactory? Reader => _responseReader; - internal SslClientAuthenticationOptions? SslOptions { get; set; } + internal bool EnableSsl + { + get + { + return _enableSsl; + } + set + { + _enableSsl = value; + } + } + + internal X509CertificateCollection? ClientCertificates + { + get + { + return _clientCertificates; + } + set + { + _clientCertificates = value; + } + } internal void InitializeConnection(string host, int port) { @@ -118,7 +144,7 @@ internal async Task GetConnectionAsync(string host, int port, Cancel } // Handle SSL/TLS - if (SslOptions is SslClientAuthenticationOptions sslOptions) + if (_enableSsl) { if (!_serverSupportsStartTls) { @@ -131,19 +157,30 @@ internal async Task GetConnectionAsync(string host, int port, Cancel await StartTlsCommand.SendAsync(this, cancellationToken).ConfigureAwait(false); - SslStream sslStream = new SslStream(_stream!); - _stream = sslStream; +#pragma warning disable SYSLIB0014 // ServicePointManager is obsolete + SslStream sslStream = new SslStream(_stream!, false, ServicePointManager.ServerCertificateValidationCallback); if (isAsync) { // If we are using async, we need to use the async version of AuthenticateAsClientAsync - await sslStream.AuthenticateAsClientAsync(sslOptions, cancellationToken).ConfigureAwait(false); + await sslStream.AuthenticateAsClientAsync( + new SslClientAuthenticationOptions + { + TargetHost = host, + ClientCertificates = _clientCertificates, + EnabledSslProtocols = (SslProtocols)ServicePointManager.SecurityProtocol, // enums use same values + CertificateRevocationCheckMode = ServicePointManager.CheckCertificateRevocationList ? + X509RevocationMode.Online : X509RevocationMode.NoCheck, + }, + cancellationToken).ConfigureAwait(false); } else { // Synchronous version - sslStream.AuthenticateAsClient(sslOptions); + sslStream.AuthenticateAsClient(host, _clientCertificates, (SslProtocols)ServicePointManager.SecurityProtocol, ServicePointManager.CheckCertificateRevocationList); } +#pragma warning restore SYSLIB0014 // ServicePointManager is obsolete + _stream = sslStream; _responseReader = new SmtpReplyReaderFactory(_stream); // According to RFC 3207: The client SHOULD send an EHLO command diff --git a/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpTransport.cs b/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpTransport.cs index d01c7a18e2c229..19d01f8af9f838 100644 --- a/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpTransport.cs +++ b/src/libraries/System.Net.Mail/src/System/Net/Mail/SmtpTransport.cs @@ -4,7 +4,6 @@ using System.Collections.Generic; using System.IO; using System.Net.Mime; -using System.Net.Security; using System.Runtime.ExceptionServices; using System.Security.Cryptography.X509Certificates; using System.Threading; @@ -80,17 +79,7 @@ internal bool EnableSsl } } - internal SslClientAuthenticationOptions SslOptions - { - get => field ??= new SslClientAuthenticationOptions(); - set - { - field = value; - InvalidateCachedConnection(); - } - } - - internal X509CertificateCollection ClientCertificates => SslOptions.ClientCertificates ??= new X509CertificateCollection(); + internal X509CertificateCollection ClientCertificates => field ??= new X509CertificateCollection(); internal bool ServerSupportsEai { @@ -133,9 +122,8 @@ internal Task GetConnectionAsync(string host, int port, Cancellation if (EnableSsl) { - SslClientAuthenticationOptions sslOptions = SslOptions.ShallowClone(); - sslOptions.TargetHost ??= host; - _connection.SslOptions = sslOptions; + _connection.EnableSsl = true; + _connection.ClientCertificates = ClientCertificates; } return _connection.GetConnectionAsync(host, port, cancellationToken); diff --git a/src/libraries/System.Net.Mail/tests/Functional/LoopbackSmtpServer.cs b/src/libraries/System.Net.Mail/tests/Functional/LoopbackSmtpServer.cs index 2a138b2161ebeb..39b73ff3eea558 100644 --- a/src/libraries/System.Net.Mail/tests/Functional/LoopbackSmtpServer.cs +++ b/src/libraries/System.Net.Mail/tests/Functional/LoopbackSmtpServer.cs @@ -55,8 +55,6 @@ public class LoopbackSmtpServer : IDisposable public ParsedMailMessage Message { get; private set; } public bool IsEncrypted { get; private set; } public string TlsHostName { get; private set; } - public System.Security.Authentication.SslProtocols TlsProtocol { get; private set; } - public SslApplicationProtocol ApplicationProtocol { get; private set; } public int ConnectionCount { get; private set; } public int MessagesReceived { get; private set; } @@ -265,8 +263,6 @@ await SendMessageAsync( await sslStream.AuthenticateAsServerAsync(SslOptions); IsEncrypted = true; TlsHostName = sslStream.TargetHostName; - TlsProtocol = sslStream.SslProtocol; - ApplicationProtocol = sslStream.NegotiatedApplicationProtocol; stream = sslStream; break; diff --git a/src/libraries/System.Net.Mail/tests/Functional/SmtpClientTest.cs b/src/libraries/System.Net.Mail/tests/Functional/SmtpClientTest.cs index 7072e0bf759e42..2f9833e4053c09 100644 --- a/src/libraries/System.Net.Mail/tests/Functional/SmtpClientTest.cs +++ b/src/libraries/System.Net.Mail/tests/Functional/SmtpClientTest.cs @@ -14,11 +14,8 @@ using System.Globalization; using System.IO; using System.Net.NetworkInformation; -using System.Net.Security; using System.Net.Sockets; using System.Reflection; -using System.Security.Authentication; -using System.Security.Cryptography.X509Certificates; using System.Threading; using System.Threading.Tasks; using Microsoft.DotNet.RemoteExecutor; @@ -83,113 +80,6 @@ public void EnableSslTest(bool value) Assert.Equal(value, Smtp.EnableSsl); } - [Fact] - public void SslOptions_DefaultsAndIdentity() - { - SslClientAuthenticationOptions options = Smtp.SslOptions; - Assert.Same(options, Smtp.SslOptions); - Assert.Null(options.TargetHost); - Assert.Null(options.ClientCertificates); - Assert.Null(options.RemoteCertificateValidationCallback); - Assert.Equal(SslProtocols.None, options.EnabledSslProtocols); - Assert.Equal(X509RevocationMode.NoCheck, options.CertificateRevocationCheckMode); - - using var other = new SmtpClient(); - Assert.NotSame(options, other.SslOptions); - - var replacement = new SslClientAuthenticationOptions(); - Smtp.SslOptions = replacement; - Assert.Same(replacement, Smtp.SslOptions); - AssertExtensions.Throws("value", () => Smtp.SslOptions = null!); - Assert.Same(replacement, Smtp.SslOptions); - } - - [Theory] - [InlineData(false)] - [InlineData(true)] - public void ClientCertificates_ForwardsToSslOptions(bool getCertificatesFirst) - { - if (getCertificatesFirst) - { - Assert.Empty(Smtp.ClientCertificates); - } - - var certificates = new X509CertificateCollection(); - var options = new SslClientAuthenticationOptions { ClientCertificates = certificates }; - Smtp.SslOptions = options; - Assert.Same(certificates, Smtp.ClientCertificates); - - var replacement = new X509CertificateCollection(); - options.ClientCertificates = replacement; - Assert.Same(replacement, Smtp.ClientCertificates); - - options.ClientCertificates = null; - X509CertificateCollection initialized = Smtp.ClientCertificates; - Assert.Empty(initialized); - Assert.Same(initialized, options.ClientCertificates); - Assert.Same(initialized, Smtp.ClientCertificates); - - Smtp.SslOptions = new SslClientAuthenticationOptions(); - Assert.NotSame(initialized, Smtp.ClientCertificates); - Assert.Same(Smtp.ClientCertificates, Smtp.SslOptions.ClientCertificates); - } - - [ConditionalTheory(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] - [InlineData(false)] - [InlineData(true)] - public async Task SslOptions_ServicePointManagerIgnored(bool customValidation) - { - await RemoteExecutor.Invoke(async useCustomValidation => - { - int globalCallbackCalls = 0; -#pragma warning disable SYSLIB0014 // Verify that SMTP no longer uses these global settings. - ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls13; - ServicePointManager.CheckCertificateRevocationList = true; - ServicePointManager.ServerCertificateValidationCallback = (sender, certificate, chain, errors) => - { - globalCallbackCalls++; - return !bool.Parse(useCustomValidation); - }; -#pragma warning restore SYSLIB0014 - - using var certificates = new CertificateSetup(); - using var server = new LoopbackSmtpServer(); - server.SslOptions = new SslServerAuthenticationOptions - { - ServerCertificateContext = certificates.CreateSslStreamCertificateContext(), - EnabledSslProtocols = SslProtocols.Tls12, - }; - using SmtpClient client = server.CreateClient(); - client.EnableSsl = true; - Assert.Equal(SslProtocols.None, client.SslOptions.EnabledSslProtocols); - Assert.Equal(X509RevocationMode.NoCheck, client.SslOptions.CertificateRevocationCheckMode); - Assert.Null(client.SslOptions.RemoteCertificateValidationCallback); - - if (bool.Parse(useCustomValidation)) - { - int clientCallbackCalls = 0; - client.SslOptions.RemoteCertificateValidationCallback = (sender, certificate, chain, errors) => - { - clientCallbackCalls++; - Assert.Equal(X509RevocationMode.NoCheck, chain.ChainPolicy.RevocationMode); - return true; - }; - - await client.SendMailAsync("from@example.com", "to@example.com", "subject", "body"); - Assert.Equal(1, clientCallbackCalls); - Assert.True(server.IsEncrypted); - } - else - { - SmtpException exception = await Assert.ThrowsAsync(() => - client.SendMailAsync("from@example.com", "to@example.com", "subject", "body")); - Assert.IsType(exception.InnerException); - } - - Assert.Equal(0, globalCallbackCalls); - }, customValidation.ToString()).DisposeAsync(); - } - [Theory] [InlineData("127.0.0.1")] [InlineData("smtp.ximian.com")] diff --git a/src/libraries/System.Net.Mail/tests/Functional/SmtpClientTlsTest.cs b/src/libraries/System.Net.Mail/tests/Functional/SmtpClientTlsTest.cs index d29a5fcb4726d4..bc4084f45e62b4 100644 --- a/src/libraries/System.Net.Mail/tests/Functional/SmtpClientTlsTest.cs +++ b/src/libraries/System.Net.Mail/tests/Functional/SmtpClientTlsTest.cs @@ -52,7 +52,9 @@ public SmtpClientTlsTest(ITestOutputHelper output, CertificateSetup certificateS ClientCertificateRequired = false, }; - Smtp.SslOptions.RemoteCertificateValidationCallback = ServerCertValidationCallback; +#pragma warning disable SYSLIB0014 // ServicePointManager is obsolete + ServicePointManager.ServerCertificateValidationCallback = ServerCertValidationCallback; +#pragma warning restore SYSLIB0014 // ServicePointManager is obsolete } [ActiveIssue("https://github.com/dotnet/runtime/issues/120959", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot), nameof(PlatformDetection.IsAndroid))] @@ -156,10 +158,8 @@ public async Task AuthenticationException_Propagates() } [ActiveIssue("https://github.com/dotnet/runtime/issues/120959", typeof(PlatformDetection), nameof(PlatformDetection.IsNativeAot), nameof(PlatformDetection.IsAndroid))] - [Theory] - [InlineData(false)] - [InlineData(true)] - public async Task ClientCertificateRequired_Sent(bool useSslOptions) + [Fact] + public async Task ClientCertificateRequired_Sent() { Server.SslOptions.ClientCertificateRequired = true; X509Certificate2 clientCert = _certificateSetup.ServerCert; // use the server cert as a client cert for testing @@ -177,14 +177,7 @@ public async Task ClientCertificateRequired_Sent(bool useSslOptions) Smtp.Credentials = new NetworkCredential("foo", "bar"); Smtp.EnableSsl = true; - if (useSslOptions) - { - Smtp.SslOptions.ClientCertificates = new X509CertificateCollection { clientCert }; - } - else - { - Smtp.ClientCertificates.Add(clientCert); - } + Smtp.ClientCertificates.Add(clientCert); MailMessage msg = new MailMessage("foo@example.com", "bar@example.com", "hello", "howdydoo"); @@ -214,163 +207,6 @@ public async Task EnableSsl_ChangedAfterConnect_EstablishesNewEncryptedConnectio Assert.True(Server.IsEncrypted, "Second connection should be encrypted after enabling SSL."); } - [Theory] - [InlineData(null)] - [InlineData("")] - [InlineData("smtp.example.com")] - public async Task SslOptions_TargetHost(string? targetHost) - { - Smtp.EnableSsl = true; - Smtp.SslOptions.TargetHost = targetHost; - _serverCertValidationCallback = (cert, chain, errors) => true; - using var message = new MailMessage("from@example.com", "to@example.com", "subject", "body"); - - await SendMail(message); - - Assert.Equal(targetHost ?? Smtp.Host, Server.TlsHostName); - Assert.Equal(targetHost, Smtp.SslOptions.TargetHost); - } - - [Fact] - public async Task SslOptions_DefaultTargetHostFollowsHostChange() - { - Server.ReceiveMultipleConnections = true; - Smtp.EnableSsl = true; - string? validatedHost = null; - Smtp.SslOptions.RemoteCertificateValidationCallback = (sender, cert, chain, errors) => - { - validatedHost = Assert.IsType(sender).TargetHostName; - return true; - }; - using var message = new MailMessage("from@example.com", "to@example.com", "subject", "body"); - - await SendMail(message); - Assert.Equal("localhost", validatedHost); - - Smtp.Host = "127.0.0.1"; - await SendMail(message); - Assert.Equal("127.0.0.1", validatedHost); - Assert.Equal(2, Server.ConnectionCount); - Assert.Null(Smtp.SslOptions.TargetHost); - } - - [Fact] - public async Task SslOptions_ProtocolSelection() - { - Smtp.EnableSsl = true; - Smtp.SslOptions.EnabledSslProtocols = SslProtocols.Tls12; - _serverCertValidationCallback = (cert, chain, errors) => true; - using var message = new MailMessage("from@example.com", "to@example.com", "subject", "body"); - - await SendMail(message); - - Assert.Equal(SslProtocols.Tls12, Server.TlsProtocol); - } - - [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.SupportsAlpn))] - public async Task SslOptions_ApplicationProtocols() - { - var protocol = new SslApplicationProtocol("smtp-test"); - Server.SslOptions.ApplicationProtocols = new() { protocol }; - Smtp.EnableSsl = true; - Smtp.SslOptions.ApplicationProtocols = new() { protocol }; - _serverCertValidationCallback = (cert, chain, errors) => true; - using var message = new MailMessage("from@example.com", "to@example.com", "subject", "body"); - - await SendMail(message); - - Assert.Equal(protocol, Server.ApplicationProtocol); - } - - [Fact] - public async Task SslOptions_DisabledSslDoesNotUseOptions() - { - bool callbackCalled = false; - Smtp.SslOptions.RemoteCertificateValidationCallback = (sender, cert, chain, errors) => - { - callbackCalled = true; - return false; - }; - using var message = new MailMessage("from@example.com", "to@example.com", "subject", "body"); - - await SendMail(message); - - Assert.False(Server.IsEncrypted); - Assert.False(callbackCalled); - } - - [Theory] - [InlineData(false)] - [InlineData(true)] - public async Task SslOptions_AssignmentInvalidatesConnection(bool sameInstance) - { - Server.ReceiveMultipleConnections = true; - Smtp.EnableSsl = true; - X509CertificateCollection certificates = Smtp.ClientCertificates; - _serverCertValidationCallback = (cert, chain, errors) => true; - using var message = new MailMessage("from@example.com", "to@example.com", "subject", "body"); - await SendMail(message); - await SendMail(message); - Assert.Equal(1, Server.ConnectionCount); - - SslClientAuthenticationOptions options = sameInstance ? Smtp.SslOptions : new SslClientAuthenticationOptions - { - RemoteCertificateValidationCallback = ServerCertValidationCallback, - }; - options.TargetHost = "smtp.example.com"; - if (sameInstance) - { - certificates.Add(_certificateSetup.ServerCert); - Assert.Same(certificates, options.ClientCertificates); - await SendMail(message); - Assert.Equal(1, Server.ConnectionCount); - Assert.Equal("localhost", Server.TlsHostName); - } - - Smtp.SslOptions = options; - await SendMail(message); - Assert.Equal(2, Server.ConnectionCount); - Assert.Equal("smtp.example.com", Server.TlsHostName); - } - - [Fact] - public async Task SslOptions_InPlaceChangeAppliesAfterReconnect() - { - Server.ReceiveMultipleConnections = true; - Smtp.EnableSsl = true; - _serverCertValidationCallback = (cert, chain, errors) => true; - using var message = new MailMessage("from@example.com", "to@example.com", "subject", "body"); - await SendMail(message); - - Smtp.SslOptions.TargetHost = "smtp.example.com"; - Smtp.TargetName = "SMTPSVC/another-name"; - await SendMail(message); - - Assert.Equal(2, Server.ConnectionCount); - Assert.Equal("smtp.example.com", Server.TlsHostName); - } - - [Fact] - public async Task SslOptions_AssignmentDuringSendThrows() - { - Smtp.EnableSsl = true; - SslClientAuthenticationOptions original = Smtp.SslOptions; - bool callbackCalled = false; - _serverCertValidationCallback = (cert, chain, errors) => - { - callbackCalled = true; - Assert.Throws(() => Smtp.SslOptions = new SslClientAuthenticationOptions()); - Assert.Throws(() => Smtp.SslOptions = original); - Assert.Same(original, Smtp.SslOptions); - return true; - }; - using var message = new MailMessage("from@example.com", "to@example.com", "subject", "body"); - - await SendMail(message); - - Assert.True(callbackCalled); - } - private bool ServerCertValidationCallback(object sender, X509Certificate? certificate, X509Chain? chain, SslPolicyErrors sslPolicyErrors) { if (_serverCertValidationCallback != null) @@ -383,16 +219,21 @@ private bool ServerCertValidationCallback(object sender, X509Certificate? certif } } + // since the tests change global state (ServicePointManager.ServerCertificateValidationCallback), we need to run them in isolation + + [Collection(nameof(DisableParallelization))] public class SmtpClientTlsTest_Send : SmtpClientTlsTest, IClassFixture { public SmtpClientTlsTest_Send(ITestOutputHelper output, CertificateSetup certificateSetup) : base(output, certificateSetup) { } } + [Collection(nameof(DisableParallelization))] public class SmtpClientTlsTest_SendAsync : SmtpClientTlsTest, IClassFixture { public SmtpClientTlsTest_SendAsync(ITestOutputHelper output, CertificateSetup certificateSetup) : base(output, certificateSetup) { } } + [Collection(nameof(DisableParallelization))] public class SmtpClientTlsTest_SendMailAsync : SmtpClientTlsTest, IClassFixture { public SmtpClientTlsTest_SendMailAsync(ITestOutputHelper output, CertificateSetup certificateSetup) : base(output, certificateSetup) { }