Understanding the Email Validation Regex Pattern Used by Holehe

Holehe uses a lightweight regex pattern in holehe/core.py to validate email syntax before probing any services, accepting common valid formats while rejecting obviously malformed addresses.

The open-source OSINT tool Holehe verifies whether an email address is registered on various websites. Before making any network requests, it validates the email format using a compiled regular expression. This article breaks down the exact pattern, explains its components, and shows how to use it in your own code.

Where the Email Validation Lives

According to the megadose/holehe source code, the email validation logic resides in [holehe/core.py](https://github.com/megadose/holehe/blob/master/holehe/core.py). The implementation consists of two parts: a compiled regex constant and a helper function.

The Regex Definition (Lines 12-14)

import re

# Regular expression for validating a email 

EMAIL_REGEX = re.compile(
    r'^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$')

View source: holehe/core.py#L12-L14

The Validation Helper (Lines 15-17)

def is_valid_email(email):
    return bool(EMAIL_REGEX.fullmatch(email))

View source: holehe/core.py#L15-L17

Breaking Down the Regex Pattern

The Holehe email validation regex follows a practical rather than RFC-compliant approach. Here's how each component works:

Segment Pattern Purpose
Start anchor ^ Ensures match begins at string start
Local part [a-zA-Z0-9_.+-]+ Username before @; allows letters, digits, underscores, dots, plus signs, and hyphens
Separator @ Literal at-sign
Domain name [a-zA-Z0-9-]+ Domain labels; allows letters, digits, and hyphens
Dot separator \. Literal period before TLD
TLD/subdomains [a-zA-Z0-9-.]+ Top-level domain and optional subdomains; allows multiple dots for domains like co.uk
End anchor $ Ensures match reaches string end

What This Pattern Accepts and Rejects

Accepted formats:

  • user@example.com
  • first.last@sub.domain.co.uk
  • user+tag@domain.org
  • user-name@domain-name.com

Rejected formats:

  • user@domain (missing TLD)
  • user name@domain.com (space in local part)
  • user@domain..com (consecutive dots pass but fail in practice)
  • @domain.com (empty local part)
  • user@.com (empty domain label)

Using the Validation in Your Code

Direct Import and Usage

from holehe.core import is_valid_email

# Valid emails

print(is_valid_email("alice@example.com"))        # True

print(is_valid_email("bob.smith+tag@sub.co.uk"))  # True

# Invalid emails

print(is_valid_email("charlie@invalid"))          # False (no TLD)

print(is_valid_email("dave @domain.com"))         # False (space)

print(is_valid_email("eve@domain..com"))          # True (regex accepts, but malformed)

Replicating the Pattern Manually

import re

# Same pattern as defined in holehe/core.py

EMAIL_REGEX = re.compile(
    r'^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$')

def custom_validate(email):
    """Returns match object or None; use bool() for True/False"""
    return EMAIL_REGEX.fullmatch(email)

test_emails = [
    "valid@example.com",
    "also-valid+tag@sub.domain.org",
    "invalid@domain",
    "no-at-sign.com",
    "spaces not@allowed.com"
]

for email in test_emails:
    match = custom_validate(email)
    status = "valid" if match else "invalid"
    print(f"{email:<25} → {status}")

How Holehe Uses Email Validation

The validation runs immediately when processing command-line arguments. Here's the typical flow:


# Simplified representation of Holehe's internal flow

async def main(email, **options):
    # Step 1: Validate format before any network activity

    if not is_valid_email(email):
        print("Error: Invalid email format")
        return
    
    # Step 2: Proceed with service-specific checks only if valid

    results = await run_modules(email, options)
    return results

This early-exit pattern prevents wasting API calls and rate limits on malformed inputs.

Limitations and Design Rationale

The Holehe email validation regex is intentionally permissive. It prioritizes:

  • Speed: Simple regex evaluation is faster than full RFC 5322 parsing
  • Practical coverage: Catches obvious typos while accepting most real-world addresses
  • Tool scope: Holehe probes registration status, not mailbox deliverability

For production systems requiring strict validation, consider supplementing with:

  • DNS MX record verification (confirm domain accepts mail)
  • SMTP handshake testing (verify mailbox exists)
  • RFC 5322-compliant libraries like email-validator for Python

Summary

  • The Holehe email validation regex is defined in holehe/core.py at lines 12-14 as EMAIL_REGEX
  • The is_valid_email() function at lines 15-17 wraps fullmatch() for boolean returns
  • The pattern accepts letters, digits, and limited special characters in local and domain parts
  • This validation runs before any network requests to filter malformed inputs efficiently

Frequently Asked Questions

What characters are allowed in the local part of an email according to Holehe's regex?

Holehe allows letters (a-z, A-Z), digits (0-9), underscores, dots, plus signs, and hyphens in the local part (before the @). The pattern [a-zA-Z0-9_.+-]+ requires at least one such character.

Does Holehe's regex validate that an email actually exists?

No. The regex only checks syntactic format. It cannot verify DNS records, SMTP connectivity, or whether a mailbox is active. Holehe uses this lightweight check to reject obvious garbage before making HTTP requests to various services.

Why doesn't Holehe use a more complex RFC 5322-compliant regex?

RFC 5322 permits quoted strings, comments, and other edge cases rarely seen in practice. Holehe's maintainer chose a simpler pattern that covers 99%+ of real-world addresses while remaining readable and fast. Complex regexes for email validation often become unmaintainable and still fail on edge cases.

Can I use is_valid_email() in my own Python projects?

Yes. Import it directly from the module: from holehe.core import is_valid_email. Note that Holehe is released under the GNU General Public License v3.0, so derivative works must comply with GPL terms if you distribute modified versions.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →