jstedfast/MailKit · error · ProxyProtocolException

Failed to connect to

Error message

Failed to connect to {0}:{1}: {2}

What it means

When the SOCKS5 CONNECT reply's status byte (REP) is not 0x00, ProcessPartialConnectResponse throws ProxyProtocolException formatted with the requested host, port, and a textual reason from GetFailureReason (e.g. general failure, connection not allowed, network unreachable, host unreachable, connection refused, TTL expired, command not supported, address type not supported). The proxy itself reported that the proxied connection failed.

Solutions

  1. Read the embedded failure reason: for 'connection refused'/'host unreachable' fix the target service or network path, for 'not allowed' fix proxy ACLs
  2. If the target allowlists clients, add the proxy server's egress IP
  3. Confirm the target host/port by testing connectivity from the proxy machine itself
  4. Check the client is using CONNECT (the only command MailKit sends) and the port is what the target expects

Example fix

// before
await proxy.ConnectAsync(proxyHost, 1080, "internal-db", 1433); // blocked by proxy ACL
// after
await proxy.ConnectAsync(proxyHost, 1080, "internal-db.example.com", 1433); // allowed FQDN, or request ACL change
Defensive patterns

Strategy: try-catch

Try / catch

try {
    await socks5.ConnectAsync(proxyHost, proxyPort, target, targetPort);
} catch (ProxyProtocolException ex) {
    log.Warn("SOCKS5 CONNECT to {0} refused: {1}", target, ex.Message);
    // branch on the reason text / retry via alternate egress or alert ops
}

Prevention

When it happens

Trigger: Socks5Client.Connect/ConnectAsync where the proxy cannot or will not reach the target host:port — target down, proxy egress blocked by policy, unsupported command, or unresolvable target from the proxy's network.

Common situations: Target service down or moved, corporate proxy ACLs blocking the destination, trying an SMTP/IMAP port the proxy forbids, DNS not working on the proxy host, or remote host refuses connections from the proxy's IP (allowlist lacks proxy IP).

Understand the failure class

Background: ECONNREFUSED and "connection refused" / "could not connect to server" errors: what they mean and how to fix them — this error's family across 44 libraries.

Related errors


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

Appendix: source

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

				break;
			case Socks5AddressType.IPv4:
				addr = ip!.GetAddressBytes ();
				Buffer.BlockCopy (addr, 0, buffer, n, addr.Length);
				n += 4;
				break;
			}
			buffer[n++] = (byte) (port >> 8);
			buffer[n++] = (byte) port;

			return buffer;
		}

		int ProcessPartialConnectResponse (string host, int port, byte[] buffer)
		{
			VerifySocksVersion (buffer[0]);

			if (buffer[1] != (byte) Socks5Reply.Success)
				throw new ProxyProtocolException (string.Format (CultureInfo.InvariantCulture, "Failed to connect to {0}:{1}: {2}", host, port, GetFailureReason (buffer[1])));

			// +-----+-----+-------+------+----------+----------+
			// | VER | REP |  RSV  | ATYP | BND.ADDR | BND.PORT |
			// +-----+-----+-------+------+----------+----------+
			// |  1  |  1  | X'00' |  1   | Variable |    2     |
			// +-----+-----+-------+------+----------+----------+
			var addrType = (Socks5AddressType) buffer[3];

			switch (addrType) {
			case Socks5AddressType.Domain: return 4 + 1 + buffer[4] + 2;
			case Socks5AddressType.IPv6: return 4 + 16 + 2;
			case Socks5AddressType.IPv4: return 4 + 4 + 2;
			default: throw new ProxyProtocolException ("Proxy server returned unknown address type.");
			}
		}

		/// <summary>
		/// Connect to the target host.

View on GitHub (pinned to 9d3859a785)