diff --git a/MailKit/Net/Smtp/AsyncSmtpClient.cs b/MailKit/Net/Smtp/AsyncSmtpClient.cs index 6320ad4c12..f179b1c952 100644 --- a/MailKit/Net/Smtp/AsyncSmtpClient.cs +++ b/MailKit/Net/Smtp/AsyncSmtpClient.cs @@ -106,13 +106,10 @@ async Task FlushCommandQueueAsync (MimeMessage message, MailboxAdd /// /// An I/O error occurred. /// - /// - /// The SMTP command failed. - /// /// /// An SMTP protocol exception occurred. /// - protected Task SendCommandAsync (string command, CancellationToken cancellationToken = default) + protected async Task SendCommandAsync (string command, CancellationToken cancellationToken = default) { if (command == null) throw new ArgumentNullException (nameof (command)); @@ -125,27 +122,38 @@ protected Task SendCommandAsync (string command, CancellationToken if (!command.EndsWith ("\r\n", StringComparison.Ordinal)) command += "\r\n"; - return Stream.SendCommandAsync (command, cancellationToken); + try { + return await Stream.SendCommandAsync (command, cancellationToken).ConfigureAwait (false); + } catch { + Disconnect (uri.Host, uri.Port, GetSecureSocketOptions (uri), false); + throw; + } } - Task SendEhloAsync (string helo, CancellationToken cancellationToken) + async Task SendEhloAsync (bool connecting, string helo, CancellationToken cancellationToken) { var command = CreateEhloCommand (helo); - return Stream.SendCommandAsync (command, cancellationToken); + try { + return await Stream.SendCommandAsync (command, cancellationToken).ConfigureAwait (false); + } catch { + if (!connecting) + Disconnect (uri.Host, uri.Port, GetSecureSocketOptions (uri), false); + throw; + } } - async Task EhloAsync (CancellationToken cancellationToken) + async Task EhloAsync (bool connecting, CancellationToken cancellationToken) { - var response = await SendEhloAsync ("EHLO", cancellationToken).ConfigureAwait (false); + var response = await SendEhloAsync (connecting, "EHLO", cancellationToken).ConfigureAwait (false); // Some SMTP servers do not accept an EHLO after authentication (despite the rfc saying it is required). - if (authenticated && response.StatusCode == SmtpStatusCode.BadCommandSequence) + if (!connecting && response.StatusCode == SmtpStatusCode.BadCommandSequence) return; if (response.StatusCode != SmtpStatusCode.Ok) { // Try sending HELO instead... - response = await SendEhloAsync ("HELO", cancellationToken).ConfigureAwait (false); + response = await SendEhloAsync (connecting, "HELO", cancellationToken).ConfigureAwait (false); if (response.StatusCode != SmtpStatusCode.Ok) throw new SmtpCommandException (SmtpErrorCode.UnexpectedStatusCode, response.StatusCode, response.Response); } else { @@ -243,7 +251,7 @@ public override async Task AuthenticateAsync (SaslMechanism mechanism, Cancellat if (response.StatusCode == SmtpStatusCode.AuthenticationSuccessful) { if (mechanism.NegotiatedSecurityLayer) - await EhloAsync (cancellationToken).ConfigureAwait (false); + await EhloAsync (false, cancellationToken).ConfigureAwait (false); authenticated = true; OnAuthenticated (response.Response); return; @@ -379,7 +387,7 @@ public override async Task AuthenticateAsync (Encoding encoding, ICredentials cr if (response.StatusCode == SmtpStatusCode.AuthenticationSuccessful) { if (sasl.NegotiatedSecurityLayer) - await EhloAsync (cancellationToken).ConfigureAwait (false); + await EhloAsync (false, cancellationToken).ConfigureAwait (false); authenticated = true; OnAuthenticated (response.Response); return; @@ -431,7 +439,7 @@ async Task PostConnectAsync (Stream stream, string host, int port, SecureSocketO throw new SmtpCommandException (SmtpErrorCode.UnexpectedStatusCode, response.StatusCode, response.Response); // Send EHLO and get a list of supported extensions - await EhloAsync (cancellationToken).ConfigureAwait (false); + await EhloAsync (true, cancellationToken).ConfigureAwait (false); if (options == SecureSocketOptions.StartTls && (capabilities & SmtpCapabilities.StartTLS) == 0) throw new NotSupportedException ("The SMTP server does not support the STARTTLS extension."); @@ -453,7 +461,7 @@ async Task PostConnectAsync (Stream stream, string host, int port, SecureSocketO secure = true; // Send EHLO again and get the new list of supported extensions - await EhloAsync (cancellationToken).ConfigureAwait (false); + await EhloAsync (true, cancellationToken).ConfigureAwait (false); } connected = true; diff --git a/MailKit/Net/Smtp/SmtpClient.cs b/MailKit/Net/Smtp/SmtpClient.cs index 0987cb8af9..67be740b76 100644 --- a/MailKit/Net/Smtp/SmtpClient.cs +++ b/MailKit/Net/Smtp/SmtpClient.cs @@ -680,9 +680,6 @@ QueueResults FlushCommandQueue (MimeMessage message, MailboxAddress sender, ILis /// /// An I/O error occurred. /// - /// - /// The SMTP command failed. - /// /// /// An SMTP protocol exception occurred. /// @@ -699,7 +696,12 @@ protected SmtpResponse SendCommand (string command, CancellationToken cancellati if (!command.EndsWith ("\r\n", StringComparison.Ordinal)) command += "\r\n"; - return Stream.SendCommand (command, cancellationToken); + try { + return Stream.SendCommand (command, cancellationToken); + } catch { + Disconnect (uri.Host, uri.Port, GetSecureSocketOptions (uri), false); + throw; + } } static bool ReadNextLine (string text, ref int index, out int lineStartIndex, out int lineEndIndex) @@ -865,24 +867,30 @@ string CreateEhloCommand (string helo) return string.Format ("{0} {1}\r\n", helo, domain); } - SmtpResponse SendEhlo (string helo, CancellationToken cancellationToken) + SmtpResponse SendEhlo (bool connecting, string helo, CancellationToken cancellationToken) { var command = CreateEhloCommand (helo); - return Stream.SendCommand (command, cancellationToken); + try { + return Stream.SendCommand (command, cancellationToken); + } catch { + if (!connecting) + Disconnect (uri.Host, uri.Port, GetSecureSocketOptions (uri), false); + throw; + } } - void Ehlo (CancellationToken cancellationToken) + void Ehlo (bool connecting, CancellationToken cancellationToken) { - var response = SendEhlo ("EHLO", cancellationToken); + var response = SendEhlo (connecting, "EHLO", cancellationToken); // Some SMTP servers do not accept an EHLO after authentication (despite the rfc saying it is required). - if (authenticated && response.StatusCode == SmtpStatusCode.BadCommandSequence) + if (!connecting && response.StatusCode == SmtpStatusCode.BadCommandSequence) return; if (response.StatusCode != SmtpStatusCode.Ok) { // Try sending HELO instead... - response = SendEhlo ("HELO", cancellationToken); + response = SendEhlo (connecting, "HELO", cancellationToken); if (response.StatusCode != SmtpStatusCode.Ok) throw new SmtpCommandException (SmtpErrorCode.UnexpectedStatusCode, response.StatusCode, response.Response); } else { @@ -999,7 +1007,7 @@ public override void Authenticate (SaslMechanism mechanism, CancellationToken ca if (response.StatusCode == SmtpStatusCode.AuthenticationSuccessful) { if (mechanism.NegotiatedSecurityLayer) - Ehlo (cancellationToken); + Ehlo (false, cancellationToken); authenticated = true; OnAuthenticated (response.Response); return; @@ -1154,7 +1162,7 @@ public override void Authenticate (Encoding encoding, ICredentials credentials, if (response.StatusCode == SmtpStatusCode.AuthenticationSuccessful) { if (sasl.NegotiatedSecurityLayer) - Ehlo (cancellationToken); + Ehlo (false, cancellationToken); authenticated = true; OnAuthenticated (response.Response); return; @@ -1249,7 +1257,7 @@ void PostConnect (Stream stream, string host, int port, SecureSocketOptions opti throw new SmtpCommandException (SmtpErrorCode.UnexpectedStatusCode, response.StatusCode, response.Response); // Send EHLO and get a list of supported extensions - Ehlo (cancellationToken); + Ehlo (true, cancellationToken); if (options == SecureSocketOptions.StartTls && (capabilities & SmtpCapabilities.StartTLS) == 0) throw new NotSupportedException ("The SMTP server does not support the STARTTLS extension."); @@ -1271,7 +1279,7 @@ void PostConnect (Stream stream, string host, int port, SecureSocketOptions opti secure = true; // Send EHLO again and get the new list of supported extensions - Ehlo (cancellationToken); + Ehlo (true, cancellationToken); } connected = true;