# How to Use Holehe Modules Programmatically in Python

> Integrate Holehe modules directly into your Python projects. Discover how to programmatically check emails using Holehe's async functions and utilities for seamless automation.

- Repository: [Palenath/holehe](https://github.com/megadose/holehe)
- Tags: how-to-guide
- Published: 2026-08-27

---

**Yes, you can import Holehe as a standard Python library and invoke its async email-checking functions directly without using the CLI, leveraging the `import_submodules`, `get_functions`, and `launch_module` utilities exposed in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py).**

Holehe (megadose/holehe) is an open-source email reconnaissance framework that checks whether an address is registered on hundreds of websites. While the tool ships with a command-line interface, it is architected as a modular Python package that supports programmatic integration. This guide demonstrates how to use Holehe modules programmatically in Python to build custom reconnaissance workflows, automation scripts, or embedded security services.

## Core Architecture and Module Structure

The programmatic interface centers on **[`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py)**, which exports three primary utilities for module discovery and execution:

- **`import_submodules(package)`** – Recursively walks the package tree and imports every submodule under `holehe/modules`, returning a dictionary mapping module paths to module objects (line 37).
- **`get_functions(modules, exclude_password_recovery=True)`** – Extracts the public async checking functions from imported modules, optionally filtering out password-recovery routines (line 50).
- **`launch_module(func, email, client, out)`** – Executes a single module’s checking logic with an `httpx.AsyncClient` and accumulates results in a shared list (line 66).

Individual site checks live as separate Python files under **`holehe/modules/`** and implement a strict async signature. For example, the Twitter checker is defined in [`holehe/modules/social_media/twitter.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/social_media/twitter.py) (line 5) with the following interface:

```python
async def twitter(email: str, client: httpx.AsyncClient, out: list) -> None:
    ...

```

## Running a Single Module Check

To execute a specific check programmatically, load the module tree, select your target, and invoke `launch_module` with an HTTPX client:

```python
import asyncio
import httpx
from holehe.core import import_submodules, launch_module

async def check_twitter(email: str):
    # Load all modules and select the Twitter checker

    modules = import_submodules("holehe.modules")
    twitter_func = modules["holehe.modules.social_media.twitter"]
    
    async with httpx.AsyncClient() as client:
        results = []
        await launch_module(twitter_func, email, client, results)
        return results[0]  # Dict containing 'name', 'domain', 'exists', etc.

if __name__ == "__main__":
    result = asyncio.run(check_twitter("example@example.com"))
    print(result)

```

This pattern allows you to target specific platforms without the overhead of loading the full suite.

## Running a Curated Set of Modules

For scenarios requiring multiple specific checks, filter the module dictionary to build a custom execution list:

```python
import asyncio
import httpx
from holehe.core import import_submodules, launch_module

async def run_selected(email: str, module_paths: list[str]):
    modules = import_submodules("holehe.modules")
    selected = [modules[f"holehe.modules.{path}"] for path in module_paths]
    
    async with httpx.AsyncClient() as client:
        out = []
        for func in selected:
            await launch_module(func, email, client, out)
        return out

if __name__ == "__main__":
    checks = ["social_media.twitter", "social_media.instagram"]
    results = asyncio.run(run_selected("example@example.com", checks))
    for r in results:
        print(r)

```

This approach provides granular control over which sites are queried while maintaining sequential execution.

## Parallel Execution with Trio

Holehe natively uses the Trio async library for concurrency. To mirror the CLI’s parallel behavior programmatically, use `trio.open_nursery()` to spawn multiple checks simultaneously:

```python
import trio
import httpx
from holehe.core import import_submodules, get_functions, launch_module

async def full_scan(email: str):
    modules = import_submodules("holehe.modules")
    websites = get_functions(modules)  # All available checks

    client = httpx.AsyncClient(timeout=10)
    out = []
    
    async with trio.open_nursery() as nursery:
        for site in websites:
            nursery.start_soon(launch_module, site, email, client, out)
    
    await client.aclose()
    return out

if __name__ == "__main__":
    results = trio.run(full_scan, "example@example.com")
    for r in results:
        print(r)

```

While `asyncio` works for single-module or sequentially-looped checks, `trio` is required to fully replicate the CLI’s parallel scanning capabilities as implemented in the source.

## Supporting Files and Utilities

Beyond the core orchestration logic, several auxiliary components are relevant for programmatic use:

- **[`holehe/localuseragent.py`](https://github.com/megadose/holehe/blob/main/holehe/localuseragent.py)** – Generates randomized User-Agent strings used by every HTTP request to avoid fingerprinting.
- **[`holehe/__init__.py`](https://github.com/megadose/holehe/blob/main/holehe/__init__.py)** – Exposes the package version via `__version__` for dependency checking in integrated applications.

## Summary

- **Holehe is a standard Python package** that can be imported without CLI invocation using `from holehe.core import import_submodules, get_functions, launch_module`.
- **Module discovery** happens through `import_submodules("holehe.modules")`, which loads all checking logic from the `holehe/modules/` directory.
- **Individual checks** follow a strict async signature accepting `email`, `httpx.AsyncClient`, and a results `list`.
- **Execution modes** range from single-module checks with `asyncio` to high-concurrency parallel scans using `trio` nurseries.
- **Integration points** include the User-Agent generator in [`localuseragent.py`](https://github.com/megadose/holehe/blob/main/localuseragent.py) and version metadata in [`__init__.py`](https://github.com/megadose/holehe/blob/main/__init__.py).

## Frequently Asked Questions

### Can I use Holehe with standard asyncio instead of Trio?

Yes, you can execute Holehe modules using `asyncio.run()` for sequential or basic concurrent execution. However, the library’s native parallel execution relies on Trio’s nursery pattern as shown in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py). For full CLI-equivalent concurrency, Trio is recommended, though asyncio works for single-module or sequentially-looped checks.

### What is the exact function signature for a Holehe module?

Every checking module must implement the following async signature: `async def module_name(email: str, client: httpx.AsyncClient, out: list) -> None`. The function posts the email to the target service, parses the response, and appends a result dictionary to the `out` list. This standardization allows `launch_module` to treat all site checkers as uniform callables.

### How do I exclude password-recovery modules when loading functions?

Pass `exclude_password_recovery=True` (the default) to `get_functions()` in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py). When set to true, the utility filters out modules specifically flagged for password-recovery checks, returning only standard registration-verification functions suitable for email reconnaissance workflows.

### Does Holehe handle rate limiting automatically when used programmatically?

No automatic rate limiting is implemented in the core library. Each module in `holehe/modules/` makes HTTP requests as fast as the event loop schedules them. When using `launch_module` in parallel with Trio, you may overwhelm target services. Implement your own throttling (e.g., `trio.CapacityLimiter` or `asyncio.Semaphore`) if you require rate-limited scanning in production environments.