# How to Run Holehe with a List of Emails: 4 Bulk Processing Methods

> Learn how to run Holehe with a list of emails using four powerful bulk processing methods. Master shell loops, xargs, parallel, and Python for efficient email checking.

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

---

**Holehe does not have a built-in `-f` or `-i` flag for batch input; you must call it repeatedly via shell loops, `xargs`, `parallel`, or a Python wrapper that consumes the `holehe.core` library.**

The open-source OSINT tool Holehe is designed to check whether an email address is registered on hundreds of websites. However, as implemented in `megadose/holehe`, the command-line interface only accepts **one email per execution**. This guide explains how to run Holehe with a list of emails using proven bulk processing techniques backed by the source code architecture.

---

## Why Holehe Requires External Bulk Processing

In [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py), the `ArgumentParser` defines a single positional argument for the email address:

```python

# Simplified excerpt from holehe/core.py

parser.add_argument("email", help="Email address to check")
args = parser.parse_args()

# args.email is passed to the async execution engine

```

The core orchestration logic — creating an `httpx.AsyncClient`, dispatching to modules under `holehe/modules/`, and aggregating results — is built around this single-email assumption. Each module (e.g., [`instagram.py`](https://github.com/megadose/holehe/blob/main/instagram.py), [`twitter.py`](https://github.com/megadose/holehe/blob/main/twitter.py)) receives the same client and email, returning a standardized dictionary with fields like `name`, `exists`, and `emailrecovery`.

Because no native batch mode exists, you handle lists externally. Below are four reliable methods.

---

## Method 1: Bash While-Read Loop (Simplest)

The most portable approach reads a file line-by-line and invokes Holehe sequentially.

```bash
while read email; do
    holehe "$email"
done < emails.txt

```

**Pros:** Works on any POSIX shell; easy to debug.

**Cons:** Synchronous execution; large lists are slow.

---

## Method 2: xargs for Streamlined Sequential Processing

`xargs` eliminates the explicit loop and handles argument passing efficiently.

```bash
cat emails.txt | xargs -n1 holehe

```

- `-n1` ensures one email per Holehe invocation
- Automatically handles whitespace and special characters when combined with `-0`

For safer handling of odd characters:

```bash
tr '\n' '\0' < emails.txt | xargs -0 -n1 holehe

```

---

## Method 3: GNU Parallel for Speed

When scanning hundreds or thousands of emails, parallel execution dramatically reduces wall-clock time.

```bash
parallel holehe {} :::: emails.txt

```

- `{}` is the placeholder for each email
- `::::` reads from file (alternative to piping)
- Control concurrency with `-j` (e.g., `-j10` for 10 parallel jobs)

Example with rate limiting and progress bar:

```bash
parallel --bar -j8 holehe {} :::: emails.txt > results.jsonl 2> errors.log

```

---

## Method 4: Python Library Integration

For custom workflows, import `holehe.core` directly instead of shelling out. The internal `run_all_modules` function (located in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py)) executes every available module against a single email.

```python
import asyncio
import httpx
from holehe.core import run_all_modules

async def check_email(email: str):
    """Run all Holehe modules against one email address."""
    async with httpx.AsyncClient() as client:
        results = await run_all_modules(email, client)
    return {"email": email, "services": results}

async def main(emails: list[str]):
    """Process multiple emails concurrently."""
    tasks = [check_email(e) for e in emails]
    return await asyncio.gather(*tasks)

# Example usage

emails = ["alice@example.com", "bob@example.org", "charlie@example.net"]
results = asyncio.run(main(emails))

# Output processing

for r in results:
    print(f"\n{r['email']}:")
    for service in r['services']:
        status = "✓" if service.get('exists') else "✗"
        print(f"  {status} {service['name']}")

```

**Key integration points:**
- `run_all_modules(email, client)` is the core dispatcher found in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py)
- Pass a shared `httpx.AsyncClient` or create fresh clients per email depending on rate-limit needs
- Results are list[dict] with standardized keys: `name`, `domain`, `method`, `frequent_rate_limit`, `rate_limit`, `exists`, `emailrecovery`, `phoneNumber`, `others`

---

## Windows PowerShell Alternative

For Windows environments without WSL, process lists with `ForEach-Object`:

```powershell
Get-Content .\emails.txt | ForEach-Object { holehe $_ }

```

Or with parallel execution using `ForEach-Object -Parallel` (PowerShell 7+):

```powershell
Get-Content .\emails.txt | ForEach-Object -Parallel { holehe $_ } -ThrottleLimit 8

```

---

## Summary

- **No native batch mode:** Holehe's CLI in [`holehe/core.py`](https://github.com/megadose/holehe/blob/main/holehe/core.py) accepts exactly one email argument per run.
- **Shell loops:** Use `while read` for simplicity, `xargs -n1` for cleaner syntax, or `parallel` for performance.
- **Python library:** Import `run_all_modules` from `holehe.core` to build custom async pipelines with full control over concurrency and output formatting.
- **Architecture:** All methods ultimately rely on the same module system under `holehe/modules/`, where each service check receives the email and an `httpx.AsyncClient` via the core dispatcher.

---

## Frequently Asked Questions

### Can Holehe read emails from a CSV or JSON file directly?

No. Holehe has no built-in file parser for structured data. You must extract email addresses first using standard tools: `cut -d',' -f1 accounts.csv` for CSV, or `jq -r '.[].email' data.json` for JSON, then pipe into any method above.

### Does running Holehe in parallel trigger rate limits?

Yes. Many modules in `holehe/modules/` include `frequent_rate_limit` flags in their return dictionaries. When using `parallel` or Python `asyncio.gather`, start with low concurrency (`-j3` or 5 simultaneous tasks) and monitor for `rate_limit: True` responses. The source code shows modules self-report rate-limiting status, but do not automatically throttle.

### Is there a way to get structured JSON output for bulk results?

The CLI outputs formatted text to STDOUT. For machine-readable bulk results, use the Python library approach shown above, or redirect CLI output and parse with `grep`/`jq`:

```bash
parallel holehe {} :::: emails.txt 2>&1 | jq -R --slurp 'split("\n") | map(select(length > 0))'

```

The cleanest solution remains direct Python integration where you control serialization.

### What version of Holehe supports `run_all_modules`?

The `run_all_modules` helper and `httpx`-based async architecture are present in Holehe 1.60+ (current as of the `megadose/holehe` repository). Earlier versions used `requests` and synchronous execution with different internal APIs. Verify your install with `holehe --version`.