email_domain_checker 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +19 -0
- data/README.md +69 -0
- data/lib/email_domain_checker/active_model_validator.rb +107 -0
- data/lib/email_domain_checker/config.rb +31 -3
- data/lib/email_domain_checker/domain_validator.rb +4 -0
- data/lib/email_domain_checker/version.rb +1 -2
- data/lib/email_domain_checker.rb +13 -2
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 9482f21ae74333979292271bf830aa22164a859388ba73b29a090118185ac797
|
|
4
|
+
data.tar.gz: 12fa14a045d73af82ff4d179c55d9f7c425ec25a1bc171d3328e60f5045f92de
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ab00a7b94993e50f3e5e8c4b7d7fa74c270a77778c4bd7c5796f84420fe1ffb0c929ec3efa4999d573ba38325e431cca20359e55dcfe68d4b73f67367f57a92d
|
|
7
|
+
data.tar.gz: 7a1f651e88f540389f8d213e381a37047c96370d3ff2bb1b4bd8a3655045ac9bb9cf749695ca8c774d2cca38050028e11468f181c883ff6b391abaf57f1d544a
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,25 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.1.2] - 2025-11-05
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- Test mode feature to skip DNS checks during testing with block syntax support for configuration ([#4](https://github.com/tatematsu-k/email_domain_checker/pull/4))
|
|
12
|
+
|
|
13
|
+
## [0.1.1] - 2025-11-04
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
- ActiveModel/ActiveRecord validator integration (`DomainCheckValidator`) ([#3](https://github.com/tatematsu-k/email_domain_checker/pull/3))
|
|
17
|
+
- Automatic email normalization option in validator ([#3](https://github.com/tatematsu-k/email_domain_checker/pull/3))
|
|
18
|
+
- Ruby 3.4+ compatibility support for ActiveModel integration ([#3](https://github.com/tatematsu-k/email_domain_checker/pull/3))
|
|
19
|
+
- Comprehensive test coverage for ActiveModel validator ([#3](https://github.com/tatematsu-k/email_domain_checker/pull/3))
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
- CI: Added ActiveRecord version matrix testing for better compatibility testing ([#3](https://github.com/tatematsu-k/email_domain_checker/pull/3))
|
|
23
|
+
|
|
24
|
+
### Documentation
|
|
25
|
+
- Added ActiveModel integration documentation with usage examples ([#3](https://github.com/tatematsu-k/email_domain_checker/pull/3))
|
|
26
|
+
|
|
8
27
|
## [0.1.0] - 2025-11-4
|
|
9
28
|
|
|
10
29
|
### Added
|
data/README.md
CHANGED
|
@@ -39,6 +39,11 @@ EmailDomainChecker.normalize("User@Example.COM") # => "user@example.com"
|
|
|
39
39
|
|
|
40
40
|
# Configure default options globally
|
|
41
41
|
EmailDomainChecker.configure(timeout: 10, check_mx: true)
|
|
42
|
+
|
|
43
|
+
# Enable test mode (skips DNS checks)
|
|
44
|
+
EmailDomainChecker.configure do |config|
|
|
45
|
+
config.test_mode = true
|
|
46
|
+
end
|
|
42
47
|
```
|
|
43
48
|
|
|
44
49
|
### Using Checker class
|
|
@@ -73,6 +78,51 @@ checker = EmailDomainChecker::Checker.new("user@example.com")
|
|
|
73
78
|
checker.redacted_email # => "{hash}@example.com"
|
|
74
79
|
```
|
|
75
80
|
|
|
81
|
+
### ActiveModel/ActiveRecord Integration
|
|
82
|
+
|
|
83
|
+
When ActiveModel is available, you can use the `DomainCheckValidator` for easy validation and normalization in your models:
|
|
84
|
+
|
|
85
|
+
```ruby
|
|
86
|
+
class User < ActiveRecord::Base
|
|
87
|
+
validates :email, domain_check: { check_mx: true, timeout: 3 }, normalize: true
|
|
88
|
+
end
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
#### Options
|
|
92
|
+
|
|
93
|
+
- `domain_check`: Hash of options for domain validation
|
|
94
|
+
- `check_mx`: Check MX records (default: `true`)
|
|
95
|
+
- `check_a`: Check A records (default: `false`)
|
|
96
|
+
- `timeout`: DNS query timeout in seconds (default: `5`)
|
|
97
|
+
- `validate_format`: Validate email format (default: `true`)
|
|
98
|
+
- `validate_domain`: Validate domain (default: `true`)
|
|
99
|
+
- `normalize`: Normalize email before validation (default: `false`)
|
|
100
|
+
- `message`: Custom error message
|
|
101
|
+
|
|
102
|
+
#### Examples
|
|
103
|
+
|
|
104
|
+
```ruby
|
|
105
|
+
# Basic validation with domain check
|
|
106
|
+
class User < ActiveRecord::Base
|
|
107
|
+
validates :email, domain_check: { check_mx: true, timeout: 3 }
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# Format validation only (skip domain check)
|
|
111
|
+
class User < ActiveRecord::Base
|
|
112
|
+
validates :email, domain_check: { validate_domain: false }
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
# With automatic normalization
|
|
116
|
+
class User < ActiveRecord::Base
|
|
117
|
+
validates :email, domain_check: { check_mx: true }, normalize: true
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# With custom error message
|
|
121
|
+
class User < ActiveRecord::Base
|
|
122
|
+
validates :email, domain_check: { check_mx: true }, message: "Invalid email address"
|
|
123
|
+
end
|
|
124
|
+
```
|
|
125
|
+
|
|
76
126
|
### Configuration Options
|
|
77
127
|
|
|
78
128
|
- `validate_format`: Validate email format using email_address gem (default: true)
|
|
@@ -80,6 +130,25 @@ checker.redacted_email # => "{hash}@example.com"
|
|
|
80
130
|
- `check_mx`: Check MX records for domain (default: true)
|
|
81
131
|
- `check_a`: Check A records for domain (default: false)
|
|
82
132
|
- `timeout`: DNS lookup timeout in seconds (default: 5)
|
|
133
|
+
- `test_mode`: Skip DNS checks (useful for testing with dummy data) (default: false)
|
|
134
|
+
|
|
135
|
+
### Test Mode
|
|
136
|
+
|
|
137
|
+
When writing tests, you may want to skip DNS checks to avoid external requests. Enable test mode to skip all DNS validations (MX and A record checks):
|
|
138
|
+
|
|
139
|
+
```ruby
|
|
140
|
+
# In spec_helper.rb or test_helper.rb
|
|
141
|
+
EmailDomainChecker.configure do |config|
|
|
142
|
+
config.test_mode = true
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
# Or in a before block
|
|
146
|
+
before do
|
|
147
|
+
EmailDomainChecker::Config.test_mode = true
|
|
148
|
+
end
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
When test mode is enabled, domain validation will always return `true` without making any DNS requests, allowing you to use dummy email addresses in your tests without external dependencies.
|
|
83
152
|
|
|
84
153
|
## Development
|
|
85
154
|
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_model"
|
|
4
|
+
|
|
5
|
+
require_relative "checker"
|
|
6
|
+
require_relative "normalizer"
|
|
7
|
+
|
|
8
|
+
module EmailDomainChecker
|
|
9
|
+
# ActiveModel validator for email domain checking
|
|
10
|
+
#
|
|
11
|
+
# Usage:
|
|
12
|
+
# class User < ActiveRecord::Base
|
|
13
|
+
# validates :email, domain_check: { check_mx: true, timeout: 3 }, normalize: true
|
|
14
|
+
# end
|
|
15
|
+
#
|
|
16
|
+
# Options:
|
|
17
|
+
# - domain_check: Hash of options for domain validation
|
|
18
|
+
# * check_mx: Boolean (default: true) - Check MX records
|
|
19
|
+
# * check_a: Boolean (default: false) - Check A records
|
|
20
|
+
# * timeout: Integer (default: 5) - DNS query timeout in seconds
|
|
21
|
+
# * validate_format: Boolean (default: true) - Validate email format
|
|
22
|
+
# * validate_domain: Boolean (default: true) - Validate domain
|
|
23
|
+
# - normalize: Boolean (default: false) - Normalize email before validation
|
|
24
|
+
# - message: String or Symbol - Custom error message
|
|
25
|
+
class DomainCheckValidator < ActiveModel::EachValidator
|
|
26
|
+
def validate_each(record, attribute, value)
|
|
27
|
+
return if value.blank?
|
|
28
|
+
|
|
29
|
+
# ActiveModel passes domain_check hash contents directly to options
|
|
30
|
+
# when using validates :email, domain_check: { normalize: false }
|
|
31
|
+
# So options will be { validate_domain: false, normalize: false } etc.
|
|
32
|
+
normalize_option = options[:normalize] == true
|
|
33
|
+
|
|
34
|
+
original_value = value.is_a?(String) ? value : value.to_s
|
|
35
|
+
normalized_value = normalize_option ? Normalizer.normalize(original_value) : original_value
|
|
36
|
+
|
|
37
|
+
if normalize_option && normalized_value != original_value
|
|
38
|
+
record.public_send("#{attribute}=", normalized_value)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
validation_options = build_validation_options(record, attribute)
|
|
42
|
+
value_for_checker = normalize_option ? normalized_value : original_value
|
|
43
|
+
checker = Checker.new(value_for_checker, validation_options)
|
|
44
|
+
|
|
45
|
+
unless checker.valid?
|
|
46
|
+
error_message = error_message_for(record, attribute, checker)
|
|
47
|
+
record.errors.add(attribute, error_message[:key], message: error_message[:message])
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
private
|
|
52
|
+
|
|
53
|
+
def build_validation_options(record, attribute)
|
|
54
|
+
default_options = {
|
|
55
|
+
validate_format: true,
|
|
56
|
+
validate_domain: true,
|
|
57
|
+
check_mx: true,
|
|
58
|
+
check_a: false,
|
|
59
|
+
timeout: 5
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
# ActiveModel passes domain_check hash contents directly to options
|
|
63
|
+
# Exclude normalize and message from validation options
|
|
64
|
+
domain_check_options = options.reject { |k, _v| k == :normalize || k == :message }
|
|
65
|
+
default_options.merge(domain_check_options)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def error_message_for(record, attribute, checker)
|
|
69
|
+
message_option = options[:message]
|
|
70
|
+
if message_option
|
|
71
|
+
return {
|
|
72
|
+
key: :invalid,
|
|
73
|
+
message: message_option.is_a?(Symbol) ? record.errors.generate_message(attribute, message_option) : message_option
|
|
74
|
+
}
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
unless checker.format_valid?
|
|
78
|
+
return {
|
|
79
|
+
key: :invalid_format,
|
|
80
|
+
message: i18n_message("errors.messages.invalid_email_format", "is not a valid email format")
|
|
81
|
+
}
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
unless checker.domain_valid?
|
|
85
|
+
return {
|
|
86
|
+
key: :invalid_domain,
|
|
87
|
+
message: i18n_message("errors.messages.invalid_email_domain", "has an invalid domain")
|
|
88
|
+
}
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
{
|
|
92
|
+
key: :invalid,
|
|
93
|
+
message: i18n_message("errors.messages.invalid_email", "is not a valid email address")
|
|
94
|
+
}
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def i18n_message(key, default)
|
|
98
|
+
return default unless defined?(I18n)
|
|
99
|
+
|
|
100
|
+
I18n.t(key, default: default)
|
|
101
|
+
rescue StandardError
|
|
102
|
+
default
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
DomainCheckValidator = EmailDomainChecker::DomainCheckValidator unless defined?(DomainCheckValidator)
|
|
@@ -11,15 +11,43 @@ module EmailDomainChecker
|
|
|
11
11
|
}.freeze
|
|
12
12
|
|
|
13
13
|
class << self
|
|
14
|
-
attr_accessor :default_options
|
|
14
|
+
attr_accessor :default_options, :test_mode
|
|
15
15
|
|
|
16
|
-
def configure(options = {})
|
|
17
|
-
|
|
16
|
+
def configure(options = {}, &block)
|
|
17
|
+
if block_given?
|
|
18
|
+
config_instance = new
|
|
19
|
+
block.call(config_instance)
|
|
20
|
+
@default_options = DEFAULT_OPTIONS.merge(options)
|
|
21
|
+
config_instance
|
|
22
|
+
else
|
|
23
|
+
@default_options = DEFAULT_OPTIONS.merge(options)
|
|
24
|
+
new
|
|
25
|
+
end
|
|
18
26
|
end
|
|
19
27
|
|
|
20
28
|
def reset
|
|
21
29
|
@default_options = DEFAULT_OPTIONS.dup
|
|
30
|
+
@test_mode = false
|
|
22
31
|
end
|
|
32
|
+
|
|
33
|
+
def test_mode=(value)
|
|
34
|
+
@test_mode = value
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def test_mode?
|
|
38
|
+
@test_mode == true
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
attr_accessor :test_mode
|
|
43
|
+
|
|
44
|
+
def initialize
|
|
45
|
+
@test_mode = self.class.test_mode || false
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def test_mode=(value)
|
|
49
|
+
@test_mode = value
|
|
50
|
+
self.class.test_mode = value
|
|
23
51
|
end
|
|
24
52
|
|
|
25
53
|
reset
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require_relative "dns_resolver"
|
|
4
|
+
require_relative "config"
|
|
4
5
|
|
|
5
6
|
module EmailDomainChecker
|
|
6
7
|
class DomainValidator
|
|
@@ -18,6 +19,9 @@ module EmailDomainChecker
|
|
|
18
19
|
def valid?(domain)
|
|
19
20
|
return false if domain.nil? || domain.empty?
|
|
20
21
|
|
|
22
|
+
# Skip DNS checks if test mode is enabled
|
|
23
|
+
return true if Config.test_mode?
|
|
24
|
+
|
|
21
25
|
check_domain_records(domain)
|
|
22
26
|
end
|
|
23
27
|
|
data/lib/email_domain_checker.rb
CHANGED
|
@@ -8,6 +8,17 @@ require_relative "email_domain_checker/domain_validator"
|
|
|
8
8
|
require_relative "email_domain_checker/email_address_adapter"
|
|
9
9
|
require_relative "email_domain_checker/checker"
|
|
10
10
|
|
|
11
|
+
# Conditionally load ActiveModel integration if ActiveModel is available
|
|
12
|
+
begin
|
|
13
|
+
# Require logger gem for older Rails/ActiveModel versions on Ruby 3.4+
|
|
14
|
+
# This is needed because logger was removed from Ruby standard library in 3.4+
|
|
15
|
+
require "logger" if RUBY_VERSION >= "3.4"
|
|
16
|
+
require "active_model"
|
|
17
|
+
require_relative "email_domain_checker/active_model_validator"
|
|
18
|
+
rescue LoadError
|
|
19
|
+
# ActiveModel is not available, skip integration
|
|
20
|
+
end
|
|
21
|
+
|
|
11
22
|
module EmailDomainChecker
|
|
12
23
|
class Error < StandardError; end
|
|
13
24
|
|
|
@@ -32,7 +43,7 @@ module EmailDomainChecker
|
|
|
32
43
|
end
|
|
33
44
|
|
|
34
45
|
# Configure default options
|
|
35
|
-
def self.configure(options = {})
|
|
36
|
-
Config.configure(options)
|
|
46
|
+
def self.configure(options = {}, &block)
|
|
47
|
+
Config.configure(options, &block)
|
|
37
48
|
end
|
|
38
49
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: email_domain_checker
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Koki Tatematsu
|
|
@@ -79,6 +79,7 @@ files:
|
|
|
79
79
|
- Rakefile
|
|
80
80
|
- email_domain_checker.gemspec
|
|
81
81
|
- lib/email_domain_checker.rb
|
|
82
|
+
- lib/email_domain_checker/active_model_validator.rb
|
|
82
83
|
- lib/email_domain_checker/checker.rb
|
|
83
84
|
- lib/email_domain_checker/config.rb
|
|
84
85
|
- lib/email_domain_checker/dns_resolver.rb
|