How to Configure a Custom HTTP Client for Holehe Programmatically
Replace or inject a custom httpx.AsyncClient into Holehe's maincore() function to control proxies, timeouts, headers, and retry logic.
Holehe is an open-source email reconnaissance tool that performs account lookups across hundreds of websites. By default, it uses a plain httpx.AsyncClient created inside holehe/core.py. If you need to route traffic through proxies, customize TLS settings, or add retry policies, you must configure a custom HTTP client for Holehe programmatically. This guide covers three proven approaches based on the megadose/holehe source code.
Where Holehe Creates Its Default Client
Holehe instantiates its HTTP client in holehe/core.py at lines 13-14:
# holehe/core.py (lines 13-14)
client = httpx.AsyncClient(timeout=timeout) # default client
This happens inside maincore(), which is invoked by the CLI entry point holehe.main(). Because the client is hardcoded at the method level, you cannot pass a pre-configured instance through standard CLI arguments. The following three methods solve this limitation.
Method 1: Monkey-Patch httpx.AsyncClient
The fastest way to inject a custom client without modifying Holehe's source is to replace the httpx.AsyncClient class with a factory that returns your pre-configured instance.
import httpx
import trio
from holehe import core as holehe
# ----- Build your custom client -----
my_client = httpx.AsyncClient(
timeout=30, # extended timeout
headers={"User-Agent": "MyHoleheBot/1.0"}, # custom User-Agent
proxies="http://localhost:8888", # proxy (optional)
transport=httpx.AsyncHTTPTransport(retries=3) # retry logic (optional)
)
# ----- Monkey-patch the constructor -----
original_async_client = httpx.AsyncClient
def async_client_factory(*args, **kwargs):
# Ignore arguments passed by holehe.core.maincore()
return my_client
httpx.AsyncClient = async_client_factory
# ----- Run holehe -----
holehe.main() # uses my_client internally
# ----- Restore original (recommended) -----
httpx.AsyncClient = original_async_client
Key insight: maincore() calls httpx.AsyncClient() with only a timeout argument. By intercepting the constructor, your factory returns a fully configured client regardless of what arguments Holehe passes.
Method 2: Bypass the CLI and Call launch_module Directly
For production integrations where monkey-patching feels fragile, invoke launch_module directly with your own client. This requires replicating the module-loading logic from maincore().
import httpx
import trio
from holehe import core as holehe
from holehe.core import launch_module, get_functions, import_submodules
async def run_holehe(email: str, client: httpx.AsyncClient):
# Replicate CLI initialization (holehe/core.py logic)
modules = import_submodules("holehe.modules")
websites = get_functions(modules)
# Optional: attach progress instrumentation
instrument = holehe.TrioProgress(len(websites))
trio.lowlevel.add_instrument(instrument)
results = []
async with trio.open_nursery() as nursery:
for site in websites:
nursery.start_soon(launch_module, site, email, client, results)
trio.lowlevel.remove_instrument(instrument)
await client.aclose()
return sorted(results, key=lambda x: x["name"])
# ----- Execute with custom client -----
custom_client = httpx.AsyncClient(
timeout=20,
headers={"User-Agent": "MyHoleheBot/2.0"},
proxies={"https": "http://proxy.example:3128"},
)
email = "target@example.com"
results = trio.run(run_holehe, email, custom_client)
print(results)
What this unlocks: Complete control over httpx.AsyncClient parameters including http1/http2, verify (TLS certificates), limits (connection pooling), and event_hooks (request/response middleware).
Method 3: Environment Variables for Quick Tweaks
When you only need proxy routing or timeout adjustments, httpx respects standard environment variables without code changes:
| Variable | Effect |
|---|---|
HTTP_PROXY / HTTPS_PROXY |
Route requests through specified proxy |
NO_PROXY |
Comma-separated list of hosts to bypass |
HTTPX_TIMEOUT |
Override default timeout in seconds |
Shell example:
export HTTPS_PROXY="http://proxy.mycorp:3128"
export HTTPX_TIMEOUT="45"
holehe victim@example.com
Python example:
import os
os.environ["HTTPS_PROXY"] = "http://proxy.mycorp:3128"
os.environ["HTTPX_TIMEOUT"] = "45"
from holehe import core as holehe
holehe.main()
Limitation: Environment variables cannot configure headers, retry logic, or transport-layer options. Use Method 1 or 2 for advanced customization.
Key Source Files to Understand
| File | Purpose | Relevant Content |
|---|---|---|
holehe/core.py |
Entry point and orchestration | maincore(), launch_module(), client instantiation |
holehe/modules/ |
Site-specific check functions | Imported dynamically by import_submodules() |
holehe/instruments.py |
Progress reporting | TrioProgress class for monitoring execution |
holehe/localuseragent.py |
Default User-Agent string | ua variable used when headers aren't overridden |
Performance and Concurrency Considerations
Holehe uses Trio for structured concurrency. When providing a custom client:
- Connection limits: Set
limits=httpx.Limits(max_keepalive_connections=20, max_connections=100)to prevent port exhaustion during large scans - Timeouts: Individual modules may hang; pair
timeout=httpx.Timeout(10.0, connect=5.0)with your retry transport - Client lifecycle: Always
await client.aclose()when bypassingmaincore()(Method 2) to avoid unclosed connection warnings
Summary
- Default behavior: Holehe creates a minimal
httpx.AsyncClientinholehe/core.pywith only timeout configuration - Three customization paths:
- Monkey-patch
httpx.AsyncClientfor quick injection without source edits - Invoke
launch_moduledirectly with a bespoke client for full programmatic control - Environment variables (
HTTP_PROXY,HTTPX_TIMEOUT) for zero-code proxy and timeout adjustments
- Monkey-patch
- Critical files:
holehe/core.pyfor client creation,holehe/core.py::launch_modulefor the execution hook you can override
Frequently Asked Questions
Can I pass a custom client through Holehe's CLI arguments?
No. The holehe.main() CLI entry point does not expose client configuration flags. You must use one of the three programmatic approaches described above: monkey-patching, direct launch_module invocation, or environment variables.
Does Holehe support synchronous HTTP clients?
No. According to the source code in holehe/core.py, Holehe is built on Trio and requires httpx.AsyncClient. The launch_module coroutine explicitly awaits asynchronous HTTP requests. Using requests or httpx.Client would require refactoring the module architecture.
Will environment variables override my monkey-patched client settings?
No. Environment variables affect only newly instantiated clients. If you monkey-patch httpx.AsyncClient to return a pre-built instance, that instance's configuration takes precedence. However, if you rely on HTTPX_TIMEOUT without patching, it influences the default client created in maincore().
Is monkey-patching safe for production use?
Monkey-patching is acceptable for isolated scripts but carries risks: it affects all httpx.AsyncClient instantiations in the process, and must be carefully restored. For production services, prefer Method 2 (direct launch_module invocation) which provides clean separation of concerns and explicit resource management.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →