jstedfast/MailKit · error · ArgumentException

The socket is not connected.

Error message

The socket is not connected.

What it means

SmtpClient.ValidateArguments(Socket, string, int) rejects a socket argument that is not in a connected state. When you pass a pre-established socket to Connect(Socket, host, port), MailKit checks socket.Connected and throws ArgumentException before any SMTP traffic occurs. It exists to catch callers who hand over a closed, never-connected, or half-closed socket.

Solutions

  1. Connect the socket yourself (socket.Connect(host, port)) before passing it to SmtpClient.Connect, and check socket.Connected first
  2. Create a fresh socket for each SmtpClient session instead of reusing stale ones
  3. If pooling sockets, validate the connection with a probe (socket.Poll / connected check) before reuse
  4. Simplify: let MailKit manage the connection by calling Connect(host, port) directly instead of supplying your own socket

Example fix

// before
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
client.Connect(socket, "smtp.example.com", 465); // throws: socket never connected
// after
var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
socket.Connect("smtp.example.com", 465);
if (socket.Connected)
    client.Connect(socket, "smtp.example.com", 465);
Defensive patterns

Strategy: validation

Validate before calling

if (socket == null) throw new ArgumentNullException(nameof(socket));
if (!socket.Connected)
    throw new InvalidOperationException("Pass a socket that is already connected (call socket.Connect first).");
client.Connect(socket, host, port);

Type guard

bool IsUsableSocket(Socket s) => s != null && s.Connected;

Try / catch

try { client.Connect(socket, host, port); }
catch (ArgumentException ex) when (ex.ParamName == "socket") {
    // rebuild a fresh connected socket and retry
}

Prevention

When it happens

Trigger: Calling SmtpClient.Connect(Socket socket, string host, int port) (or the overload with SecureSocketOptions) with a socket that was never connected, whose connection was already closed, or whose remote end dropped (Connected becomes false after a disconnect).

Common situations: Reusing a socket from a previous failed session; creating a new Socket and forgetting to call Connect on it before handing it to MailKit; a long-lived app whose pooled socket timed out or was reset by a firewall; passing a socket from a cancelled/disposed connection.

Understand the failure class

Background: "Must be a positive integer", "Invalid value", "Unsupported": the invalid-argument-value error family, when a library rejects the value you pass — this error's family across 35 libraries.

Related errors


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

Appendix: source

Thrown at MailKit/Net/Smtp/SmtpClient.cs:1538

					stream = ssl;
				} else {
					secure = false;
				}

				PostConnect (stream, host, port, options, starttls, cancellationToken);
			} catch (Exception ex) {
				operation.SetError (ex);
				throw;
			}
		}

		void ValidateArguments (Socket socket, string host, int port)
		{
			if (socket == null)
				throw new ArgumentNullException (nameof (socket));

			if (!socket.Connected)
				throw new ArgumentException ("The socket is not connected.", nameof (socket));

			ValidateArguments (host, port);
		}

		/// <summary>
		/// Establish a connection to the specified SMTP or SMTP/S server using the provided socket.
		/// </summary>
		/// <remarks>
		/// <para>Establishes a connection to the specified SMTP or SMTP/S server using the provided socket.</para>
		/// <para>If the <paramref name="options"/> has a value of
		/// <see cref="SecureSocketOptions.Auto"/>, then the <paramref name="port"/> is used
		/// to determine the default security options. If the <paramref name="port"/> has a value
		/// of <c>465</c>, then the default options used will be
		/// <see cref="SecureSocketOptions.SslOnConnect"/>. All other values will use
		/// <see cref="SecureSocketOptions.StartTlsWhenAvailable"/>.</para>
		/// <para>Once a connection is established, properties such as
		/// <see cref="AuthenticationMechanisms"/> and <see cref="Capabilities"/> will be
		/// populated.</para>

View on GitHub (pinned to 9d3859a785)