jstedfast/MailKit · error · ProxyProtocolException

Failed to negotiate authentication method with the proxy…

Error message

Failed to negotiate authentication method with the proxy server.

What it means

MailKit's Socks5Client threw ProxyProtocolException because the SOCKS5 proxy did not accept any of the authentication methods the client offered during method negotiation. When no credentials are configured the client offers only Anonymous; with credentials it offers UserPassword plus Anonymous. If the server replies with 0xFF (no acceptable methods) or an unrecognized method byte, the negotiation switch falls to the default case and this exception is thrown.

Solutions

  1. Create the Socks5Client with credentials: new Socks5Client(host, port, new NetworkCredential(user, pass)) so UserPassword is negotiated.
  2. Verify the proxy is genuinely SOCKS5 and the host/port are correct (HTTP proxies will not speak the SOCKS5 handshake).
  3. Check the proxy server's allowed auth methods (may need GSSAPI or IP allowlisting instead of user/pass).
  4. Catch ProxyProtocolException and surface a clear configuration error to the user.

Example fix

// before
var proxy = new Socks5Client("proxy.corp.com", 1080);
// after
var proxy = new Socks5Client("proxy.corp.com", 1080, new NetworkCredential("proxyuser", "proxypass"));
Defensive patterns

Strategy: try-catch

Validate before calling

var proxy = proxyCredentials != null
    ? new Socks5Client(proxyHost, proxyPort, proxyCredentials)
    : new Socks5Client(proxyHost, proxyPort);
if (proxyCredentials == null)
    Console.WriteLine("Warning: no proxy credentials supplied; proxy must allow anonymous access");

Type guard

bool IsSocks5ClientUsable(Socks5Client c) => c != null && !string.IsNullOrEmpty(c.ProxyHost) && c.ProxyPort > 0;

Try / catch

try {
    var stream = proxy.Connect(host, port);
} catch (ProxyProtocolException ex) {
    // auth negotiation failed: proxy likely requires credentials or an unsupported method
    throw new ApplicationException("SOCKS5 proxy authentication negotiation failed; check proxy credentials/type", ex);
}

Prevention

When it happens

Trigger: Calling Socks5Client.Connect() against a SOCKS5 proxy that requires username/password authentication while ProxyCredentials is null (so only Anonymous is offered), or against a proxy that uses an unsupported auth method (e.g. GSSAPI), or a non-SOCKS5 server on the proxy port returning a garbage reply.

Common situations: Connecting through a corporate SOCKS5 proxy that mandates authentication but instantiating Socks5Client(host, port) without a NetworkCredential; proxy server actually an HTTP proxy; wrong proxy port pointing at a different service.

Understand the failure class

Related errors


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

Appendix: source

Thrown at MailKit/Net/Proxy/Socks5Client.cs:417

			if (addrType == Socks5AddressType.Domain)
				domain = Encoding.UTF8.GetBytes (host);

			try {
				Socks5AuthMethod method;

				if (ProxyCredentials != null)
					method = NegotiateAuthMethod (socket, cancellationToken, Socks5AuthMethod.UserPassword, Socks5AuthMethod.Anonymous);
				else
					method = NegotiateAuthMethod (socket, cancellationToken, Socks5AuthMethod.Anonymous);

				switch (method) {
				case Socks5AuthMethod.UserPassword:
					Authenticate (socket, cancellationToken);
					break;
				case Socks5AuthMethod.Anonymous:
					break;
				default:
					throw new ProxyProtocolException ("Failed to negotiate authentication method with the proxy server.");
				}

				var buffer = GetConnectCommand (addrType, domain, ip, port, out int n);

				Send (socket, buffer, 0, n, cancellationToken);

				// +-----+-----+-------+------+----------+----------+
				// | VER | REP |  RSV  | ATYP | BND.ADDR | BND.PORT |
				// +-----+-----+-------+------+----------+----------+
				// |  1  |  1  | X'00' |  1   | Variable |    2     |
				// +-----+-----+-------+------+----------+----------+

				// Note: We know we'll need at least 4 bytes of header + a minimum of 1 byte
				// to determine the length of the BND.ADDR field if ATYP is a domain.
				int nread, need = 5;
				n = 0;

				do {

View on GitHub (pinned to 9d3859a785)