valid_email 0.1.3 → 0.2.1
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/.github/workflows/ci.yaml +44 -0
- data/.rspec +0 -0
- data/README.md +91 -52
- data/config/locales/cs.yml +5 -0
- data/config/locales/es.yml +5 -0
- data/config/valid_email.yml +0 -1
- data/lib/valid_email/ban_disposable_email_validator.rb +13 -3
- data/lib/valid_email/email_validator.rb +2 -2
- data/lib/valid_email/validate_email.rb +20 -3
- data/lib/valid_email/version.rb +1 -1
- data/spec/email_validator_spec.rb +96 -46
- data/spec/spec_helper.rb +6 -0
- data/spec/validate_email_spec.rb +14 -0
- data/valid_email.gemspec +5 -6
- metadata +30 -14
- data/.travis.yml +0 -15
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7e0da2f8d6e1b69a777c0d9a6bb14632fa577ecfa55acb7128d436e1543a6842
|
|
4
|
+
data.tar.gz: c8a125e2971de31cd1e43a49827af99cb1a44130082c555b448083aa1fc6bbaf
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 736072b973d66828d1f2cd78b6248599a5ecc3d054d0cbbd1354a4735447a97024575649c7bbe110edb576f18cedd647d378ceb12a9d8344639179c3c8d8ade0
|
|
7
|
+
data.tar.gz: 52fa87c50d4bf5570779706a39dea8c803b894256d7a92563b0b02009f92b262b6439565d4efd5345b65974f41dbd899085c6349f7c1cb4a5e9c82abcf21efe1
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
on:
|
|
3
|
+
workflow_dispatch:
|
|
4
|
+
push:
|
|
5
|
+
|
|
6
|
+
permissions:
|
|
7
|
+
checks: write
|
|
8
|
+
contents: read
|
|
9
|
+
pull-requests: write
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
rspec:
|
|
13
|
+
name: RSpec (ruby ${{ matrix.ruby-version }})
|
|
14
|
+
runs-on: ubuntu-20.04
|
|
15
|
+
strategy:
|
|
16
|
+
fail-fast: false
|
|
17
|
+
matrix:
|
|
18
|
+
ruby-version:
|
|
19
|
+
- '1.9.3'
|
|
20
|
+
- '2.0'
|
|
21
|
+
- '2.1'
|
|
22
|
+
- '2.2'
|
|
23
|
+
- '2.3'
|
|
24
|
+
- '2.4'
|
|
25
|
+
- '2.5'
|
|
26
|
+
- '2.6'
|
|
27
|
+
- '2.7'
|
|
28
|
+
- '3.0'
|
|
29
|
+
- '3.1'
|
|
30
|
+
- '3.2'
|
|
31
|
+
- 'jruby-head'
|
|
32
|
+
- 'truffleruby-head'
|
|
33
|
+
env:
|
|
34
|
+
CI: true
|
|
35
|
+
steps:
|
|
36
|
+
- name: Checkout
|
|
37
|
+
uses: actions/checkout@v3
|
|
38
|
+
- name: Setup ruby
|
|
39
|
+
uses: ruby/setup-ruby@v1
|
|
40
|
+
with:
|
|
41
|
+
ruby-version: ${{ matrix.ruby-version }}
|
|
42
|
+
bundler-cache: true
|
|
43
|
+
- name: Run tests
|
|
44
|
+
run: bundle exec rake
|
data/.rspec
ADDED
|
File without changes
|
data/README.md
CHANGED
|
@@ -1,98 +1,141 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Valid Email
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## Purpose
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
It validates email for application use (registering a new account for example).
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
gem 'valid_email'
|
|
7
|
+
## Usage
|
|
10
8
|
|
|
9
|
+
In your `Gemfile`:
|
|
10
|
+
```ruby
|
|
11
|
+
gem 'valid_email'
|
|
12
|
+
```
|
|
11
13
|
|
|
12
|
-
In your code
|
|
14
|
+
In your code:
|
|
15
|
+
```ruby
|
|
16
|
+
require 'valid_email'
|
|
13
17
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
attr_accessor :name, :email
|
|
18
|
+
class Person
|
|
19
|
+
include ActiveModel::Validations
|
|
20
|
+
attr_accessor :name, :email
|
|
18
21
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
+
validates :name, presence: true, length: { maximum: 100 }
|
|
23
|
+
validates :email, presence: true, email: true
|
|
24
|
+
end
|
|
22
25
|
|
|
23
26
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
27
|
+
person = Person.new
|
|
28
|
+
person.name = 'hallelujah'
|
|
29
|
+
person.email = 'john@doe.com'
|
|
30
|
+
person.valid? # => true
|
|
28
31
|
|
|
29
|
-
|
|
30
|
-
|
|
32
|
+
person.email = 'john@doe'
|
|
33
|
+
person.valid? # => false
|
|
31
34
|
|
|
32
|
-
|
|
33
|
-
|
|
35
|
+
person.email = 'John Does <john@doe.com>'
|
|
36
|
+
person.valid? # => false
|
|
37
|
+
```
|
|
34
38
|
|
|
35
39
|
You can check if email domain has MX record:
|
|
36
|
-
|
|
37
|
-
|
|
40
|
+
```ruby
|
|
41
|
+
validates :email,
|
|
42
|
+
email: {
|
|
43
|
+
mx: true,
|
|
44
|
+
message: I18n.t('validations.errors.models.user.invalid_email')
|
|
45
|
+
}
|
|
46
|
+
```
|
|
38
47
|
|
|
39
48
|
Or
|
|
40
49
|
|
|
41
|
-
|
|
50
|
+
```ruby
|
|
51
|
+
validates :email,
|
|
52
|
+
email: {
|
|
53
|
+
message: I18n.t('validations.errors.models.user.invalid_email')
|
|
54
|
+
},
|
|
55
|
+
mx: {
|
|
56
|
+
message: I18n.t('validations.errors.models.user.invalid_mx')
|
|
57
|
+
}
|
|
58
|
+
```
|
|
42
59
|
|
|
43
60
|
By default, the email domain is validated using a regular expression, which does not require an external service and improves performance.
|
|
44
61
|
Alternatively, you can check if an email domain has a MX or A record by using `:mx_with_fallback` instead of `:mx`.
|
|
45
62
|
|
|
46
|
-
|
|
63
|
+
```ruby
|
|
64
|
+
validates :email, email: { mx_with_fallback: true }
|
|
65
|
+
```
|
|
47
66
|
|
|
48
67
|
You can detect disposable accounts
|
|
49
68
|
|
|
50
|
-
|
|
69
|
+
```ruby
|
|
70
|
+
validates :email,
|
|
71
|
+
email: {
|
|
72
|
+
ban_disposable_email: true,
|
|
73
|
+
message: I18n.t('validations.errors.models.user.invalid_email')
|
|
74
|
+
}
|
|
75
|
+
```
|
|
51
76
|
|
|
52
|
-
|
|
77
|
+
You can also detect a partial match on disposable accounts, good for services that use subdomains.
|
|
53
78
|
|
|
54
|
-
|
|
79
|
+
```ruby
|
|
80
|
+
validates :email,
|
|
81
|
+
email: {
|
|
82
|
+
message: I18n.t('validations.errors.models.user.invalid_email')
|
|
83
|
+
ban_disposable_email: true,
|
|
84
|
+
partial: true
|
|
85
|
+
}
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
If you don't want the MX validator stuff, just require the right file
|
|
55
89
|
|
|
56
|
-
|
|
90
|
+
```ruby
|
|
91
|
+
require 'valid_email/email_validator'
|
|
92
|
+
```
|
|
57
93
|
|
|
58
|
-
|
|
94
|
+
Or in your `Gemfile`
|
|
59
95
|
|
|
96
|
+
```ruby
|
|
97
|
+
gem 'valid_email', require: 'valid_email/email_validator'
|
|
98
|
+
```
|
|
60
99
|
|
|
61
100
|
### Usage outside of model validation
|
|
62
|
-
|
|
101
|
+
|
|
102
|
+
There is a chance that you want to use e-mail validator outside of model validation.
|
|
63
103
|
If that's the case, you can use the following methods:
|
|
64
104
|
|
|
65
105
|
```ruby
|
|
66
|
-
|
|
106
|
+
options = {} # You can optionally pass a hash of options, same as validator
|
|
107
|
+
ValidateEmail.valid?('email@randommail.com', options)
|
|
67
108
|
ValidateEmail.mx_valid?('email@randommail.com')
|
|
68
109
|
ValidateEmail.mx_valid_with_fallback?('email@randommail.com')
|
|
69
110
|
ValidateEmail.valid?('email@randommail.com')
|
|
70
111
|
```
|
|
71
112
|
|
|
72
|
-
Load it (and not the
|
|
73
|
-
|
|
74
|
-
gem 'valid_email', require: 'valid_email/validate_email'
|
|
113
|
+
Load it (and not the Rails extensions) with
|
|
75
114
|
|
|
115
|
+
```ruby
|
|
116
|
+
gem 'valid_email', require: 'valid_email/validate_email'
|
|
117
|
+
```
|
|
76
118
|
|
|
77
119
|
### String and Nil object extensions
|
|
78
120
|
|
|
79
|
-
There is also a String and Nil class extension, if you require the gem in this way in Gemfile
|
|
121
|
+
There is also a String and Nil class extension, if you require the gem in this way in `Gemfile`:
|
|
80
122
|
|
|
81
123
|
```ruby
|
|
82
|
-
gem 'valid_email', require:
|
|
124
|
+
gem 'valid_email', require: 'valid_email/all_with_extensions'
|
|
83
125
|
```
|
|
84
126
|
|
|
85
127
|
You will be able to use the following methods:
|
|
86
128
|
```ruby
|
|
87
129
|
nil.email? # => false
|
|
88
|
-
|
|
130
|
+
'john@gmail.com'.email? # => May return true if it exists.
|
|
131
|
+
# It accepts a hash of options like ValidateEmail.valid?
|
|
89
132
|
```
|
|
90
133
|
|
|
91
134
|
## Code Status
|
|
92
135
|
|
|
93
|
-
|
|
136
|
+
[](https://github.com/hallelujah/valid_email/actions/workflows/ci.yaml)
|
|
94
137
|
|
|
95
|
-
|
|
138
|
+
## Credits
|
|
96
139
|
|
|
97
140
|
* Ramihajamalala Hery hery[at]rails-royce.org
|
|
98
141
|
* Fire-Dragon-DoL francesco.belladonna[at]gmail.com
|
|
@@ -109,18 +152,14 @@ nil.email? # => false
|
|
|
109
152
|
* Jean Boussier jean.boussier[at]gmail.com
|
|
110
153
|
* Masaki Hara - @qnighy
|
|
111
154
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
* Fork the project.
|
|
115
|
-
|
|
116
|
-
* Make your feature addition or bug fix.
|
|
117
|
-
|
|
118
|
-
* Add tests for it. This is important so I don’t break it in a future version unintentionally.
|
|
119
|
-
|
|
120
|
-
* Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
|
155
|
+
## Pull Requests
|
|
121
156
|
|
|
122
|
-
|
|
157
|
+
1. Fork the project.
|
|
158
|
+
2. Make your feature addition or bug fix.
|
|
159
|
+
3. Add tests for it. This is important so I don’t break it in a future version unintentionally.
|
|
160
|
+
4. Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
|
|
161
|
+
5. Send me a pull request. Bonus points for topic branches.
|
|
123
162
|
|
|
124
|
-
|
|
163
|
+
## Copyright
|
|
125
164
|
|
|
126
165
|
Copyright © 2011 Ramihajamalala Hery. See LICENSE for details
|
data/config/valid_email.yml
CHANGED
|
@@ -15,9 +15,19 @@ class BanDisposableEmailValidator < ActiveModel::EachValidator
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def validate_each(record, attribute, value)
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
# Check if part of domain is in disposable_email_services yml list
|
|
19
|
+
if options[:partial]
|
|
20
|
+
r = ValidateEmail.ban_partial_disposable_email?(value)
|
|
21
|
+
record.errors.add attribute, (options[:message] ||
|
|
22
|
+
I18n.t(:invalid, :scope => "valid_email.validations.email")) unless r
|
|
20
23
|
|
|
21
|
-
|
|
24
|
+
r
|
|
25
|
+
else
|
|
26
|
+
r = ValidateEmail.ban_disposable_email?(value)
|
|
27
|
+
record.errors.add attribute, (options[:message] ||
|
|
28
|
+
I18n.t(:invalid, :scope => "valid_email.validations.email")) unless r
|
|
29
|
+
|
|
30
|
+
r
|
|
31
|
+
end
|
|
22
32
|
end
|
|
23
33
|
end
|
|
@@ -18,11 +18,11 @@ class EmailValidator < ActiveModel::EachValidator
|
|
|
18
18
|
# Check if domain is disposable
|
|
19
19
|
if r && options[:ban_disposable_email]
|
|
20
20
|
require 'valid_email/ban_disposable_email_validator'
|
|
21
|
-
r = BanDisposableEmailValidator.new(:attributes => attributes, message: options[:message]).validate(record)
|
|
21
|
+
r = BanDisposableEmailValidator.new(:attributes => attributes, message: options[:message], partial: options[:partial]).validate(record)
|
|
22
22
|
end
|
|
23
23
|
unless r
|
|
24
24
|
msg = (options[:message] || I18n.t(:invalid, :scope => "valid_email.validations.email"))
|
|
25
|
-
record.errors.add attribute, (msg
|
|
25
|
+
record.errors.add attribute, message: I18n.interpolate(msg, value: value)
|
|
26
26
|
end
|
|
27
27
|
end
|
|
28
28
|
end
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
require 'mail'
|
|
2
|
+
require 'simpleidn'
|
|
2
3
|
|
|
3
4
|
class ValidateEmail
|
|
4
5
|
class << self
|
|
@@ -27,7 +28,7 @@ class ValidateEmail
|
|
|
27
28
|
return false unless m.domain.match(/^\S+$/)
|
|
28
29
|
|
|
29
30
|
domain_dot_elements = m.domain.split(/\./)
|
|
30
|
-
return false unless domain_dot_elements.size > 1 &&
|
|
31
|
+
return false unless domain_dot_elements.size > 1 && domain_dot_elements.none?(&:empty?)
|
|
31
32
|
|
|
32
33
|
# Ensure that the local segment adheres to adheres to RFC-5322
|
|
33
34
|
return false unless valid_local?(m.local)
|
|
@@ -90,11 +91,17 @@ class ValidateEmail
|
|
|
90
91
|
m = Mail::Address.new(value)
|
|
91
92
|
return false unless m.domain
|
|
92
93
|
|
|
94
|
+
if m.domain.ascii_only?
|
|
95
|
+
ascii_domain = m.domain
|
|
96
|
+
else
|
|
97
|
+
ascii_domain = SimpleIDN.to_ascii(m.domain)
|
|
98
|
+
end
|
|
99
|
+
|
|
93
100
|
Resolv::DNS.open do |dns|
|
|
94
101
|
dns.timeouts = MxValidator.config[:timeouts] unless MxValidator.config[:timeouts].empty?
|
|
95
102
|
|
|
96
|
-
return dns.getresources(
|
|
97
|
-
fallback && dns.getresources(
|
|
103
|
+
return dns.getresources(ascii_domain, Resolv::DNS::Resource::IN::MX).size > 0 || (
|
|
104
|
+
fallback && dns.getresources(ascii_domain, Resolv::DNS::Resource::IN::A).size > 0
|
|
98
105
|
)
|
|
99
106
|
end
|
|
100
107
|
rescue Mail::Field::ParseError
|
|
@@ -121,5 +128,15 @@ class ValidateEmail
|
|
|
121
128
|
rescue Mail::Field::ParseError
|
|
122
129
|
false
|
|
123
130
|
end
|
|
131
|
+
|
|
132
|
+
def ban_partial_disposable_email?(value)
|
|
133
|
+
m = Mail::Address.new(value)
|
|
134
|
+
m.domain && !BanDisposableEmailValidator.config.any? do |bde|
|
|
135
|
+
next if bde == nil
|
|
136
|
+
m.domain.end_with?(bde)
|
|
137
|
+
end
|
|
138
|
+
rescue Mail::Field::ParseError
|
|
139
|
+
false
|
|
140
|
+
end
|
|
124
141
|
end
|
|
125
142
|
end
|
data/lib/valid_email/version.rb
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
ValidEmailVersion = "0.1
|
|
1
|
+
ValidEmailVersion = "0.2.1"
|
|
@@ -1,63 +1,73 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
|
|
3
|
+
RSpec::Matchers.define :have_error_messages do |field, expected|
|
|
4
|
+
match do |model|
|
|
5
|
+
errors = model.errors[field]
|
|
6
|
+
|
|
7
|
+
messages = errors.map do |error|
|
|
8
|
+
case error
|
|
9
|
+
when String then error
|
|
10
|
+
when Hash then error[:message]
|
|
11
|
+
else fail ArgumentError, "Unknown model error type #{error.class}"
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
expect(messages).to eq expected
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
3
19
|
describe EmailValidator do
|
|
4
|
-
|
|
20
|
+
email_class = Class.new do
|
|
5
21
|
include ActiveModel::Validations
|
|
22
|
+
|
|
6
23
|
attr_accessor :email
|
|
24
|
+
|
|
25
|
+
def self.model_name
|
|
26
|
+
ActiveModel::Name.new(self, nil, "TestModel")
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
person_class = Class.new(email_class) do
|
|
7
31
|
validates :email, :email => true
|
|
8
32
|
end
|
|
9
33
|
|
|
10
|
-
person_class_mx = Class.new do
|
|
11
|
-
include ActiveModel::Validations
|
|
12
|
-
attr_accessor :email
|
|
34
|
+
person_class_mx = Class.new(email_class) do
|
|
13
35
|
validates :email, :email => {:mx => true}
|
|
14
36
|
end
|
|
15
37
|
|
|
16
|
-
person_class_mx_with_fallback = Class.new do
|
|
17
|
-
include ActiveModel::Validations
|
|
18
|
-
attr_accessor :email
|
|
38
|
+
person_class_mx_with_fallback = Class.new(email_class) do
|
|
19
39
|
validates :email, :email => {:mx_with_fallback => true}
|
|
20
40
|
end
|
|
21
41
|
|
|
22
|
-
person_class_disposable_email = Class.new do
|
|
23
|
-
include ActiveModel::Validations
|
|
24
|
-
attr_accessor :email
|
|
42
|
+
person_class_disposable_email = Class.new(email_class) do
|
|
25
43
|
validates :email, :email => {:ban_disposable_email => true}
|
|
26
44
|
end
|
|
27
45
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
46
|
+
person_class_partial_disposable_email = Class.new(email_class) do
|
|
47
|
+
validates :email, :email => {:ban_disposable_email => true, :partial => true}
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
person_class_nil_allowed = Class.new(email_class) do
|
|
31
51
|
validates :email, :email => {:allow_nil => true}
|
|
32
52
|
end
|
|
33
53
|
|
|
34
|
-
person_class_blank_allowed = Class.new do
|
|
35
|
-
include ActiveModel::Validations
|
|
36
|
-
attr_accessor :email
|
|
54
|
+
person_class_blank_allowed = Class.new(email_class) do
|
|
37
55
|
validates :email, :email => {:allow_blank => true}
|
|
38
56
|
end
|
|
39
57
|
|
|
40
|
-
person_class_mx_separated = Class.new do
|
|
41
|
-
include ActiveModel::Validations
|
|
42
|
-
attr_accessor :email
|
|
58
|
+
person_class_mx_separated = Class.new(email_class) do
|
|
43
59
|
validates :email, :mx => true
|
|
44
60
|
end
|
|
45
61
|
|
|
46
|
-
person_class_mx_with_fallback_separated = Class.new do
|
|
47
|
-
include ActiveModel::Validations
|
|
48
|
-
attr_accessor :email
|
|
62
|
+
person_class_mx_with_fallback_separated = Class.new(email_class) do
|
|
49
63
|
validates :email, :mx_with_fallback => true
|
|
50
64
|
end
|
|
51
65
|
|
|
52
|
-
person_class_domain = Class.new do
|
|
53
|
-
include ActiveModel::Validations
|
|
54
|
-
attr_accessor :email
|
|
66
|
+
person_class_domain = Class.new(email_class) do
|
|
55
67
|
validates :email, :domain => true
|
|
56
68
|
end
|
|
57
69
|
|
|
58
|
-
person_message_specified = Class.new do
|
|
59
|
-
include ActiveModel::Validations
|
|
60
|
-
attr_accessor :email
|
|
70
|
+
person_message_specified = Class.new(email_class) do
|
|
61
71
|
validates :email, :email => { :message => 'custom message', :ban_disposable_email => true }
|
|
62
72
|
end
|
|
63
73
|
|
|
@@ -79,43 +89,43 @@ describe EmailValidator do
|
|
|
79
89
|
|
|
80
90
|
it "fails when email empty" do
|
|
81
91
|
expect(subject.valid?).to be_falsey
|
|
82
|
-
expect(subject
|
|
92
|
+
expect(subject).to have_error_messages(:email, errors)
|
|
83
93
|
end
|
|
84
94
|
|
|
85
95
|
it "fails when email is not valid" do
|
|
86
96
|
subject.email = 'joh@doe'
|
|
87
97
|
expect(subject.valid?).to be_falsey
|
|
88
|
-
expect(subject
|
|
98
|
+
expect(subject).to have_error_messages(:email, errors)
|
|
89
99
|
end
|
|
90
100
|
|
|
91
101
|
it "fails when email domain is prefixed with dot" do
|
|
92
102
|
subject.email = 'john@.doe'
|
|
93
103
|
expect(subject.valid?).to be_falsey
|
|
94
|
-
expect(subject
|
|
104
|
+
expect(subject).to have_error_messages(:email, errors)
|
|
95
105
|
end
|
|
96
106
|
|
|
97
107
|
it "fails when email domain contains two consecutive dots" do
|
|
98
108
|
subject.email = 'john@doe-two..com'
|
|
99
109
|
expect(subject.valid?).to be_falsey
|
|
100
|
-
expect(subject
|
|
110
|
+
expect(subject).to have_error_messages(:email, errors)
|
|
101
111
|
end
|
|
102
112
|
|
|
103
113
|
it "fails when email ends with a period" do
|
|
104
114
|
subject.email = 'john@doe.com.'
|
|
105
115
|
expect(subject.valid?).to be_falsey
|
|
106
|
-
expect(subject
|
|
116
|
+
expect(subject).to have_error_messages(:email, errors)
|
|
107
117
|
end
|
|
108
118
|
|
|
109
119
|
it "fails when email ends with special characters" do
|
|
110
120
|
subject.email = 'john@doe.com&'
|
|
111
121
|
expect(subject.valid?).to be_falsey
|
|
112
|
-
expect(subject
|
|
122
|
+
expect(subject).to have_error_messages(:email, errors)
|
|
113
123
|
end
|
|
114
124
|
|
|
115
125
|
it "fails when email is valid with information" do
|
|
116
126
|
subject.email = '"John Doe" <john@doe.com>'
|
|
117
127
|
expect(subject.valid?).to be_falsey
|
|
118
|
-
expect(subject
|
|
128
|
+
expect(subject).to have_error_messages(:email, errors)
|
|
119
129
|
end
|
|
120
130
|
|
|
121
131
|
it "passes when email is simple email address" do
|
|
@@ -127,42 +137,51 @@ describe EmailValidator do
|
|
|
127
137
|
it "fails when email is simple email address not stripped" do
|
|
128
138
|
subject.email = 'john@doe.com '
|
|
129
139
|
expect(subject.valid?).to be_falsey
|
|
130
|
-
expect(subject
|
|
140
|
+
expect(subject).to have_error_messages(:email, errors)
|
|
131
141
|
end
|
|
132
142
|
|
|
133
143
|
it "fails when domain contains a space" do
|
|
134
144
|
subject.email = 'john@doe .com'
|
|
135
145
|
expect(subject.valid?).to be_falsey
|
|
136
|
-
expect(subject
|
|
146
|
+
expect(subject).to have_error_messages(:email, errors)
|
|
137
147
|
end
|
|
138
148
|
|
|
139
149
|
it "fails when passing multiple simple email addresses" do
|
|
140
150
|
subject.email = 'john@doe.com, maria@doe.com'
|
|
141
151
|
expect(subject.valid?).to be_falsey
|
|
142
|
-
expect(subject
|
|
152
|
+
expect(subject).to have_error_messages(:email, errors)
|
|
143
153
|
end
|
|
144
|
-
|
|
145
154
|
end
|
|
146
155
|
|
|
147
156
|
describe "validating email with MX and fallback to A" do
|
|
157
|
+
let(:dns) { instance_double('Resolv::DNS', :dns) }
|
|
158
|
+
|
|
148
159
|
subject { person_class_mx_with_fallback.new }
|
|
149
160
|
|
|
161
|
+
before do
|
|
162
|
+
allow(Resolv::DNS).to receive(:open).and_yield(dns)
|
|
163
|
+
end
|
|
164
|
+
|
|
150
165
|
it "passes when email domain has MX record" do
|
|
151
|
-
|
|
166
|
+
allow(dns).to receive(:getresources).with('has-mx-record.org', Resolv::DNS::Resource::IN::MX).and_return(['1.2.3.4'])
|
|
167
|
+
subject.email = 'john@has-mx-record.org'
|
|
152
168
|
expect(subject.valid?).to be_truthy
|
|
153
169
|
expect(subject.errors[:email]).to be_empty
|
|
154
170
|
end
|
|
155
171
|
|
|
156
172
|
it "passes when email domain has no MX record but has an A record" do
|
|
157
|
-
|
|
173
|
+
allow(dns).to receive(:getresources).with('has-a-record.org', Resolv::DNS::Resource::IN::MX).and_return([])
|
|
174
|
+
allow(dns).to receive(:getresources).with('has-a-record.org', Resolv::DNS::Resource::IN::A).and_return(['1.2.3.4'])
|
|
175
|
+
subject.email = 'john@has-a-record.org'
|
|
158
176
|
expect(subject.valid?).to be_truthy
|
|
159
177
|
expect(subject.errors[:email]).to be_empty
|
|
160
178
|
end
|
|
161
179
|
|
|
162
180
|
it "fails when domain does not exists" do
|
|
163
|
-
|
|
181
|
+
allow(dns).to receive(:getresources).with('does-not-exist.org', anything).and_return([])
|
|
182
|
+
subject.email = 'john@does-not-exist.org'
|
|
164
183
|
expect(subject.valid?).to be_falsey
|
|
165
|
-
expect(subject
|
|
184
|
+
expect(subject).to have_error_messages(:email, errors)
|
|
166
185
|
end
|
|
167
186
|
end
|
|
168
187
|
|
|
@@ -178,13 +197,13 @@ describe EmailValidator do
|
|
|
178
197
|
it "fails when email domain has no MX record" do
|
|
179
198
|
subject.email = 'john@subdomain.rubyonrails.org'
|
|
180
199
|
expect(subject.valid?).to be_falsey
|
|
181
|
-
expect(subject
|
|
200
|
+
expect(subject).to have_error_messages(:email, errors)
|
|
182
201
|
end
|
|
183
202
|
|
|
184
203
|
it "fails when domain does not exists" do
|
|
185
204
|
subject.email = 'john@nonexistentdomain.abc'
|
|
186
205
|
expect(subject.valid?).to be_falsey
|
|
187
|
-
expect(subject
|
|
206
|
+
expect(subject).to have_error_messages(:email, errors)
|
|
188
207
|
end
|
|
189
208
|
end
|
|
190
209
|
|
|
@@ -228,6 +247,22 @@ describe EmailValidator do
|
|
|
228
247
|
it "fails when email from disposable email services" do
|
|
229
248
|
subject.email = 'john@grr.la'
|
|
230
249
|
expect(subject.valid?).to be_falsey
|
|
250
|
+
expect(subject).to have_error_messages(:email, errors)
|
|
251
|
+
end
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
describe "validating email against partial disposable service match" do
|
|
255
|
+
subject { person_class_partial_disposable_email.new }
|
|
256
|
+
|
|
257
|
+
it "passes when email from trusted email services" do
|
|
258
|
+
subject.email = 'john@test.mail.ru'
|
|
259
|
+
expect(subject.valid?).to be_truthy
|
|
260
|
+
expect(subject.errors[:email]).to be_empty
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
it "fails when disposable email services partially matches email domain" do
|
|
264
|
+
subject.email = 'john@sub.grr.la'
|
|
265
|
+
expect(subject.valid?).to be_falsey
|
|
231
266
|
expect(subject.errors[:email]).to eq errors
|
|
232
267
|
end
|
|
233
268
|
end
|
|
@@ -238,7 +273,7 @@ describe EmailValidator do
|
|
|
238
273
|
it "does not pass with an invalid domain" do
|
|
239
274
|
subject.email = "test@example.org$\'"
|
|
240
275
|
expect(subject.valid?).to be_falsey
|
|
241
|
-
expect(subject
|
|
276
|
+
expect(subject).to have_error_messages(:email, errors)
|
|
242
277
|
end
|
|
243
278
|
|
|
244
279
|
it "passes with valid domain" do
|
|
@@ -290,4 +325,19 @@ describe EmailValidator do
|
|
|
290
325
|
let!(:errors) { [ "est invalide" ] }
|
|
291
326
|
it_behaves_like "Validating emails"
|
|
292
327
|
end
|
|
328
|
+
|
|
329
|
+
describe 'Translating in czech' do
|
|
330
|
+
let!(:locale){ :cs }
|
|
331
|
+
let!(:errors) do
|
|
332
|
+
[
|
|
333
|
+
I18n.t(
|
|
334
|
+
:invalid,
|
|
335
|
+
locale: locale,
|
|
336
|
+
scope: [:valid_email, :validations, :email]
|
|
337
|
+
)
|
|
338
|
+
]
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
it_behaves_like 'Validating emails'
|
|
342
|
+
end
|
|
293
343
|
end
|
data/spec/spec_helper.rb
CHANGED
data/spec/validate_email_spec.rb
CHANGED
|
@@ -15,13 +15,27 @@ describe ValidateEmail do
|
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
context 'when mx: true option passed' do
|
|
18
|
+
let(:dns) { Resolv::DNS.new }
|
|
19
|
+
|
|
20
|
+
def mock_dns_mx
|
|
21
|
+
allow(dns).to receive(:getresources).and_return([])
|
|
22
|
+
allow(Resolv::DNS).to receive(:new).and_return(dns)
|
|
23
|
+
end
|
|
24
|
+
|
|
18
25
|
it 'returns true when mx record exist' do
|
|
19
26
|
expect(ValidateEmail.valid?('user@gmail.com', mx: true)).to be_truthy
|
|
20
27
|
end
|
|
21
28
|
|
|
22
29
|
it "returns false when mx record doesn't exist" do
|
|
30
|
+
mock_dns_mx
|
|
23
31
|
expect(ValidateEmail.valid?('user@example.com', mx: true)).to be_falsey
|
|
24
32
|
end
|
|
33
|
+
|
|
34
|
+
it "IDN-encodes the domain name if it contains multibyte characters" do
|
|
35
|
+
mock_dns_mx
|
|
36
|
+
ValidateEmail.valid?("user@\u{1F600}.com", mx: true)
|
|
37
|
+
expect(dns).to have_received(:getresources).with('xn--e28h.com', anything)
|
|
38
|
+
end
|
|
25
39
|
end
|
|
26
40
|
|
|
27
41
|
context 'when domain: true option passed' do
|
data/valid_email.gemspec
CHANGED
|
@@ -12,21 +12,20 @@ Gem::Specification.new do |s|
|
|
|
12
12
|
s.description = %q{ActiveModel Validation for email}
|
|
13
13
|
s.license = 'MIT'
|
|
14
14
|
|
|
15
|
-
s.rubyforge_project = "valid_email"
|
|
16
|
-
|
|
17
15
|
s.files = `git ls-files`.split("\n")
|
|
18
16
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
19
17
|
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
20
18
|
s.require_paths = ["lib"]
|
|
21
19
|
|
|
22
20
|
# specify any dependencies here; for example:
|
|
23
|
-
s.add_development_dependency "rspec", "~>
|
|
24
|
-
s.add_development_dependency "rake"
|
|
21
|
+
s.add_development_dependency "rspec", "~> 3.10"
|
|
22
|
+
s.add_development_dependency "rake"
|
|
25
23
|
s.add_runtime_dependency "mail", ">= 2.6.1"
|
|
26
|
-
|
|
24
|
+
s.add_runtime_dependency "simpleidn"
|
|
25
|
+
if Gem::Version.new(RUBY_VERSION.dup) <= Gem::Version.new('2.0')
|
|
27
26
|
s.add_runtime_dependency 'mime-types', '<= 2.6.2'
|
|
28
27
|
end
|
|
29
|
-
if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.2.2')
|
|
28
|
+
if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.2.2')
|
|
30
29
|
s.add_runtime_dependency "activemodel", '< 5.0.0'
|
|
31
30
|
else
|
|
32
31
|
s.add_runtime_dependency "activemodel"
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: valid_email
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1
|
|
4
|
+
version: 0.2.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ramihajamalala Hery
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2024-03-16 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rspec
|
|
@@ -16,28 +16,28 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - "~>"
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version: '
|
|
19
|
+
version: '3.10'
|
|
20
20
|
type: :development
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
24
|
- - "~>"
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version: '
|
|
26
|
+
version: '3.10'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
28
|
name: rake
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
|
-
- - "
|
|
31
|
+
- - ">="
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '
|
|
33
|
+
version: '0'
|
|
34
34
|
type: :development
|
|
35
35
|
prerelease: false
|
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
|
37
37
|
requirements:
|
|
38
|
-
- - "
|
|
38
|
+
- - ">="
|
|
39
39
|
- !ruby/object:Gem::Version
|
|
40
|
-
version: '
|
|
40
|
+
version: '0'
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: mail
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -52,6 +52,20 @@ dependencies:
|
|
|
52
52
|
- - ">="
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
54
|
version: 2.6.1
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: simpleidn
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - ">="
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '0'
|
|
62
|
+
type: :runtime
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - ">="
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '0'
|
|
55
69
|
- !ruby/object:Gem::Dependency
|
|
56
70
|
name: activemodel
|
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -73,15 +87,18 @@ executables: []
|
|
|
73
87
|
extensions: []
|
|
74
88
|
extra_rdoc_files: []
|
|
75
89
|
files:
|
|
90
|
+
- ".github/workflows/ci.yaml"
|
|
76
91
|
- ".gitignore"
|
|
77
|
-
- ".
|
|
92
|
+
- ".rspec"
|
|
78
93
|
- Gemfile
|
|
79
94
|
- History.md
|
|
80
95
|
- LICENSE
|
|
81
96
|
- README.md
|
|
82
97
|
- Rakefile
|
|
98
|
+
- config/locales/cs.yml
|
|
83
99
|
- config/locales/de.yml
|
|
84
100
|
- config/locales/en.yml
|
|
101
|
+
- config/locales/es.yml
|
|
85
102
|
- config/locales/fi.yml
|
|
86
103
|
- config/locales/fr.yml
|
|
87
104
|
- config/locales/hu.yml
|
|
@@ -113,7 +130,7 @@ homepage: https://github.com/hallelujah/valid_email
|
|
|
113
130
|
licenses:
|
|
114
131
|
- MIT
|
|
115
132
|
metadata: {}
|
|
116
|
-
post_install_message:
|
|
133
|
+
post_install_message:
|
|
117
134
|
rdoc_options: []
|
|
118
135
|
require_paths:
|
|
119
136
|
- lib
|
|
@@ -128,9 +145,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
128
145
|
- !ruby/object:Gem::Version
|
|
129
146
|
version: '0'
|
|
130
147
|
requirements: []
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
signing_key:
|
|
148
|
+
rubygems_version: 3.5.6
|
|
149
|
+
signing_key:
|
|
134
150
|
specification_version: 4
|
|
135
151
|
summary: ActiveModel Validation for email
|
|
136
152
|
test_files:
|