"""企业微信推送诊断:分步查 gettoken / message_send 的确切 errcode/errmsg。 用法(服务器上,.env 同目录): .venv/Scripts/python.exe scripts/diag_wecom.py 读 .env 的 WECOM_CORPID/AGENTID/SECRET。ASCII 输出,secret 不打印。 常见 errcode: gettoken: 40013=corpid 错 / 40001|42001=secret 错 / 41002=缺 corpid send: 60011=无权限(应用可见范围没包含该成员)/ 81013=UserID 不存在 40056=agentid 错 / 60020=IP 不在可信IP / 81014=该成员未关注/未激活 """ import os import sys # 仓库根加入 sys.path(脚本在 scripts/ 下,直跑时 core 在上一级) _ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) if _ROOT not in sys.path: sys.path.insert(0, _ROOT) def _load_env(path: str) -> None: """加载 .env:优先 python-dotenv,没装则手动解析(只填未设置的 key)。""" try: from dotenv import load_dotenv load_dotenv(path) return except Exception: pass try: with open(path, encoding="utf-8") as f: for line in f: line = line.strip() if not line or line.startswith("#") or "=" not in line: continue k, v = line.split("=", 1) os.environ.setdefault(k.strip(), v.strip().strip('"').strip("'")) except FileNotFoundError: pass _load_env(os.path.join(_ROOT, ".env")) from core.wechat import wecom def main() -> int: uid = sys.argv[1] if len(sys.argv) > 1 else None print("[cfg] configured:", wecom.wecom_configured()) print("[cfg] corpid:", (os.getenv("WECOM_CORPID", "") or "")[:8] + "...", "| agentid:", os.getenv("WECOM_AGENTID", "")) if not wecom.wecom_configured(): print("[FAIL] WECOM_CORPID/AGENTID/SECRET 没读到(确认 .env 在当前目录、值已填)") return 1 print("[step1] gettoken ...") try: tok = wecom.get_access_token(force=True) print(f"[step1] OK (token len {len(tok)})") except Exception as e: print(f"[step1] FAIL: {e}") print(" → corpid 或 secret 不对(secret 必须是这个自建应用的,不是通讯录密钥)") return 2 if not uid: print("[step2] 跳过(没给 userid 参数);用法: diag_wecom.py ") return 0 print(f"[step2] message/send 到 userid={uid} ...") try: wecom.send_text(uid, "zcbot 企业微信诊断测试消息") print(f"[step2] OK → 去企业微信查收。链路通了!") except Exception as e: print(f"[step2] FAIL: {e}") print(" → 看 errcode:60011=应用可见范围没含该成员 / 81013=userid 写错" "(大小写要和通讯录「账号」完全一致)/ 40056=agentid 错") return 3 return 0 if __name__ == "__main__": sys.exit(main())