zerobounce 0.0.6 → 0.2.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 +5 -5
- data/.github/ISSUE_TEMPLATE/bug_report.md +27 -0
- data/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- data/.github/dependabot.yml +10 -0
- data/.github/pull_request_template.md +22 -0
- data/.github/workflows/gem-push.yml +44 -0
- data/.github/workflows/ruby.yml +34 -0
- data/.gitignore +1 -0
- data/.rubocop.yml +6 -2
- data/.ruby-version +1 -1
- data/CHANGELOG.md +18 -0
- data/CONTRIBUTING.md +1 -0
- data/README.md +1 -3
- data/bin/console +1 -4
- data/bin/setup +0 -2
- data/lib/zerobounce.rb +1 -5
- data/lib/zerobounce/configuration.rb +6 -0
- data/lib/zerobounce/error.rb +18 -14
- data/lib/zerobounce/middleware/raise_error.rb +1 -1
- data/lib/zerobounce/request.rb +15 -37
- data/lib/zerobounce/request/v1_request.rb +47 -0
- data/lib/zerobounce/request/v2_request.rb +32 -0
- data/lib/zerobounce/response.rb +12 -98
- data/lib/zerobounce/response/v1_response.rb +104 -0
- data/lib/zerobounce/response/v2_response.rb +97 -0
- data/lib/zerobounce/version.rb +1 -1
- data/zerobounce.gemspec +15 -11
- metadata +73 -29
- data/.circleci/config.yml +0 -136
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Zerobounce
|
4
|
+
class Request
|
5
|
+
# Request methods specific to V1 of the API.
|
6
|
+
module V1Request
|
7
|
+
# Valid v1 get query params
|
8
|
+
VALID_GET_PARAMS = %i[apikey ipaddress email].freeze
|
9
|
+
|
10
|
+
# Validate the email address.
|
11
|
+
#
|
12
|
+
# @param [Hash] params
|
13
|
+
# @option params [String] :email
|
14
|
+
# @option params [String] :ip_address
|
15
|
+
# @option params [String] :apikey
|
16
|
+
# @return [Zerobounce::Response]
|
17
|
+
def validate(params)
|
18
|
+
if params.key?(:ipaddress) || params.key?(:ip_address)
|
19
|
+
validate_with_ip(params)
|
20
|
+
else
|
21
|
+
Response.new(get('validate', params), self)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Validate the email address and get geoip info for the IP.
|
26
|
+
#
|
27
|
+
# @param [Hash] params
|
28
|
+
# @option params [String] :email
|
29
|
+
# @option params [String] :ip_address
|
30
|
+
# @option params [String] :apikey
|
31
|
+
# @return [Zerobounce::Response]
|
32
|
+
def validate_with_ip(params)
|
33
|
+
Response.new(get('validatewithip', params), self)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
# @param [Hash] params
|
39
|
+
# @return [Hash]
|
40
|
+
def get_params(params)
|
41
|
+
params[:ipaddress] = params.delete(:ip_address) if params.key?(:ip_address) # normalize ipaddress key
|
42
|
+
params[:apikey] = params.delete(:api_key) if params.key?(:api_key) # normalize apikey param
|
43
|
+
{ apikey: Zerobounce.config.apikey }.merge(params.select { |k, _| VALID_GET_PARAMS.include?(k) })
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Zerobounce
|
4
|
+
class Request
|
5
|
+
# Request methods specific to V2 of the API.
|
6
|
+
module V2Request
|
7
|
+
# Valid v2 query params
|
8
|
+
VALID_GET_PARAMS = %i[api_key ip_address email].freeze
|
9
|
+
|
10
|
+
# Validate the email address.
|
11
|
+
#
|
12
|
+
# @param [Hash] params
|
13
|
+
# @option params [String] :email
|
14
|
+
# @option params [String] :ip_address
|
15
|
+
# @option params [String] :api_key
|
16
|
+
# @return [Zerobounce::Response]
|
17
|
+
def validate(params)
|
18
|
+
Response.new(get('validate', params), self)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
# @param [Hash] params
|
24
|
+
# @return [Hash]
|
25
|
+
def get_params(params)
|
26
|
+
params[:ip_address] ||= '' # ip_address must be in query string
|
27
|
+
params[:api_key] = params.delete(:apikey) if params.key?(:apikey) # normalize api_key param
|
28
|
+
{ api_key: Zerobounce.config.apikey }.merge(params.select { |k, _| VALID_GET_PARAMS.include?(k) })
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/zerobounce/response.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'time'
|
4
|
+
require 'zerobounce/response/v1_response'
|
5
|
+
require 'zerobounce/response/v2_response'
|
4
6
|
|
5
7
|
module Zerobounce
|
6
8
|
# A Zerobounce response
|
@@ -11,62 +13,24 @@ module Zerobounce
|
|
11
13
|
# The request instance.
|
12
14
|
#
|
13
15
|
# @attr_reader [Faraday::Response] response
|
14
|
-
# The original {https://www.rubydoc.info/gems/faraday/
|
16
|
+
# The original {https://www.rubydoc.info/gems/faraday/1.4.2/Faraday/Response Faraday::Response}
|
15
17
|
class Response
|
16
18
|
attr_reader :response
|
17
19
|
attr_reader :request
|
18
20
|
|
19
21
|
# @param [Faraday::Response] response
|
20
|
-
# @param [Zerobounce::Request] request
|
22
|
+
# @param [Zerobounce::Request::V2Response, Zerobounce::Request::V1Response] request
|
21
23
|
def initialize(response, request)
|
22
24
|
@response = response
|
23
25
|
@request = request
|
24
26
|
@body = response.body
|
25
|
-
end
|
26
|
-
|
27
|
-
# Deliverability status
|
28
|
-
#
|
29
|
-
# Possible values:
|
30
|
-
# :valid
|
31
|
-
# :invalid
|
32
|
-
# :catch_all
|
33
|
-
# :unknown
|
34
|
-
# :spamtrap
|
35
|
-
# :abuse
|
36
|
-
# :do_not_mail
|
37
|
-
#
|
38
|
-
# @return [Symbol] The status as a +Symbol+.
|
39
|
-
def status
|
40
|
-
@status ||= underscore(@body[:status])&.to_sym
|
41
|
-
end
|
42
27
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
# :forcible_disconnect
|
50
|
-
# :mail_server_did_not_respond
|
51
|
-
# :timeout_exceeded
|
52
|
-
# :failed_smtp_connection
|
53
|
-
# :mailbox_quota_exceeded
|
54
|
-
# :exception_occurred
|
55
|
-
# :possible_traps
|
56
|
-
# :role_based
|
57
|
-
# :global_suppression
|
58
|
-
# :mailbox_not_found
|
59
|
-
# :no_dns_entries
|
60
|
-
# :failed_syntax_check
|
61
|
-
# :possible_typo
|
62
|
-
# :unroutable_ip_address
|
63
|
-
# :leading_period_removed
|
64
|
-
# :does_not_accept_mail
|
65
|
-
# :alias_address
|
66
|
-
#
|
67
|
-
# @return [Symbol] The sub_status as a +Symbol+.
|
68
|
-
def sub_status
|
69
|
-
@sub_status ||= underscore(@body[:sub_status])&.to_sym
|
28
|
+
case request.api_version
|
29
|
+
when 'v2'
|
30
|
+
extend(V2Response)
|
31
|
+
else
|
32
|
+
extend(V1Response)
|
33
|
+
end
|
70
34
|
end
|
71
35
|
|
72
36
|
# The email address you are validating.
|
@@ -111,13 +75,6 @@ module Zerobounce
|
|
111
75
|
@gender ||= @body[:gender]
|
112
76
|
end
|
113
77
|
|
114
|
-
# The location of the owner of the email when available.
|
115
|
-
#
|
116
|
-
# @return [String, nil]
|
117
|
-
def location
|
118
|
-
@location ||= @body[:location]
|
119
|
-
end
|
120
|
-
|
121
78
|
# The country of the IP passed in.
|
122
79
|
#
|
123
80
|
# @return [String, nil]
|
@@ -162,48 +119,13 @@ module Zerobounce
|
|
162
119
|
!valid?
|
163
120
|
end
|
164
121
|
|
165
|
-
# If the email domain is disposable, which are usually temporary email addresses.
|
166
|
-
#
|
167
|
-
# These are temporary emails created for the sole purpose to sign up to websites without giving their real
|
168
|
-
# email address. These emails are short lived from 15 minutes to around 6 months.
|
169
|
-
#
|
170
|
-
# @note If you have valid emails with this flag set to +true+, you shouldn't email them.
|
171
|
-
#
|
172
|
-
# @return [Boolean]
|
173
|
-
def disposable?
|
174
|
-
@disposable ||= @body[:disposable] || false
|
175
|
-
end
|
176
|
-
|
177
|
-
# These domains are known for abuse, spam, or are bot created.
|
178
|
-
#
|
179
|
-
# @note If you have a valid email with this flag set to +true+, you shouldn't email them.
|
180
|
-
#
|
181
|
-
# @return [Boolean]
|
182
|
-
def toxic?
|
183
|
-
@toxic ||= @body[:toxic] || false
|
184
|
-
end
|
185
|
-
|
186
|
-
# The UTC time the email was validated.
|
187
|
-
#
|
188
|
-
# @return [Time, nil]
|
189
|
-
def process_date
|
190
|
-
@process_date ||= @body[:processedat] && Time.parse(@body[:processedat])
|
191
|
-
end
|
192
|
-
|
193
|
-
# The creation date of the email when available.
|
194
|
-
#
|
195
|
-
# @return [Time, nil]
|
196
|
-
def creation_date
|
197
|
-
@creation_date ||= @body[:creationdate] && Time.parse(@body[:creationdate])
|
198
|
-
end
|
199
|
-
|
200
122
|
# Returns a string containing a human-readable representation.
|
201
123
|
#
|
202
124
|
# @note Overriding inspect to hide the {#request}/{#response} instance variables
|
203
125
|
#
|
204
126
|
# @return [String]
|
205
127
|
def inspect
|
206
|
-
"#<#{self.class.name}
|
128
|
+
"#<#{self.class.name}:0x#{object_id.to_s(16)} @address=#{address}>"
|
207
129
|
end
|
208
130
|
|
209
131
|
# Convert to a hash.
|
@@ -212,17 +134,9 @@ module Zerobounce
|
|
212
134
|
def to_h
|
213
135
|
public_methods(false).each_with_object({}) do |meth, memo|
|
214
136
|
next if %i[request response inspect to_h].include?(meth)
|
137
|
+
|
215
138
|
memo[meth] = send(meth)
|
216
139
|
end
|
217
140
|
end
|
218
|
-
|
219
|
-
private
|
220
|
-
|
221
|
-
# @param [String, nil] word
|
222
|
-
# @return [String, nil]
|
223
|
-
def underscore(word)
|
224
|
-
return if word.nil? || word.empty?
|
225
|
-
word.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase.tr('-', '_')
|
226
|
-
end
|
227
141
|
end
|
228
142
|
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Zerobounce
|
4
|
+
class Response
|
5
|
+
# V1 specific methods for the API.
|
6
|
+
module V1Response
|
7
|
+
# Deliverability status
|
8
|
+
#
|
9
|
+
# Possible values:
|
10
|
+
# :valid
|
11
|
+
# :invalid
|
12
|
+
# :catch_all
|
13
|
+
# :unknown
|
14
|
+
# :spamtrap
|
15
|
+
# :abuse
|
16
|
+
# :do_not_mail
|
17
|
+
#
|
18
|
+
# @return [Symbol] The status as a +Symbol+.
|
19
|
+
def status
|
20
|
+
@status ||= @body[:status].to_s.empty? ? nil : underscore(@body[:status]).to_sym
|
21
|
+
end
|
22
|
+
|
23
|
+
# A more detailed status
|
24
|
+
#
|
25
|
+
# Possible values:
|
26
|
+
# :antispam_system
|
27
|
+
# :greylisted
|
28
|
+
# :mail_server_temporary_error
|
29
|
+
# :forcible_disconnect
|
30
|
+
# :mail_server_did_not_respond
|
31
|
+
# :timeout_exceeded
|
32
|
+
# :failed_smtp_connection
|
33
|
+
# :mailbox_quota_exceeded
|
34
|
+
# :exception_occurred
|
35
|
+
# :possible_traps
|
36
|
+
# :role_based
|
37
|
+
# :global_suppression
|
38
|
+
# :mailbox_not_found
|
39
|
+
# :no_dns_entries
|
40
|
+
# :failed_syntax_check
|
41
|
+
# :possible_typo
|
42
|
+
# :unroutable_ip_address
|
43
|
+
# :leading_period_removed
|
44
|
+
# :does_not_accept_mail
|
45
|
+
# :alias_address
|
46
|
+
# :unknown
|
47
|
+
#
|
48
|
+
# @return [Symbol] The sub_status as a +Symbol+.
|
49
|
+
def sub_status
|
50
|
+
@sub_status ||= @body[:sub_status].to_s.empty? ? nil : underscore(@body[:sub_status]).to_sym
|
51
|
+
end
|
52
|
+
|
53
|
+
# If the email domain is disposable, which are usually temporary email addresses.
|
54
|
+
#
|
55
|
+
# These are temporary emails created for the sole purpose to sign up to websites without giving their real
|
56
|
+
# email address. These emails are short lived from 15 minutes to around 6 months.
|
57
|
+
#
|
58
|
+
# @note If you have valid emails with this flag set to +true+, you shouldn't email them.
|
59
|
+
#
|
60
|
+
# @return [Boolean]
|
61
|
+
def disposable?
|
62
|
+
@disposable ||= @body[:disposable] || false
|
63
|
+
end
|
64
|
+
|
65
|
+
# These domains are known for abuse, spam, or are bot created.
|
66
|
+
#
|
67
|
+
# @note If you have a valid email with this flag set to +true+, you shouldn't email them.
|
68
|
+
#
|
69
|
+
# @return [Boolean]
|
70
|
+
def toxic?
|
71
|
+
@toxic ||= @body[:toxic] || false
|
72
|
+
end
|
73
|
+
|
74
|
+
# The location of the owner of the email when available.
|
75
|
+
#
|
76
|
+
# @return [String, nil]
|
77
|
+
def location
|
78
|
+
@location ||= @body[:location]
|
79
|
+
end
|
80
|
+
|
81
|
+
# The UTC time the email was validated.
|
82
|
+
#
|
83
|
+
# @return [Time, nil]
|
84
|
+
def processed_at
|
85
|
+
@processed_at ||= @body[:processedat] && Time.parse("#{@body[:processedat]} UTC")
|
86
|
+
end
|
87
|
+
|
88
|
+
# The creation date of the email when available.
|
89
|
+
#
|
90
|
+
# @return [Time, nil]
|
91
|
+
def creation_date
|
92
|
+
@creation_date ||= @body[:creationdate] && Time.parse("#{@body[:creationdate]} UTC")
|
93
|
+
end
|
94
|
+
|
95
|
+
private
|
96
|
+
|
97
|
+
# @param [String] word
|
98
|
+
# @return [String]
|
99
|
+
def underscore(word)
|
100
|
+
word.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase.tr('-', '_')
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,97 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Zerobounce
|
4
|
+
class Response
|
5
|
+
# V2 specific methods for the API.
|
6
|
+
module V2Response
|
7
|
+
# Deliverability status
|
8
|
+
#
|
9
|
+
# @see https://www.zerobounce.net/docs/email-validation-api-quickstart/#status_codes__v2__
|
10
|
+
#
|
11
|
+
# Possible values:
|
12
|
+
# :valid
|
13
|
+
# :invalid
|
14
|
+
# :catch_all
|
15
|
+
# :unknown
|
16
|
+
# :spamtrap
|
17
|
+
# :abuse
|
18
|
+
# :do_not_mail
|
19
|
+
#
|
20
|
+
# @return [Symbol, nil] The status as a +Symbol+.
|
21
|
+
def status
|
22
|
+
@status ||= @body[:status].to_s.empty? ? nil : @body[:status].tr('-', '_').to_sym
|
23
|
+
end
|
24
|
+
|
25
|
+
# @return [Symbol, nil]
|
26
|
+
def sub_status
|
27
|
+
@sub_status ||= @body[:sub_status].to_s.empty? ? nil : @body[:sub_status].to_sym
|
28
|
+
end
|
29
|
+
|
30
|
+
# @return [Integer]
|
31
|
+
def domain_age_days
|
32
|
+
@domain_age_days ||= @body[:domain_age_days].to_i
|
33
|
+
end
|
34
|
+
|
35
|
+
# The SMTP Provider of the email.
|
36
|
+
#
|
37
|
+
# @return [String, nil]
|
38
|
+
def smtp_provider
|
39
|
+
@smtp_provider ||= @body[:smtp_provider]
|
40
|
+
end
|
41
|
+
|
42
|
+
# @return [String, nil]
|
43
|
+
def did_you_mean
|
44
|
+
@did_you_mean ||= @body[:did_you_mean]
|
45
|
+
end
|
46
|
+
|
47
|
+
# The preferred MX record of the domain.
|
48
|
+
#
|
49
|
+
# @return [String, nil]
|
50
|
+
def mx_record
|
51
|
+
@mx_record ||= @body[:mx_record]
|
52
|
+
end
|
53
|
+
|
54
|
+
# The UTC time the email was validated.
|
55
|
+
#
|
56
|
+
# @return [Time, nil]
|
57
|
+
def processed_at
|
58
|
+
@processed_at ||= @body[:processed_at] && Time.parse("#{@body[:processed_at]} UTC")
|
59
|
+
end
|
60
|
+
|
61
|
+
# If the email comes from a free provider.
|
62
|
+
#
|
63
|
+
# @return [Boolean]
|
64
|
+
def free_email?
|
65
|
+
@free_email ||= @body[:free_email] || false
|
66
|
+
end
|
67
|
+
|
68
|
+
# If the email domain is disposable, which are usually temporary email addresses.
|
69
|
+
#
|
70
|
+
# These are temporary emails created for the sole purpose to sign up to websites without giving their real
|
71
|
+
# email address. These emails are short lived from 15 minutes to around 6 months.
|
72
|
+
#
|
73
|
+
# @note If you have valid emails with this flag set to +true+, you shouldn't email them.
|
74
|
+
#
|
75
|
+
# @return [Boolean]
|
76
|
+
def disposable?
|
77
|
+
@disposable ||= sub_status == :disposable
|
78
|
+
end
|
79
|
+
|
80
|
+
# These domains are known for abuse, spam, or are bot created.
|
81
|
+
#
|
82
|
+
# @note If you have a valid email with this flag set to +true+, you shouldn't email them.
|
83
|
+
#
|
84
|
+
# @return [Boolean]
|
85
|
+
def toxic?
|
86
|
+
@toxic ||= sub_status == :toxic
|
87
|
+
end
|
88
|
+
|
89
|
+
# Does the domain have an MX record.
|
90
|
+
#
|
91
|
+
# @return [Boolean]
|
92
|
+
def mx_found?
|
93
|
+
@mx_found ||= @body[:mx_found] == 'true'
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
data/lib/zerobounce/version.rb
CHANGED