Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

21 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

📧 Email Validator

Fast, statically linked email list validator in Rust — CLI pipeline & HTTP API.

Email Validator extracts, deduplicates, and validates email addresses from any text source (TXT, Markdown, XML, CSV, STDIN pipes). Three validation modes: regex only, MX lookup, or full SMTP handshake. Ships as a single static binary with both a CLI pipeline and a built-in HTTP API server.


🚀 Quickstart

# Simplest usage: file in, validated list out
email_validator run -i input.txt -o verified.txt

# Regex-only validation (no network)
email_validator run -i mails.txt -m regex

# GoPhish CSV output format
email_validator run -i mails.txt -o out.csv -f gophish

# JSON output for scripting / automation
email_validator run -i mails.txt -j | jq

# Via pipe (STDIN)
cat mails.txt | email_validator run -f list

🌐 HTTP API Server

The binary includes a built-in HTTP API via the api subcommand:

# Start the server (defaults to 0.0.0.0:8080)
email_validator api

# Custom bind address
email_validator api 127.0.0.1:3000

# Or via environment variable
BIND_ADDR=0.0.0.0:9000 email_validator api

Endpoints

Method Path Description
GET /health Health check — returns {"status":"ok","version":"0.4.2"}
GET /validate?email=…&method=… Validate a single email
POST /validate Batch validate up to 1000 emails

POST /validate Request

{
  "emails": ["alice@example.com", "bogus", "bob@test.de"],
  "method": "regex",
  "disable_wildcard": false
}

Response

{
  "total": 3,
  "valid_count": 2,
  "invalid_count": 1,
  "catch_all_count": 0,
  "results": [
    { "email": "alice@example.com", "valid": true },
    { "email": "bogus", "valid": false },
    { "email": "bob@test.de", "valid": true }
  ]
}
  • Emails are deduplicated case-insensitively before validation
  • Max 1000 emails per request — returns HTTP 400 if exceeded
  • Empty list returns HTTP 400
  • method and disable_wildcard are optional (default: smtp / false)

Examples

# Health check
curl http://localhost:8080/health
# → {"status":"ok","version":"0.4.2"}

# Single email (GET)
curl "http://localhost:8080/validate?email=test@example.com&method=regex"
# → {"total":1,"valid_count":1,"invalid_count":0,"catch_all_count":0,"results":[{"email":"test@example.com","valid":true}]}

# Batch — Regex (no network, instant)
curl -X POST http://localhost:8080/validate \
  -H "Content-Type: application/json" \
  -d '{"emails":["alice@example.com","bogus","bob@test.de"],"method":"regex"}'
# → Syntax-only check, valid JSON emails pass, "bogus" fails

# Batch — MX (DNS lookup)
curl -X POST http://localhost:8080/validate \
  -H "Content-Type: application/json" \
  -d '{"emails":["user@gmail.com","nobody@this-domain-does-not-exist-12345.com"],"method":"mx"}'
# → Checks MX records of each domain

# Batch — SMTP (default, full handshake)
curl -X POST http://localhost:8080/validate \
  -H "Content-Type: application/json" \
  -d '{"emails":["info@example.com","fake@nonexistent.invalid"]}'
# → Full SMTP handshake: HELO → MAIL FROM → RCPT TO → QUIT

# Batch — SMTP with wildcard detection
curl -X POST http://localhost:8080/validate \
  -H "Content-Type: application/json" \
  -d '{"emails":["user@catch-all-domain.com"],"method":"smtp"}'
# → Pre-checks domain for catch-all behavior (catch_all: true in response)

# Error: empty list → 400
curl -X POST http://localhost:8080/validate \
  -H "Content-Type: application/json" \
  -d '{"emails":[]}'
# → {"error":"email list is empty"}

# Error: too many emails → 400
curl -X POST http://localhost:8080/validate \
  -H "Content-Type: application/json" \
  -d '{"emails":["a@b.de","c@d.de", ...]}'
# → {"error":"too many emails, max 1000"} (checked before any processing)

# Error: malformed JSON → 422
curl -X POST http://localhost:8080/validate \
  -H "Content-Type: application/json" \
  -d '{broken'
# → 422 Unprocessable Entity (axum auto-rejects invalid JSON)

🐳 Docker / Wolfi

# Containerfile
FROM cgr.dev/chainguard/wolfi-base:latest
COPY email_validator /usr/local/bin/email_validator
EXPOSE 8080
USER nonroot
ENTRYPOINT ["email_validator", "api"]
# docker-compose.yml
services:
  email-validator:
    image: ghcr.io/evait-security/email_validator:latest
    ports:
      - "8080:8080"          # Host:Container
    restart: unless-stopped
    read_only: true

  # Optional: auto-update container on new releases
  watchtower:
    image: containrrr/watchtower:latest
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock
    command: --interval 300 email-validator
    restart: unless-stopped

The image is built automatically on every release and pushed to ghcr.io/evait-security/email_validator. Add Watchtower to auto-update.


📥 Download (Standalone Binary)

The binary is statically linked (musl) and runs on any Linux x86_64 — Alpine, Wolfi, Arch, Debian, Ubuntu, CentOS, embedded systems. No glibc, no runtime dependencies.

👉 Download latest release

Simply make it executable and go:

chmod +x email_validator
./email_validator run -i emails.txt -o clean.txt

🛠️ CLI Reference

email_validator run — CLI Pipeline

Flag Description Default
-i Input file (optional, STDIN otherwise)
-o Output file (optional, STDOUT otherwise)
-m Validation method: regex, mx, smtp smtp
-f Output format: list, gophish list
-j JSON array output (conflicts with -f) false
-d Disable wildcard domain check false
-v Verbose mode false

email_validator api — HTTP Server

Arg / Env Description Default
[BIND_ADDR] Address to bind (positional or $BIND_ADDR env) 0.0.0.0:8080
-v Verbose STDERR logging false
# All equivalent:
email_validator api
email_validator api 127.0.0.1:3000
BIND_ADDR=127.0.0.1:3000 email_validator api

🔍 Validation Methods

Method Description Network
regex Syntax check via RFC-compliant regex
mx Regex + MX record lookup of domain
smtp Regex + MX + SMTP handshake (RCPT TO)

� Output Formats

Flag Format Includes
-f list (default) One valid email per line Valid only
-f gophish CSV: First Name,Last Name,Email,Position Valid only
-j / --json JSON array All emails (valid + invalid)

JSON Output (-j)

Designed for scripting, automation pipelines, and API consumption. Each email is an object with email, valid, and optionally catch_all (only present when true):

[
  { "email": "alice@example.com", "valid": true },
  { "email": "bob@catch-all.tld", "valid": true, "catch_all": true },
  { "email": "nobody@no-mx-xyz123.de", "valid": false }
]

Use with jq for filtering and transformation:

# Extract only valid emails
email_validator -i mails.txt -j -m smtp | jq '[.[] | select(.valid)]'

# Pipe directly into a webhook or file
email_validator -i mails.txt -j -o result.json

�📋 Supported Input Formats

The regex parser reliably extracts emails from:

  • TXT — prose, lists, CSV exports
  • Markdown — links, code blocks, tables, mailto: links
  • XML — attributes, CDATA sections, text nodes
  • HTML — tags, attributes, plaintext
  • Any mixed content with noise, special characters, and broken entries

Duplicates (including case-insensitive variants) are automatically detected and removed.


🧪 Build from Source

# Clone the repository
git clone https://github.com/USERNAME/email_validator.git
cd email_validator

# Build a static binary (requires musl toolchain)
rustup target add x86_64-unknown-linux-musl
cargo build --release --target x86_64-unknown-linux-musl

# Optional: compress with UPX (~8 MB → ~3 MB)
upx --best --lzma target/x86_64-unknown-linux-musl/release/email_validator

Run tests (53 total, all green ✅):

cargo test

� Architecture

Program Flow

Program Flow

Sequence Diagram

Sequence Diagram

API Sequence

API Sequence

# Regenerate diagrams (requires plantuml)
cd doc && plantuml *.puml

🛠️ Developer Documentation

Module-level docs for all internal types and functions.

Browse Online

👉 Developer Docs — live on GitHub Pages.

Build Locally

cargo doc --no-deps --open

Download

A tarball of the docs is also attached to every release as email_validator_docs.tar.gz.

This opens a local browser with docs for ingestion, precheck, validation, output, and all public types.


�📜 License

This project is licensed under the MIT License.

You may copy, modify, distribute, and use it in your own projects (including commercial software) with proper attribution.


🧬 Tech Stack

  • Rust (Edition 2024)
  • musl — fully static linking
  • UPX — binary compression for minimal download size
  • axum — HTTP API server
  • Property-Based Testing via proptest for fuzzing Markdown/XML/noise inputs
  • CI/CD via GitHub Actions (tests + automatic release)

About

Fast, statically linked email list validator in Rust — CLI pipeline & HTTP API.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Used by

Contributors

Languages