validatemail 1.0.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 2cf96d6c64ed3589ccb30bdc24617a2769cc48b449b3b1ccbf52947bce1f7bd7
4
+ data.tar.gz: f35e605affa914372bc060954b81fe9b447fa880c1bd70f264b52f21cd004850
5
+ SHA512:
6
+ metadata.gz: 8db378bd246095c716b60fab890a223cada22955f19202c3c6d25f4ea840816e444ae88102bfbf87fd302868541be8d46f5de6e45765ab1fb37573e35f8989c8
7
+ data.tar.gz: 906e6dc6939f2810a7ced0c4fe050b4448f56bbbbc90ee705fee71da4c11459ca9abeb5da96bcd242c8688ca767a1f52c72a7631a97a7b1ae8c1379d5b28237b
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.0.0
data/assets/bg.png ADDED
Binary file
data/assets/logo.png ADDED
Binary file
@@ -0,0 +1,78 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Validatemail
4
+ module Agent
5
+ class ABase
6
+ def initialize(email)
7
+ @email = email
8
+ @config = ::Validatemail::Config.new
9
+ end
10
+
11
+ def data
12
+ return @data if defined?(@data)
13
+
14
+ @data = Validatemail::Struct.new(
15
+ email: email,
16
+ autocorrect: autocorrect,
17
+ score: score,
18
+ valid: valid,
19
+ free: free,
20
+ first_name: first_name,
21
+ last_name: last_name,
22
+ validated_by: self.class.name.demodulize,
23
+ )
24
+ end
25
+
26
+ def ok?
27
+ api_url.present? &&
28
+ api_key.present? &&
29
+ http.code.between?(200, 299) &&
30
+ data.is_a?(Validatemail::Struct)
31
+ rescue StandardError => _e
32
+ false
33
+ end
34
+
35
+ def body
36
+ return @body if defined?(@body)
37
+
38
+ @body = JSON.parse(http.body).deep_symbolize_keys
39
+ end
40
+
41
+ def http
42
+ @http ||= HTTParty.get(
43
+ request_url,
44
+ headers: request_headers,
45
+ query: request_query,
46
+ )
47
+ end
48
+
49
+ def request_url
50
+ api_url
51
+ end
52
+
53
+ def request_headers
54
+ {}
55
+ end
56
+
57
+ def request_query
58
+ {}
59
+ end
60
+
61
+ private
62
+
63
+ attr_reader :email, :config
64
+
65
+ def api_url
66
+ config.public_send("#{name}_url")
67
+ end
68
+
69
+ def api_key
70
+ config.public_send("#{name}_api_key")
71
+ end
72
+
73
+ def name
74
+ self.class.name.demodulize.downcase
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Validatemail
4
+ module Agent
5
+ class Abstract < Validatemail::Agent::ABase
6
+ PRIORITY = 0
7
+ VALID = "DELIVERABLE"
8
+
9
+ def autocorrect
10
+ body[:autocorrect]
11
+ end
12
+
13
+ def score
14
+ body[:quality_score].to_f
15
+ end
16
+
17
+ def first_name
18
+ nil
19
+ end
20
+
21
+ def last_name
22
+ nil
23
+ end
24
+
25
+ def free
26
+ body[:is_free_email][:value]
27
+ end
28
+
29
+ def valid
30
+ body[:is_valid_format][:value] && body[:is_smtp_valid][:value] && body[:deliverability] == VALID
31
+ end
32
+
33
+ def request_query
34
+ { api_key: api_key, email: email }
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Validatemail
4
+ module Agent
5
+ class Apilayer < Validatemail::Agent::ABase
6
+ PRIORITY = 0
7
+
8
+ def autocorrect
9
+ body[:did_you_mean]
10
+ end
11
+
12
+ def score
13
+ body[:score].to_f
14
+ end
15
+
16
+ def first_name
17
+ nil
18
+ end
19
+
20
+ def last_name
21
+ nil
22
+ end
23
+
24
+ def free
25
+ body[:free]
26
+ end
27
+
28
+ def valid
29
+ body[:syntax_valid] && body[:is_deliverable] && body[:can_connect_smtp]
30
+ end
31
+
32
+ def request_url
33
+ "#{api_url}/#{email}"
34
+ end
35
+
36
+ def request_headers
37
+ { apikey: api_key }
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Validatemail
4
+ module Agent
5
+ class Hunter < Validatemail::Agent::ABase
6
+ PRIORITY = 1
7
+ VALID = "valid"
8
+
9
+ def autocorrect
10
+ nil
11
+ end
12
+
13
+ def score
14
+ body[:data][:score].to_f / 100.0
15
+ end
16
+
17
+ def first_name
18
+ nil
19
+ end
20
+
21
+ def last_name
22
+ nil
23
+ end
24
+
25
+ def free
26
+ nil
27
+ end
28
+
29
+ def valid
30
+ body[:data][:regexp] && body[:data][:smtp_check] && body[:data][:status] == VALID
31
+ end
32
+
33
+ def request_query
34
+ { api_key: api_key, email: email }
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Validatemail
4
+ module Agent
5
+ class Reacher < Validatemail::Agent::ABase
6
+ PRIORITY = 1
7
+ VALID = "safe"
8
+
9
+ def autocorrect
10
+ nil
11
+ end
12
+
13
+ def score
14
+ nil
15
+ end
16
+
17
+ def first_name
18
+ nil
19
+ end
20
+
21
+ def last_name
22
+ nil
23
+ end
24
+
25
+ def free
26
+ nil
27
+ end
28
+
29
+ def valid
30
+ body[:syntax][:is_valid_syntax] && body[:smtp][:can_connect_smtp] && body[:is_reachable] == VALID
31
+ end
32
+
33
+ def http
34
+ @http ||= HTTParty.post(
35
+ api_url,
36
+ headers: {
37
+ "Content-Type": "application/json",
38
+ Authorization: api_key,
39
+ },
40
+ data: { to_email: email },
41
+ )
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Validatemail
4
+ module Agent
5
+ class Whoisxml < Validatemail::Agent::ABase
6
+ PRIORITY = 1
7
+ API_TRUE = "true"
8
+ API_FALSE = "false"
9
+
10
+ def autocorrect
11
+ nil
12
+ end
13
+
14
+ def score
15
+ nil
16
+ end
17
+
18
+ def first_name
19
+ nil
20
+ end
21
+
22
+ def last_name
23
+ nil
24
+ end
25
+
26
+ def free
27
+ body[:freeCheck] == API_TRUE
28
+ end
29
+
30
+ def valid
31
+ body[:formatCheck] == API_TRUE &&
32
+ body[:smtpCheck] == API_TRUE &&
33
+ body[:dnsCheck] == API_TRUE &&
34
+ body[:disposableCheck] == API_FALSE &&
35
+ body[:catchAllCheck] == API_FALSE
36
+ end
37
+
38
+ def request_query
39
+ { apiKey: api_key, emailAddress: email }
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Validatemail
4
+ module Agent
5
+ class Zerobounce < Validatemail::Agent::ABase
6
+ PRIORITY = 1
7
+ VALID = "valid"
8
+
9
+ def autocorrect
10
+ body[:did_you_mean]
11
+ end
12
+
13
+ def score
14
+ nil
15
+ end
16
+
17
+ def first_name
18
+ body[:firstname]
19
+ end
20
+
21
+ def last_name
22
+ body[:lastname]
23
+ end
24
+
25
+ def free
26
+ body[:free_email]
27
+ end
28
+
29
+ def valid
30
+ body[:status] == VALID
31
+ end
32
+
33
+ def request_query
34
+ { api_key: api_key, email: email, ip_address: "0.0.0.0" }
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ Dir[__FILE__.sub(/\.rb$/, "/**/*.rb").to_s].each { |rb| require rb }
4
+
5
+ module Validatemail
6
+ module Agent; end
7
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Validatemail
4
+ class API
5
+ PROVIDERS = %w[
6
+ Abstract
7
+ Apilayer
8
+ Hunter
9
+ Reacher
10
+ Whoisxml
11
+ Zerobounce
12
+ ].freeze
13
+
14
+ attr_reader :email, :data
15
+
16
+ def initialize(email)
17
+ @email = email
18
+ @ok = false
19
+ validate!
20
+ end
21
+
22
+ def ok?
23
+ ok
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :ok
29
+
30
+ def validate!
31
+ done = false
32
+ @data = nil
33
+ until done
34
+ agent = providers.delete(providers.sample).new(email)
35
+ done = agent.ok? || providers.empty?
36
+ @data = agent.data if agent.ok?
37
+ @ok = true if agent.ok?
38
+ end
39
+ end
40
+
41
+ def providers
42
+ @providers ||= PROVIDERS.map { |provider| "Validatemail::Agent::#{provider}".constantize }
43
+ # .sort { |left, right| left::PRIORITY <=> right::PRIORITY }
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Validatemail
4
+ class Config < Anyway::Config
5
+ attr_config(
6
+ :abstract_api_key,
7
+ :apilayer_api_key,
8
+ :hunter_api_key,
9
+ :reacher_api_key,
10
+ :whoisxml_api_key,
11
+ :zerobounce_api_key,
12
+ )
13
+
14
+ # https://app.abstractapi.com/api/email-validation/documentation
15
+ def abstract_url
16
+ "https://emailvalidation.abstractapi.com/v1"
17
+ end
18
+
19
+ # https://apilayer.com/marketplace/email_verification-api#documentation-tab
20
+ def apilayer_url
21
+ "https://api.apilayer.com/email_verification"
22
+ end
23
+
24
+ # https://hunter.io/api-keys
25
+ def hunter_url
26
+ "https://api.hunter.io/v2/email-verifier"
27
+ end
28
+
29
+ # https://app.reacher.email/dashboard
30
+ def reacher_url
31
+ "https://api.reacher.email/v0/check_email"
32
+ end
33
+
34
+ # https://emailverification.whoisxmlapi.com/api/documentation/making-requests
35
+ def whoisxml_url
36
+ "https://emailverification.whoisxmlapi.com/api/v2"
37
+ end
38
+
39
+ # https://www.zerobounce.net/docs/email-validation-api-quickstart#validate_emails__v2__
40
+ def zerobounce_url
41
+ "https://api.zerobounce.net/v2/validate"
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Validatemail
4
+ class Struct < Dry::Struct
5
+ attribute(:email, Types::Strict::String)
6
+ attribute(:valid, Types::Strict::Bool)
7
+ attribute(:validated_by, Types::Strict::String.enum(
8
+ "Abstract",
9
+ "Apilayer",
10
+ "Hunter",
11
+ "Reacher",
12
+ "Whoisxml",
13
+ "Zerobounce",
14
+ ),)
15
+ attribute(:autocorrect, Types::Strict::String.optional.default(nil))
16
+ attribute(:score, Types::Strict::Float.optional.default(nil))
17
+ attribute(:first_name, Types::Strict::String.optional.default(nil))
18
+ attribute(:last_name, Types::Strict::String.optional.default(nil))
19
+ attribute(:free, Types::Strict::Bool.optional.default(nil))
20
+ end
21
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Types
4
+ include Dry.Types
5
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Validatemail
4
+ class Version
5
+ STRING = File.read(__dir__.sub(%r{lib/validatemail$}, "VERSION"))
6
+ end
7
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/all"
4
+ require "anyway_config"
5
+ require "dry-struct"
6
+ require "httparty"
7
+ require "json"
8
+ require "pry"
9
+
10
+ require_relative "validatemail/config"
11
+ require_relative "validatemail/types"
12
+ require_relative "validatemail/struct"
13
+ require_relative "validatemail/agent"
14
+ require_relative "validatemail/api"
15
+ require_relative "validatemail/version"
16
+
17
+ module Validatemail; end
metadata ADDED
@@ -0,0 +1,249 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: validatemail
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Wiktor Plaga
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2023-02-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '7.0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '7.0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: anyway_config
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: dry-struct
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: httparty
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.20'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.20'
69
+ - !ruby/object:Gem::Dependency
70
+ name: pry
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.14'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.14'
83
+ - !ruby/object:Gem::Dependency
84
+ name: fasterer
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.10'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.10'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rspec
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '3.11'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '3.11'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rspec-expectations
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '3.12'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '3.12'
125
+ - !ruby/object:Gem::Dependency
126
+ name: rubocop
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '1.36'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '1.36'
139
+ - !ruby/object:Gem::Dependency
140
+ name: rubocop-performance
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '1.15'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '1.15'
153
+ - !ruby/object:Gem::Dependency
154
+ name: rubocop-rspec
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '2.13'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '2.13'
167
+ - !ruby/object:Gem::Dependency
168
+ name: simplecov
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: '0.21'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: '0.21'
181
+ - !ruby/object:Gem::Dependency
182
+ name: simplecov-cobertura
183
+ requirement: !ruby/object:Gem::Requirement
184
+ requirements:
185
+ - - "~>"
186
+ - !ruby/object:Gem::Version
187
+ version: '2.1'
188
+ type: :development
189
+ prerelease: false
190
+ version_requirements: !ruby/object:Gem::Requirement
191
+ requirements:
192
+ - - "~>"
193
+ - !ruby/object:Gem::Version
194
+ version: '2.1'
195
+ description: |2
196
+ Email validator that hits freemium providers one by one and returns
197
+ normalized response.
198
+ email: hix.dev@tzif.io
199
+ executables: []
200
+ extensions: []
201
+ extra_rdoc_files: []
202
+ files:
203
+ - VERSION
204
+ - assets/bg.png
205
+ - assets/logo.png
206
+ - lib/validatemail.rb
207
+ - lib/validatemail/agent.rb
208
+ - lib/validatemail/agent/a_base.rb
209
+ - lib/validatemail/agent/abstract.rb
210
+ - lib/validatemail/agent/apilayer.rb
211
+ - lib/validatemail/agent/hunter.rb
212
+ - lib/validatemail/agent/reacher.rb
213
+ - lib/validatemail/agent/whoisxml.rb
214
+ - lib/validatemail/agent/zerobounce.rb
215
+ - lib/validatemail/api.rb
216
+ - lib/validatemail/config.rb
217
+ - lib/validatemail/struct.rb
218
+ - lib/validatemail/types.rb
219
+ - lib/validatemail/version.rb
220
+ homepage: https://github.com/hixdevs/email-validator-rubygem
221
+ licenses:
222
+ - GPL-3.0
223
+ metadata:
224
+ homepage_uri: https://github.com/hixdevs/email-validator-rubygem
225
+ changelog_uri: https://github.com/hixdevs/email-validator-rubygem/blob/prd/CHANGELOG.md
226
+ source_code_uri: https://github.com/hixdevs/email-validator-rubygem/
227
+ documentation_uri: https://github.com/hixdevs/email-validator-rubygem/blob/prd/README.md
228
+ bug_tracker_uri: https://github.com/hixdevs/email-validator-rubygem/issues
229
+ rubygems_mfa_required: 'true'
230
+ post_install_message:
231
+ rdoc_options: []
232
+ require_paths:
233
+ - lib
234
+ required_ruby_version: !ruby/object:Gem::Requirement
235
+ requirements:
236
+ - - ">="
237
+ - !ruby/object:Gem::Version
238
+ version: 3.0.0
239
+ required_rubygems_version: !ruby/object:Gem::Requirement
240
+ requirements:
241
+ - - ">="
242
+ - !ruby/object:Gem::Version
243
+ version: '0'
244
+ requirements: []
245
+ rubygems_version: 3.4.6
246
+ signing_key:
247
+ specification_version: 4
248
+ summary: Email validation via freemium providers.
249
+ test_files: []