How to Import and Use Holehe Modules in Custom Python Scripts
You can import and use Holehe modules by leveraging two helper utilities from holehe.core — import_submodules() to dynamically load all service probes, and get_functions() to extract the callable async functions — then run them concurrently with Trio and an httpx.AsyncClient.
Holehe is an OSINT tool for checking email address registrations across hundreds of online services. While it ships with a command-line interface, its modular architecture makes it easy to embed directly into your own Python applications. According to the megadose/holehe source code, each service probe lives under holehe.modules and follows a consistent async signature, enabling programmatic reuse without CLI overhead.
Holehe's Module Architecture
The repository organizes email verification logic into independent modules, each targeting a specific platform (Twitter, Instagram, Amazon, etc.). Understanding this structure is key to importing and using Holehe modules effectively.
Module Location and Signature
All modules reside under the holehe.modules package. Each exposes a single asynchronous function with this signature:
async def <service_name>(email: str, client: httpx.AsyncClient, out: list) -> None
The function receives an email string, an HTTP client instance, and a shared results list. It appends discovery results directly to out rather than returning values.
Core Helper Utilities
In holehe/core.py, two functions handle module discovery and extraction:
| Utility | Purpose | Source Location |
|---|---|---|
import_submodules |
Dynamically imports every submodule under a package path using pkgutil.walk_packages |
holehe/core.py:37-48 |
get_functions |
Converts imported modules into a flat list of callable probe functions; respects --no-password-recovery flags |
holehe/core.py:50-64 |
These utilities separate discovery from execution, making the codebase extensible and testable.
How the CLI Uses These Modules
The maincore function in holehe/core.py demonstrates the standard workflow for importing and using Holehe modules:
- Parse command-line arguments
- Call
import_submodules("holehe.modules")to load all service modules - Call
get_functions(modules, args)to extract probe functions - Create an
httpx.AsyncClientwith user-specified timeout - Launch probes concurrently via Trio's
nursery.start_soon() - Collect results from the shared
outlist
You can replicate this exact pattern in custom scripts, substituting your own logic for steps 1 and 6.
Example 1: Basic Email Check with All Modules
This script mirrors the CLI workflow but gives you direct access to raw results:
import httpx
import trio
from holehe.core import import_submodules, get_functions
async def check_email(email: str):
# 1. Import every module under holehe.modules
modules = import_submodules("holehe.modules")
# 2. Extract probe functions (default behavior, no filtering)
functions = get_functions(modules)
# 3. Create async HTTP client
client = httpx.AsyncClient(timeout=10)
# 4. Prepare results collection list
results = []
# 5. Launch all probes concurrently with Trio
async with trio.open_nursery() as nursery:
for probe in functions:
nursery.start_soon(probe, email, client, results)
await client.aclose()
return results
if __name__ == "__main__":
email = "target@example.com"
data = trio.run(check_email, email)
for entry in data:
print(f"Service: {entry.get('name')}, Exists: {entry.get('exists')}")
Key points: The get_functions() call returns all available probes. Each probe runs independently; failures in one don't affect others due to launch_module's internal try/except wrapping in core.py.
Example 2: Selective Module Usage
For targeted checks, bypass get_functions() and import specific modules directly:
import httpx
import trio
from holehe.core import import_submodules
async def check_twitter_instagram(email: str):
# Import full module tree
modules = import_submodules("holehe.modules")
# Select specific modules by fully-qualified name
target_modules = {
"holehe.modules.social_media.twitter",
"holehe.modules.social_media.instagram"
}
# Extract probe functions manually
selected_funcs = [
modules[name].__dict__[name.split(".")[-1]]
for name in target_modules
if name in modules
]
client = httpx.AsyncClient(timeout=8)
out = []
async with trio.open_nursery() as nursery:
for fn in selected_funcs:
nursery.start_soon(fn, email, client, out)
await client.aclose()
return out
if __name__ == "__main__":
results = trio.run(check_twitter_instagram, "user@domain.com")
print(results)
Key points: Direct module access reduces overhead when you only need specific platforms. The __dict__ lookup uses the final segment of the module path as the function name.
Example 3: Integration with Existing Async Workflows
Embed Holehe checks into larger Trio applications using queues or other communication patterns:
import httpx
import trio
from holehe.core import import_submodules, get_functions
async def holehe_background_task(email: str, result_queue: trio.MemorySendChannel):
"""Run Holehe probes and send results through a Trio channel."""
modules = import_submodules("holehe.modules")
probes = get_functions(modules)
async with httpx.AsyncClient(timeout=12) as client:
results = []
async with trio.open_nursery() as nursery:
for probe in probes:
nursery.start_soon(probe, email, client, results)
# Send completed results to parent task
await result_queue.send(results)
async def main_application():
"""Example of Holehe integrated into a larger program."""
send_channel, receive_channel = trio.open_memory_channel(0)
async with trio.open_nursery() as nursery:
# Start Holehe check in background
nursery.start_soon(
holehe_background_task,
"alice@example.org",
send_channel
)
# Concurrently run other tasks...
# Then collect Holehe results when ready
report = await receive_channel.receive()
print(f"Found {len(report)} services with registrations")
for item in report:
if item.get("exists"):
print(f" - {item['name']}: account exists")
if __name__ == "__main__":
trio.run(main_application)
Key points: The results list behaves like standard Python data — serializable, storable, and transformable. Use Trio channels, asyncio queues, or direct return values depending on your architecture.
Key Source Files for Reference
| File | Role |
|---|---|
holehe/core.py |
Central orchestration: import_submodules(), get_functions(), maincore() |
holehe/modules/__init__.py |
Package marker enabling module discovery |
holehe/modules/social_media/twitter.py |
Example probe showing expected function signature |
holehe/localuseragent.py |
Random User-Agent generator used by probes |
holehe/instruments.py |
Trio progress bar implementation for CLI |
Summary
- Import modules dynamically with
import_submodules("holehe.modules")fromholehe/core.py - Extract probe functions using
get_functions()for automatic discovery, or reference modules directly by their fully-qualified names - Execute probes concurrently via Trio's nursery pattern with a shared
httpx.AsyncClient - Handle results flexibly — the
outlist receives standard dictionaries withname,exists, and other service-specific fields - Reuse any probe individually by importing its module and calling its async function directly
Frequently Asked Questions
Can I use Holehe modules without the Trio concurrency library?
No. According to the megadose/holehe source code, all probe functions are designed for Trio and use trio.open_nursery() for concurrent execution. The probes themselves are standard async def functions, but the execution pattern expects Trio. Using asyncio would require wrapping or rewriting the concurrency logic.
How do I filter out password-recovery probes when importing modules?
Pass a configuration object to get_functions() with the nopasswordrecovery attribute set. The function signature is get_functions(modules, args=None), and when args has nopasswordrecovery=True, it filters out probes that only check password recovery endpoints. Check holehe/core.py:50-64 for the exact implementation.
What data structure does each probe return to the results list?
Each probe appends a dictionary with consistent keys: name (service name), domain (service domain), method (detection method), frequent_rate_limit (boolean), rateLimit (boolean), exists (boolean), and optionally emailrecovery, phoneNumber, or others with leaked account metadata. The exact fields vary by service.
Can I modify the HTTP timeout for individual probes?
No timeouts are set per-probe. Create the httpx.AsyncClient with your desired timeout before launching probes — this single client instance is shared across all concurrent checks. In holehe/core.py, the CLI passes --timeout directly to httpx.AsyncClient(timeout=...).
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 →