jstedfast/MailKit · error · ServiceNotConnectedException

The SmtpClient is not connected.

Error message

The SmtpClient is not connected.

What it means

AsyncSmtpClient.NoOpAsync sends the SMTP NOOP command as a liveness/keep-alive check, but only on an established session. If IsConnected is false it throws ServiceNotConnectedException before touching the stream.

Solutions

  1. Guard with if (client.IsConnected) before calling NoOpAsync.
  2. Reconnect with ConnectAsync when IsConnected is false, then retry.
  3. Catch ServiceNotConnectedException in keep-alive loops and reconnect there.
  4. Dispose and recreate the client after unrecoverable disconnections.

Example fix

// before
await client.NoOpAsync();
// after
if (!client.IsConnected)
    await client.ConnectAsync("smtp.example.com", 587, SecureSocketOptions.StartTls);
await client.NoOpAsync();
Defensive patterns

Strategy: validation

Validate before calling

if (client.IsConnected)
    await client.NoOpAsync();

Type guard

bool CanNoOp(AsyncSmtpClient c) => c != null && !c.IsDisposed && c.IsConnected;

Try / catch

try {
    await client.NoOpAsync();
} catch (ServiceNotConnectedException) {
    await client.ConnectAsync(host, port, SecureSocketOptions.Auto);
    await client.AuthenticateAsync(user, pass);
}

Prevention

When it happens

Trigger: Calling NoOpAsync before ConnectAsync, after DisconnectAsync, or after the server closed the connection (idle timeout, network drop).

Common situations: Keep-alive timers firing while the client is disconnected; calling NoOp on a stale client instance after a failed send.

Understand the failure class

Background: "Invalid state transition" errors: "status must be X, actually Y", "already rejected/charging/uninstalled", "cannot ... while running" — what they mean when a library rejects your call — this error's family across 31 libraries.

Related errors


AI-assisted analysis of jstedfast/MailKit@9d3859a785 (2026-09-15). Data as JSON: /api/errors/a04050603c0532f6. Report an issue: GitHub.

Appendix: source

Thrown at MailKit/Net/Smtp/AsyncSmtpClient.cs:845

		/// </exception>
		/// <exception cref="System.OperationCanceledException">
		/// The operation was canceled.
		/// </exception>
		/// <exception cref="System.IO.IOException">
		/// An I/O error occurred.
		/// </exception>
		/// <exception cref="SmtpCommandException">
		/// The SMTP command failed.
		/// </exception>
		/// <exception cref="SmtpProtocolException">
		/// An SMTP protocol error occurred.
		/// </exception>
		public override async Task NoOpAsync (CancellationToken cancellationToken = default)
		{
			CheckDisposed ();

			if (!IsConnected)
				throw new ServiceNotConnectedException ("The SmtpClient is not connected.");

			var response = await SendCommandInternalAsync ("NOOP\r\n", cancellationToken).ConfigureAwait (false);

			if (response.StatusCode != SmtpStatusCode.Ok)
				throw new SmtpCommandException (SmtpErrorCode.UnexpectedStatusCode, response.StatusCode, response.Response);
		}

		/// <summary>
		/// Asynchronously get the size of the message.
		/// </summary>
		/// <remarks>
		/// <para>Asynchronously calculates the size of the message in bytes.</para>
		/// <para>This method is called by <a href="Overload_MailKit_MailTransport_SendAsync.htm">SendAsync</a>
		/// methods in the following conditions:</para>
		/// <list type="bullet">
		/// <item>The SMTP server supports the <c>SIZE=</c> parameter in the <c>MAIL FROM</c> command.</item>
		/// <item>The <see cref="ITransferProgress"/> parameter is non-null.</item>
		/// <item>The SMTP server supports the <c>CHUNKING</c> extension.</item>

View on GitHub (pinned to 9d3859a785)