# How to Use Holehe as a Python API: Programmatic Email OSINT Guide

> Use Holehe as a Python API to programmatically check email existence across platforms. Import core functions and run async service checks with trio and httpx for powerful OSINT.

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

---

**You can use Holehe as a Python API by importing the core functions `import_submodules`, `get_functions`, and `launch_module` from [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/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](https://github.com/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 in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/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`](https://github.com/megadose/holehe/blob/main/holehe/modules/shopping/amazon.py)) defines an async function that receives an email string, an `httpx.AsyncClient` instance, and a mutable list to append results.

- **`holehe.instruments`** – The `TrioProgress` class in [`holehe/instruments.py`](https://github.com/megadose/holehe/blob/main/holehe/instruments.py) provides optional progress bar integration with the `trio` event 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`](https://github.com/megadose/holehe/blob/main/holehe/core.py):

1. **`import_submodules(package_name)`** – Dynamically imports all modules under `holehe.modules` and returns them as a dictionary mapping module names to module objects.

2. **`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., the `amazon` and `github` functions).

3. **`launch_module(func, email, client, results)`** – A wrapper that safely executes a single service check. It appends a structured result dictionary to the `results` list 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:

```python
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_functions` filters the module contents to return only the async check functions defined in files like [`holehe/modules/shopping/amazon.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/shopping/amazon.py).
- `launch_module` safely 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:

```python
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`](https://github.com/megadose/holehe/blob/main/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`](https://github.com/megadose/holehe/blob/main/holehe/core.py): `import_submodules`, `get_functions`, and `launch_module`.
- **Use `trio`** for structured concurrency, or bridge to `asyncio` using `trio.run()` if necessary.
- **Provide an `httpx.AsyncClient`** to 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`](https://github.com/megadose/holehe/blob/main/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.