""" Network preflight — proves the two halves of the login can run at the same time. Manually, this account is a deadlock. The eCW portal only answers through the corporate proxy, and the proxy refuses the webmail host outright, so a human has to flip the system proxy on to log in, off to read the approval mail, and on again to confirm it. The bot sidesteps that by never touching the webmail *website*: eCW portal + approval link → Playwright, launched with an explicit proxy the approval mail → imaplib, a raw TCP socket to port 993 Two different network paths, so both work concurrently and nothing gets toggled. The one rule that keeps it true: the SYSTEM proxy must stay OFF. Playwright is handed the proxy per-browser; imaplib ignores WinINET and the HTTP(S)_PROXY environment variables because it never speaks HTTP. Run: python "D:\\Ecw Process\\src\\check_net.py" """ # Run standalone from the project root: python tools\check_net.py # The package lives under src\ , which is not on the path for a loose script. import sys as _sys from pathlib import Path as _Path _sys.path.insert(0, str(_Path(__file__).resolve().parent.parent / "src")) # Windows hands these scripts a cp1252 console, which cannot encode the box # characters and arrows below — check_imap.py died on its own output with # UnicodeEncodeError. See runlog._force_utf8_console. for _s in (_sys.stdout, _sys.stderr): try: _s.reconfigure(encoding="utf-8", errors="replace") except Exception: pass import re import ssl import sys import time import socket import urllib.request as urlreq from urllib.parse import urlsplit from ecw_bot import settings as cfg TIMEOUT = 25 def _host_of(url: str) -> str: return urlsplit(url).hostname or url def _try_http(url: str, proxy: str) -> tuple: """(ok, detail). proxy="" forces a direct connection.""" handler = urlreq.ProxyHandler({"http": proxy, "https": proxy} if proxy else {}) opener = urlreq.build_opener(handler) start = time.time() try: resp = opener.open(url, timeout=TIMEOUT) return True, f"HTTP {resp.status} ({time.time() - start:.1f}s)" except Exception as exc: return False, f"{type(exc).__name__}: {str(exc)[:80]} ({time.time() - start:.1f}s)" def _try_tcp(host: str, port: int) -> tuple: start = time.time() sock = socket.socket() sock.settimeout(TIMEOUT) try: sock.connect((host, port)) return True, f"connected ({time.time() - start:.1f}s)" except Exception as exc: return False, f"{type(exc).__name__}: {exc}" finally: sock.close() def _row(label: str, ok: bool, detail: str) -> None: print(f" {label:<22} {'OK ' if ok else 'FAIL'} {detail}") def _system_proxy_enabled(): """True/False, or None when it cannot be read (non-Windows).""" try: import winreg key = winreg.OpenKey( winreg.HKEY_CURRENT_USER, r"Software\Microsoft\Windows\CurrentVersion\Internet Settings") with key: return bool(winreg.QueryValueEx(key, "ProxyEnable")[0]) except Exception: return None def main() -> int: proxy = cfg.proxy_settings() if not proxy: print("No proxy configured in .env — set PROXY_IP / PROXY_PORT") return 2 proxy_url = proxy["server"] problems = [] print(f"proxy : {proxy_url}") print(f"portal : {_host_of(cfg.ECW_URL)}") print(f"mailbox : {cfg.IMAP_HOST}:{cfg.IMAP_PORT}\n") # ── the proxy itself ────────────────────────────────────────────────────── m = re.match(r"https?://([^:/]+):(\d+)", proxy_url) print("proxy reachability") if m: ok, detail = _try_tcp(m.group(1), int(m.group(2))) _row("TCP to proxy", ok, detail) if not ok: problems.append("the proxy itself is unreachable — check VPN / network") print() # ── eCW: must need the proxy ────────────────────────────────────────────── print("eCW portal (browser goes through the proxy)") direct_ok, direct_detail = _try_http(cfg.ECW_URL, "") proxy_ok, proxy_detail = _try_http(cfg.ECW_URL, proxy_url) _row("without proxy", direct_ok, direct_detail) _row("through proxy", proxy_ok, proxy_detail) if not proxy_ok: problems.append("eCW is unreachable through the proxy — the bot cannot log in") print() # ── mailbox: must NOT need the proxy ────────────────────────────────────── print("mailbox (imaplib — raw socket, never proxied)") imap_ok, imap_detail = _try_tcp(cfg.IMAP_HOST, cfg.IMAP_PORT) _row(f"TCP :{cfg.IMAP_PORT}", imap_ok, imap_detail) if imap_ok: start = time.time() try: conn = (imap_ssl(cfg) if cfg.IMAP_SSL else None) conn.login(cfg.IMAP_USERNAME, cfg.IMAP_PASSWORD) conn.logout() _row("IMAP login", True, f"{cfg.IMAP_USERNAME} ({time.time() - start:.1f}s)") except Exception as exc: _row("IMAP login", False, f"{type(exc).__name__}: {str(exc)[:80]}") problems.append("IMAP login failed — run check_imap.py") else: problems.append("port 993 is blocked — the bot cannot read the approval mail") print() # ── the rule that makes it work ─────────────────────────────────────────── print("system proxy (must stay OFF)") sysproxy = _system_proxy_enabled() if sysproxy is None: _row("ProxyEnable", True, "not readable (non-Windows?) — skipped") elif sysproxy: _row("ProxyEnable", False, "1 — system proxy is ON") problems.append( "the system proxy is ON. Turn it OFF: the bot proxies only its own " "browser, and a system-wide proxy is what blocks the webmail host") else: _row("ProxyEnable", True, "0 — off, correct") print() if problems: print("PROBLEMS") for p in problems: print(f" - {p}") return 1 print("All good — the browser can reach eCW through the proxy while imaplib") print("reads the mailbox directly. No proxy toggling needed.") return 0 def imap_ssl(c): import imaplib return imaplib.IMAP4_SSL(c.IMAP_HOST, c.IMAP_PORT, ssl_context=ssl.create_default_context()) if __name__ == "__main__": sys.exit(main())