How to Use Holehe as a Python API: Programmatic Email OSINT Guide
You can use Holehe as a Python API by importing the core functions import_submodules, get_functions, and launch_module from holehe/core.py, then executing the async service checks using trio with an httpx.AsyncClient to verify email existence across platforms without using the CLI.
The megadose/holehe repository provides an open-source email OSINT tool that checks if an address is registered on hundreds of websites. While it ships with a command-line interface, the internal architecture exposes clean Python functions that allow you to integrate email checking directly into your applications, automate workflows, and process results as structured data.
Understanding the Holehe Python API Architecture
Holehe's design separates service-specific logic from the execution engine. Three primary components form the public API surface:
-
holehe.core– Located inholehe/core.py, this module provides the dynamic module loader (import_submodules), function extractor (get_functions), and the async launcher (launch_module). These utilities handle CLI parsing when used as a script, but remain fully accessible for library usage. -
holehe.modules– This package contains individual service check functions. Each file (e.g.,holehe/modules/shopping/amazon.py) defines an async function that receives an email string, anhttpx.AsyncClientinstance, and a mutable list to append results. -
holehe.instruments– TheTrioProgressclass inholehe/instruments.pyprovides optional progress bar integration with thetrioevent loop, though you can omit this for headless API usage.
Because the service modules are pure async functions, you can import and execute them without spawning subprocesses or parsing terminal output.
Importing and Using the Core API Functions
To use Holehe programmatically, import three specific functions from holehe/core.py:
-
import_submodules(package_name)– Dynamically imports all modules underholehe.modulesand returns them as a dictionary mapping module names to module objects. -
get_functions(modules)– Extracts the async check functions from the imported modules. It filters out module metadata and returns a list of callables (e.g., theamazonandgithubfunctions). -
launch_module(func, email, client, results)– A wrapper that safely executes a single service check. It appends a structured result dictionary to theresultslist and handles exceptions internally so that one failed check doesn't crash the entire batch.
All service checks require an httpx.AsyncClient instance for HTTP communication. Each module handles its own rate limiting, HTTP errors, and response normalization, keeping your API integration code minimal.
Complete Code Examples
The following examples demonstrate how to use the Holehe Python API in different async contexts.
Basic Usage with Trio
Since Holehe uses trio for structured concurrency, the simplest integration runs directly in a trio event loop:
import trio
import httpx
from holehe.core import import_submodules, get_functions, launch_module
async def check_email(email: str):
# 1️⃣ Load all service modules dynamically
modules = import_submodules("holehe.modules")
# 2️⃣ Extract the check functions
website_funcs = get_functions(modules)
# 3️⃣ Create async HTTP client with custom timeout
client = httpx.AsyncClient(timeout=10)
# 4️⃣ Initialize results container
results = []
# 5️⃣ Execute all checks concurrently in a trio nursery
async with trio.open_nursery() as nursery:
for func in website_funcs:
nursery.start_soon(launch_module, func, email, client, results)
await client.aclose()
return results
if __name__ == "__main__":
email_to_test = "target@example.com"
all_results = trio.run(check_email, email_to_test)
# Process results: each is a dict with 'domain', 'exists', 'rateLimit', etc.
for r in all_results:
print(f"{r['domain']}: {'Found' if r['exists'] else 'Not found'}")
Key implementation details from the source code:
import_submodules("holehe.modules")walks the package directory and imports every service module automatically.get_functionsfilters the module contents to return only the async check functions defined in files likeholehe/modules/shopping/amazon.py.launch_modulesafely executes the check and guarantees a result dictionary is appended, even if the service request fails.
Integrating with Asyncio Applications
If your application uses asyncio rather than trio, you can bridge the two frameworks using trio.run() inside an async function:
import asyncio
import trio
import httpx
from holehe.core import import_submodules, get_functions, launch_module
async def holehe_asyncio_bridge(email: str):
modules = import_submodules("holehe.modules")
funcs = get_functions(modules)
client = httpx.AsyncClient(timeout=10)
results = []
async def _run_checks():
async with trio.open_nursery() as nursery:
for fn in funcs:
nursery.start_soon(launch_module, fn, email, client, results)
# Delegate to trio's event loop temporarily
await trio.run(_run_checks)
await client.aclose()
return results
async def main():
data = await holehe_asyncio_bridge("user@example.org")
found_services = [r["domain"] for r in data if r.get("exists")]
print(f"Email found on: {', '.join(found_services)}")
asyncio.run(main())
This pattern allows you to maintain an asyncio-based codebase while leveraging Holehe's parallel execution capabilities.
Processing API Results
Each check returns a standardized dictionary appended to your results list. Typical keys include:
domain– The service name (e.g.,amazon,github).exists– Boolean indicating if the email is registered.rateLimit– Boolean indicating if the check was skipped due to rate limiting.error– String description if an exception occurred during the check.
Since launch_module handles exceptions internally in holehe/core.py, you can iterate through results immediately without try-catch blocks for individual services.
Summary
- Import the three core functions from
holehe/core.py:import_submodules,get_functions, andlaunch_module. - Use
triofor structured concurrency, or bridge toasynciousingtrio.run()if necessary. - Provide an
httpx.AsyncClientto manage HTTP connections and timeouts across all service checks. - Call
import_submodules("holehe.modules")to dynamically load all available service checks without hardcoding imports. - Process the results list after the nursery completes; each entry is a dictionary containing
domain,exists, and error information.
Frequently Asked Questions
Can I use Holehe without installing the CLI dependencies?
Yes. If you import from holehe.core and holehe.modules directly, you only need httpx and trio as dependencies. The CLI-specific requirements in holehe/core.py (such as click or trio-console) are only necessary if you invoke the command-line interface.
How do I filter specific services when using the Holehe Python API?
After calling get_functions(modules), you receive a list of function objects. Filter this list by inspecting func.__module__ or func.__name__ before passing them to the nursery. For example, exclude modules containing "shopping" or include only specific domains by checking the function's module path.
Does the Holehe API support synchronous (blocking) usage?
No. All service checks in holehe/modules are implemented as async functions using httpx.AsyncClient. To use Holehe in synchronous code, you must run an async event loop explicitly using trio.run() or asyncio.run() as shown in the examples above.
What is the performance impact of running all checks concurrently?
The launch_module wrapper executes checks in parallel using trio.open_nursery(), which spawns all service checks as concurrent tasks. Performance depends on network latency and the httpx.AsyncClient timeout settings. For large-scale operations, consider implementing semaphores or limiting the nursery concurrency, though this requires modifying the loop structure in your implementation.
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 →