philiprehberger-email_validator
RFC-compliant email validation with MX record verification, disposable domain detection, normalization, and typo suggestions
Requirements
- Ruby >= 3.1
Installation
Add to your Gemfile:
gem "philiprehberger-email_validator"
Or install directly:
gem install philiprehberger-email_validator
Usage
require "philiprehberger/email_validator"
Philiprehberger::EmailValidator.valid?("[email protected]")
# => true
Philiprehberger::EmailValidator.valid?("not-an-email")
# => false
Full Validation
result = Philiprehberger::EmailValidator.validate("[email protected]")
result.valid? # => true
result.errors # => []
result.warnings # => []
result = Philiprehberger::EmailValidator.validate("[email protected]")
result.valid? # => true
result.warnings # => ["address appears to be role-based"]
MX Record Verification
result = Philiprehberger::EmailValidator.validate("[email protected]", check_mx: true)
result.valid? # => true (if domain has MX/A records)
Philiprehberger::EmailValidator.mx_valid?("example.com")
# => true
Disposable Domain Detection
Philiprehberger::EmailValidator.disposable?("[email protected]")
# => true
result = Philiprehberger::EmailValidator.validate("[email protected]", allow_disposable: false)
result.valid? # => false
result.errors # => ["disposable email domains are not allowed"]
Role-Based Address Detection
Philiprehberger::EmailValidator.role_based?("[email protected]")
# => true
Philiprehberger::EmailValidator.role_based?("[email protected]")
# => false
Bulk Validation
emails = ["[email protected]", "invalid", "[email protected]"]
results = Philiprehberger::EmailValidator.validate_all(emails, allow_disposable: false)
results[0].valid? # => true
results[1].valid? # => false
Philiprehberger::EmailValidator.valid_all?(["[email protected]", "[email protected]"])
# => true
Batch Validation (Hash)
emails = ["[email protected]", "invalid", "[email protected]"]
results = Philiprehberger::EmailValidator.batch_validate(emails)
results["[email protected]"].valid? # => true
results["invalid"].valid? # => false
results["[email protected]"].valid? # => true
Custom Disposable Domain List
Philiprehberger::EmailValidator.configure do |config|
config.add_disposable_domains(["custom-temp.com", "temp.org"])
config.remove_disposable_domains(["mailinator.com"])
end
Philiprehberger::EmailValidator.disposable?("[email protected]")
# => true
Philiprehberger::EmailValidator.reset_configuration!
Email Normalization
Philiprehberger::EmailValidator.normalize("[email protected]")
# => "[email protected]"
Philiprehberger::EmailValidator.normalize(" [email protected] ")
# => "[email protected]"
Sub-address Tags
Philiprehberger::EmailValidator.extract_tag("[email protected]")
# => "promo"
Philiprehberger::EmailValidator.extract_tag("[email protected]")
# => nil
Philiprehberger::EmailValidator.strip_tag("[email protected]")
# => "[email protected]"
Philiprehberger::EmailValidator.strip_tag("[email protected]")
# => "[email protected]"
Splitting an Address
Get the local, domain, and tag in one call:
Philiprehberger::EmailValidator.split("[email protected]")
# => { local: "user", domain: "example.com", tag: "work" }
Philiprehberger::EmailValidator.split("[email protected]")
# => { local: "user", domain: "example.com", tag: nil }
Philiprehberger::EmailValidator.split("not-an-email")
# => nil
Canonical Equality
require "philiprehberger/email_validator"
Philiprehberger::EmailValidator.canonical_equal?("[email protected]", "[email protected]")
# => true
Philiprehberger::EmailValidator.canonical_equal?("[email protected]", "[email protected]")
# => false
Philiprehberger::EmailValidator.canonical_equal?(nil, "[email protected]")
# => false
Typo Suggestion
Philiprehberger::EmailValidator.suggest("[email protected]")
# => { original: "[email protected]", suggested: "[email protected]" }
Philiprehberger::EmailValidator.suggest("[email protected]")
# => nil
Domain Info
Philiprehberger::EmailValidator.domain_info("[email protected]")
# => { domain: "mail.example.co.uk", tld: "uk" }
Philiprehberger::EmailValidator.domain_info("[email protected]", check_mx: true)
# => { domain: "example.com", tld: "com", mx_records: ["mail.example.com"] }
API
| Method | Description | ||
|---|---|---|---|
EmailValidator.valid?(email) |
Quick syntax check, returns boolean | ||
EmailValidator.validate(email, check_mx: false, allow_disposable: true) |
Full validation returning Result | ||
EmailValidator.validate_all(emails, **opts) |
Bulk validation returning array of Results | ||
EmailValidator.batch_validate(emails, **opts) |
Bulk validation returning hash of { email => Result } |
||
EmailValidator.valid_all?(emails) |
Returns true only if all emails are valid | ||
EmailValidator.mx_valid?(domain) |
Check if domain has MX or A records | ||
EmailValidator.disposable?(email) |
Check if email uses a disposable domain | ||
EmailValidator.role_based?(email) |
Detect role-based addresses (info@, admin@, etc.) | ||
| `EmailValidator.configure { \ | config\ | ... }` | Configure custom disposable domain list |
EmailValidator.reset_configuration! |
Reset configuration to defaults | ||
EmailValidator.normalize(email) |
Normalize email (lowercase, remove aliases, Gmail dots) | ||
EmailValidator.canonical_equal?(a, b) |
Compare two emails after normalization; false on invalid input | ||
EmailValidator.same_domain?(a, b) |
Return true when both addresses share the same domain (case-insensitive); false for invalid input | ||
EmailValidator.extract_tag(email) |
Extract the sub-address tag after + in the local part; nil if none or invalid |
||
EmailValidator.strip_tag(email) |
Remove any +tag from the local part; returns the original value on invalid input |
||
EmailValidator.split(email) |
Return { local:, domain:, tag: }; nil for invalid input |
||
EmailValidator.suggest(email) |
Suggest corrected domain for typos | ||
EmailValidator.domain_info(email, check_mx: false) |
Extract domain metadata |
Result
| Method | Description |
|---|---|
#valid? |
True if no validation errors |
#errors |
Array of error message strings |
#warnings |
Array of warning message strings |
Development
bundle install
bundle exec rspec
bundle exec rubocop
Support
If you find this project useful: