ProxyFunc parsed system.networkProxy once, when a client was built, and baked the result into the transport. Editing the proxy address therefore had no effect on any client that already existed: ntfy, the outgoing webhook, NapCat's HTTP API, Telegram's polling and the NapCat WebSocket dialer all kept the address they were built with, and Email's SMTP dialer did the same. Only a controller rebuild would pick up a new one, and that fires only when controllerMethod changes — so the address was effectively fixed until a restart. Resolve it inside the returned function instead. A transport proxy function that returns a nil URL asks for a direct connection, so this also covers clearing the setting: a channel built while a proxy was configured now falls back to dialing directly rather than retrying a dead address. Opting out is now the only case where ProxyFunc returns nil. That is deliberate: a function resolved to nothing at construction time is exactly what pinned the address in the first place. DialWithTimeout reads the address per dial for the same reason, which is what lets the gomail NetDialTimeout hook follow a settings change.