# What Is Holehe? A Deep Dive Into the Open-Source OSINT Email Investigation Tool

> Discover Holehe, the open-source OSINT tool that checks over 120 services for an email address. Learn how this Python utility aids in digital investigations and enhances security.

- Repository: [Palenath/holehe](https://github.com/megadose/holehe)
- Tags: deep-dive
- Published: 2026-08-16

---

**Holehe is a Python-based open-source OSINT utility that checks whether an email address is registered on more than 120 online services by querying their password-recovery or registration endpoints.**

Holehe excels at discovering **digital footprints** tied to email addresses without requiring authentication or API keys. Investigators, security researchers, and bug bounty hunters use it to map account associations across social media, software platforms, forums, and payment services. The tool operates entirely through asynchronous HTTP requests, making it fast and scalable for batch operations.

## How Holehe Works Under the Hood

The tool's architecture prioritizes **extensibility**, **speed**, and **stealth**. Rather than scraping profile pages, each service module exploits password-reset flows or registration validation endpoints—techniques that typically don't trigger rate limits or authentication barriers.

### Core Engine in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py)

The central orchestration happens in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py). The `main()` function serves as the CLI entry point, immediately delegating to `trio.run(maincore)` on line 32-34. This establishes the asynchronous runtime before any network activity begins.

The `maincore()` function handles argument parsing through `argparse.ArgumentParser` (lines 80-96), supporting flags like:
- `--only-used` — Filter to registered accounts only
- `--no-color` — Disable ANSI color codes
- `--csv` — Export results to CSV format
- `--timeout` — Configure per-request timeouts

### Dynamic Module Discovery System

Holehe's plugin architecture allows new services to be added without modifying core code. The `import_submodules()` function (lines 37-47) walks the `holehe/modules/*` package tree using `pkgutil`, while `get_functions()` (lines 50-63) filters imported objects into callable "website" functions matching the expected async signature.

```python

# From holehe/core.py - dynamic module loading

modules = import_submodules("holehe.modules")
websites = get_functions(modules)  # Returns list of async service checkers

```

### Concurrent Execution with Trio and HTTPX

Performance comes from **structured concurrency** via the Trio library and `httpx.AsyncClient`. The `launch_module()` function (lines 66-71) spawns each service check in a nursery, enabling parallel execution across dozens of endpoints.

A custom `TrioProgress` instrument (defined in [`holehe/instruments.py`](https://github.com/megadose/holehe/blob/main/holehe/instruments.py)) attaches to the runtime to render a live progress bar, then detaches after completion.

## What Information Holehe Extracts

Each service module returns a standardized dictionary with these fields:
- `name` — Human-readable service identifier
- `domain` — Base domain of the service
- `exists` — Boolean indicating account registration
- `emailrecovery` — Partially obfuscated recovery email (if exposed)
- `phoneNumber` — Masked recovery phone (if exposed)
- `others` — Additional metadata per service

The `print_result()` function (lines 22-49) aggregates these into color-coded terminal output, with `export_csv()` (lines 54-64) handling structured data export when requested.

## Practical Usage Examples

### Command-Line Scanning

```bash

# Basic scan against all supported services

holehe target@example.com

# Show only confirmed registrations

holehe target@example.com --only-used

# Export to CSV for further analysis

holehe target@example.com --csv results.csv

# Disable colors for piping to other tools

holehe target@example.com --no-color

```

### Single Service Module (Programmatic)

```python
import trio
import httpx
from holehe.modules.social_media.instagram import instagram

async def check_instagram():
    email = "target@example.com"
    out = []
    
    async with httpx.AsyncClient() as client:
        await instagram(email, client, out)
    
    # out contains: [{'name': 'instagram', 'domain': 'instagram.com', 

    #                 'exists': True/False, 'emailrecovery': 't***@gmail.com', ...}]

    return out

result = trio.run(check_instagram)

```

### Bulk Custom Scanning

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

async def comprehensive_scan(email: str):
    """Scan all discovered modules concurrently."""
    modules = import_submodules("holehe.modules")
    websites = get_functions(modules)
    
    client = httpx.AsyncClient()
    results = []
    
    async with trio.open_nursery() as nursery:
        for site_func in websites:
            nursery.start_soon(launch_module, site_func, email, client, results)
    
    await client.aclose()
    return [r for r in results if r.get("exists")]  # Filter to hits only

# Execute

matches = trio.run(lambda: comprehensive_scan("target@example.com"))
print(f"Found {len(matches)} registered accounts")

```

## Anti-Detection Measures

Holehe implements several evasion techniques:

| Mechanism | Implementation | Source |
|-----------|---------------|--------|
| **Rotating User-Agents** | Randomized browser strings from [`holehe/localuseragent.py`](https://github.com/megadose/holehe/blob/main/holehe/localuseragent.py) | [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) lines 21-22 |
| **Async I/O** | Non-blocking requests prevent sequential timing patterns | Trio + HTTPX throughout |
| **Timeout Configuration** | Per-request limits avoid hanging on slow endpoints | `--timeout` flag |

The [`localuseragent.py`](https://github.com/megadose/holehe/blob/main/localuseragent.py) module generates plausible browser fingerprints, while the asynchronous design distributes traffic patterns across time windows rather than burst sequences.

## Extending Holehe with New Services

Creating a new module requires only three elements:

1. A Python file in the appropriate `holehe/modules/` subdirectory
2. An async function following the signature: `async def servicename(email, client, out)`
3. Appending a result dictionary to the `out` list

Example module structure from [`holehe/modules/software/adobe.py`](https://github.com/megadose/holehe/blob/main/holehe/modules/software/adobe.py):

```python
import httpx

async def adobe(email: str, client: httpx.AsyncClient, out: list):
    try:
        # Service-specific password-recovery request

        response = await client.post(
            "https://auth.services.adobe.com/signin/v2",
            data={"username": email}
        )
        
        # Parse response for account indicators

        exists = "password" in response.text  # Simplified logic

        
        out.append({
            "name": "adobe",
            "domain": "adobe.com",
            "exists": exists,
            "emailrecovery": None,
            "phoneNumber": None,
            "others": {}
        })
    except Exception:
        out.append({
            "name": "adobe",
            "domain": "adobe.com",
            "exists": None,  # Error state

            "emailrecovery": None,
            "phoneNumber": None,
            "others": {}
        })

```

## Self-Update Mechanism

The `check_update()` function (lines 65-85 in an earlier version, consolidated in current releases) queries the PyPI JSON API for version comparison. When outdated, it executes `pip install --upgrade holehe` automatically—ensuring investigators access the latest service modules without manual intervention.

## Summary

- **Holehe** is an async Python OSINT tool that maps email addresses to accounts across 120+ services via password-recovery endpoint analysis
- Core architecture in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) uses **Trio** for structured concurrency and **HTTPX** for HTTP/2-capable async requests
- **Dynamic module loading** via `pkgutil` enables plugin-style service additions without core modifications
- Standardized output format supports both human-readable terminal display and **CSV export** for pipeline integration
- Built-in **stealth features** include rotating User-Agents and configurable timeouts
- GPL-3.0 licensed for educational and authorized security research use

## Frequently Asked Questions

### How does Holehe differ from commercial OSINT email tools?

Holehe operates without API keys, rate-limited subscriptions, or authenticated access. It exploits publicly accessible password-recovery flows that return account-existence indicators—making it free and unrestricted, though potentially more fragile to endpoint changes than paid services with official APIs.

### Can Holehe access private account information or passwords?

No. Holehe only determines **whether** an account exists and may recover **partially masked** recovery contacts (like `t***@gmail.com`). It cannot retrieve passwords, private messages, or profile content. The tool respects rate limits and is designed for passive reconnaissance.

### Why does Holehe use Trio instead of asyncio?

Trio provides **structured concurrency** guarantees that prevent common async bugs like orphaned tasks or uncaught exceptions. The `trio.open_nursery()` pattern ensures all service checks complete or fail cleanly, while the instrument system enables the progress bar without callback complexity.

### How do I add support for a new website to Holehe?

Create a Python file in the appropriate `holehe/modules/` category folder with an async function accepting `(email, client, out)` parameters. The function should append a result dictionary to `out` and handle its own exception catching. No registration with core code is required—discovery happens automatically at runtime.