emailable 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 0e7635cc0f814700d29137678bd7b53fd91f07f042ff5435b8777cc269a51fb6
4
+ data.tar.gz: 808f71d2c343495ad48143230d1daa11ba59e334d75a242d25df637abd446b51
5
+ SHA512:
6
+ metadata.gz: 8a78fd0ab06eca710c67e2e8c01142d0a4bfdfa19f7357c9f54b7a8d53eddaf7b29f32ded7ad85145f414e95782a61dd4774d0a39821f2194f0228b9b402b6c4
7
+ data.tar.gz: 99f27b66dc848815689fe3a0869b2b47a0f412c3305b910a044488b65598161a8349f690b5772d4e5181e97a4c55fa794f9593d3fa4b60bca5d5ad9a99b84530
data/.gitignore ADDED
@@ -0,0 +1,8 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
data/.ruby-gemset ADDED
@@ -0,0 +1 @@
1
+ emailable-ruby
data/.ruby-version ADDED
@@ -0,0 +1 @@
1
+ 2.6.5
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ sudo: false
3
+ language: ruby
4
+ cache: bundler
5
+ rvm:
6
+ - 2.6.3
7
+ before_install: gem install bundler -v 1.17.3
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "https://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in emailable-ruby.gemspec
4
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,70 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ emailable (3.0.0)
5
+ faraday
6
+ faraday_middleware
7
+ net-http-persistent
8
+
9
+ GEM
10
+ remote: https://rubygems.org/
11
+ specs:
12
+ activemodel (6.0.3.4)
13
+ activesupport (= 6.0.3.4)
14
+ activesupport (6.0.3.4)
15
+ concurrent-ruby (~> 1.0, >= 1.0.2)
16
+ i18n (>= 0.7, < 2)
17
+ minitest (~> 5.1)
18
+ tzinfo (~> 1.1)
19
+ zeitwerk (~> 2.2, >= 2.2.2)
20
+ ansi (1.5.0)
21
+ awesome_print (1.8.0)
22
+ builder (3.2.3)
23
+ coderay (1.1.2)
24
+ concurrent-ruby (1.1.7)
25
+ connection_pool (2.2.3)
26
+ faraday (1.3.0)
27
+ faraday-net_http (~> 1.0)
28
+ multipart-post (>= 1.2, < 3)
29
+ ruby2_keywords
30
+ faraday-net_http (1.0.1)
31
+ faraday_middleware (1.0.0)
32
+ faraday (~> 1.0)
33
+ i18n (1.8.5)
34
+ concurrent-ruby (~> 1.0)
35
+ method_source (0.9.2)
36
+ minitest (5.11.3)
37
+ minitest-reporters (1.3.6)
38
+ ansi
39
+ builder
40
+ minitest (>= 5.0)
41
+ ruby-progressbar
42
+ multipart-post (2.1.1)
43
+ net-http-persistent (4.0.1)
44
+ connection_pool (~> 2.2)
45
+ pry (0.12.2)
46
+ coderay (~> 1.1.0)
47
+ method_source (~> 0.9.0)
48
+ rake (13.0.1)
49
+ ruby-progressbar (1.10.1)
50
+ ruby2_keywords (0.0.4)
51
+ thread_safe (0.3.6)
52
+ tzinfo (1.2.8)
53
+ thread_safe (~> 0.1)
54
+ zeitwerk (2.4.1)
55
+
56
+ PLATFORMS
57
+ ruby
58
+
59
+ DEPENDENCIES
60
+ activemodel
61
+ awesome_print
62
+ bundler
63
+ emailable!
64
+ minitest (~> 5.0)
65
+ minitest-reporters
66
+ pry
67
+ rake (~> 13.0)
68
+
69
+ BUNDLED WITH
70
+ 1.17.3
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2019 Emailable. https://emailable.com
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,135 @@
1
+ # Emailable Ruby Library
2
+
3
+ [![Build Status](https://travis-ci.com/emailable/emailable-ruby.svg)](https://travis-ci.com/emailable/emailable-ruby)
4
+ [![Maintainability](https://api.codeclimate.com/v1/badges/2d74c69a9155109058a7/maintainability)](https://codeclimate.com/github/emailable/emailable-ruby/maintainability)
5
+
6
+ This is the official ruby wrapper for the Emailable API.
7
+
8
+ It also includes an Active Record (Rails) validator to verify email attributes.
9
+
10
+ ## Documentation
11
+
12
+ See the [Ruby API docs](https://emailable.com/docs/api/?ruby).
13
+
14
+ ## Installation
15
+
16
+ Add this line to your application's Gemfile:
17
+
18
+ ```ruby
19
+ gem 'emailable'
20
+ ```
21
+
22
+ And then execute:
23
+
24
+ $ bundle
25
+
26
+ Or install it yourself as:
27
+
28
+ $ gem install emailable
29
+
30
+ ## Usage
31
+
32
+ The library needs to be configured with your account's API key which is available in your [Emailable Dashboard](https://app.emailable.com/api). Set `Emailable.api_key` to its value:
33
+
34
+ ### Setup
35
+
36
+ ```ruby
37
+ require 'emailable'
38
+
39
+ # set api key
40
+ Emailable.api_key = 'live_...'
41
+ ```
42
+
43
+ ### Verification
44
+
45
+ ```ruby
46
+ # verify an email address
47
+ Emailable.verify('jarrett@emailable.com')
48
+ ```
49
+
50
+ #### Slow Email Server Handling
51
+
52
+ Some email servers are slow to respond. As a result, the timeout may be reached
53
+ before we are able to complete the verification process. If this happens, the
54
+ verification will continue in the background on our servers, and a
55
+ `Emailable::TimeoutError` will be raised. We recommend sleeping for at least
56
+ one second and trying your request again. Re-requesting the same verification
57
+ with the same options will not impact your credit allocation within a 5 minute
58
+ window. You can test this behavior using a test key and the special
59
+ email `slow@example.com`.
60
+
61
+ ### Batch Verification
62
+
63
+ #### Start a batch
64
+
65
+ ```ruby
66
+ emails = ['jarrett@emailable.com', 'support@emailable.com', ...]
67
+ batch = Emailable::Batch.new(emails)
68
+
69
+ # you can optionally pass in a callback url that we'll POST to when the
70
+ # batch is complete.
71
+ batch = Emailable::Batch.new(emails, callback: 'https://emailable.com/')
72
+
73
+ # start verifying the batch
74
+ batch.verify
75
+ ```
76
+
77
+ #### Get the status / results of a batch
78
+
79
+ Calling `status` on a batch will return the status. It will contain the results as well once complete. You can also `results` to get just the results.
80
+
81
+ ```ruby
82
+ id = '5cfcbfdeede34200693c4319'
83
+ batch = Emailable::Batch.new(id)
84
+
85
+ # get status of batch
86
+ batch.status
87
+
88
+ # gets the results
89
+ batch.status.emails
90
+
91
+ # get the counts
92
+ batch.status.total_counts
93
+ batch.status.reason_counts
94
+
95
+ # returns true / false
96
+ batch.complete?
97
+ ```
98
+
99
+ ### Active Record Validator
100
+
101
+ Define a validator on an Active Record model for your email attribute(s).
102
+ It'll validate the attribute only when it's present and has changed.
103
+
104
+ #### Options
105
+
106
+ * `smtp`, `timeout`: Passed directly to API as options.
107
+ * `states`: An array of states you'd like to be considered valid.
108
+ * `free`, `role`, `disposable`, `accept_all`: If you'd like any of these to be valid.
109
+
110
+ ```ruby
111
+ validates :email, email: {
112
+ smtp: true, states: %i[deliverable risky unknown],
113
+ free: true, role: true, disposable: false, accept_all: true, timeout: 3
114
+ }
115
+ ```
116
+
117
+ #### Access Verification Result
118
+
119
+ You can define an `attr_accessor` with the following format to gain
120
+ access to the verification result.
121
+
122
+ ```ruby
123
+ # [attribute_name]_verification_result
124
+ attr_accessor :email_verification_result
125
+ ```
126
+
127
+ ## Development
128
+
129
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
130
+
131
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
132
+
133
+ ## Contributing
134
+
135
+ Bug reports and pull requests are welcome on GitHub at https://github.com/emailable/emailable-ruby.
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rake/testtask'
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << 'test'
6
+ t.libs << 'lib'
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task :default => :test
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "emailable/ruby"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start(__FILE__)
data/bin/setup ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,10 @@
1
+ en:
2
+ errors:
3
+ messages:
4
+ undeliverable: is undeliverable
5
+ risky: is risky
6
+ unknown: is unknown
7
+ free: is a free address
8
+ role: is a role address
9
+ disposable: is a disposable address
10
+ accept_all: is an accept-all address
data/emailable.gemspec ADDED
@@ -0,0 +1,40 @@
1
+ # frozen_string_literal: true
2
+
3
+ $LOAD_PATH.unshift(::File.join(::File.dirname(__FILE__), 'lib'))
4
+
5
+ require 'emailable/version'
6
+
7
+ Gem::Specification.new do |s|
8
+ s.name = 'emailable'
9
+ s.version = Emailable::VERSION
10
+ s.summary = 'Ruby bindings for the Emailable API'
11
+ s.description = 'Email Verification that’s astonishingly easy and low-cost. '\
12
+ 'See https://emailable.com for details.'
13
+ s.homepage = 'https://emailable.com'
14
+ s.author = 'Emailable'
15
+ s.email = 'support@emailable.com'
16
+ s.license = 'MIT'
17
+ s.metadata = {
18
+ "bug_tracker_uri" => "https://github.com/emailable/emailable-ruby/issues",
19
+ "documentation_uri" => "https://docs.emailable.com/?ruby",
20
+ "source_code_uri" => "https://github.com/emailable/emailable-ruby"
21
+ }
22
+
23
+ s.files = `git ls-files`.split("\n")
24
+ s.test_files = `git ls-files -- test/*`.split("\n")
25
+ s.executables = `git ls-files -- bin/*`.split("\n").map do |f|
26
+ ::File.basename(f)
27
+ end
28
+ s.require_paths = ['lib']
29
+
30
+ s.add_dependency 'faraday'
31
+ s.add_dependency 'faraday_middleware'
32
+ s.add_dependency 'net-http-persistent'
33
+ s.add_development_dependency 'bundler'
34
+ s.add_development_dependency 'rake', '~> 13.0'
35
+ s.add_development_dependency 'pry'
36
+ s.add_development_dependency 'awesome_print'
37
+ s.add_development_dependency 'minitest', '~> 5.0'
38
+ s.add_development_dependency 'minitest-reporters'
39
+ s.add_development_dependency 'activemodel'
40
+ end
@@ -0,0 +1,51 @@
1
+ module Emailable
2
+ class Batch
3
+ attr_accessor :id
4
+
5
+ def initialize(id_or_emails, callback: nil)
6
+ if id_or_emails.is_a?(Array)
7
+ @emails = id_or_emails
8
+ @callback = callback
9
+ elsif id_or_emails.is_a?(String)
10
+ @id = id_or_emails
11
+ else
12
+ raise ArgumentError, 'expected an array of emails or batch id'
13
+ end
14
+
15
+ @client = Emailable::Client.new
16
+ end
17
+
18
+ def verify
19
+ return @id unless @id.nil?
20
+
21
+ opts = { emails: @emails.join(','), url: @callback }
22
+ response = @client.request(:post, 'batch', opts)
23
+
24
+ @id = response.body['id']
25
+ end
26
+
27
+ def status
28
+ return nil unless @id
29
+ return @status if @status
30
+
31
+ response = @client.request(:get, 'batch', { id: @id })
32
+ bs = BatchStatus.new(response.body)
33
+ @status = bs if bs.complete?
34
+
35
+ bs
36
+ end
37
+
38
+ def complete?
39
+ !status.complete?
40
+ end
41
+
42
+ def inspect
43
+ ivars = instance_variables.map do |e|
44
+ [e.to_s.delete('@'), instance_variable_get(e)]
45
+ end.to_h
46
+ "#<#{self.class}:0x#{(object_id << 1).to_s(16)}> JSON: " +
47
+ JSON.pretty_generate(ivars)
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,70 @@
1
+ module Emailable
2
+ class Client
3
+
4
+ def initialize
5
+ @client = Faraday.new('https://api.emailable.com/v1') do |f|
6
+ f.request :url_encoded
7
+ f.response :json, content_type: /\bjson$/
8
+ f.adapter :net_http_persistent
9
+ end
10
+ end
11
+
12
+ def request(method, endpoint, opts = {})
13
+ begin
14
+ tries ||= 0
15
+
16
+ @client.params[:api_key] = Emailable.api_key
17
+
18
+ response =
19
+ if method == :get
20
+ @client.get(endpoint, opts)
21
+ elsif method == :post
22
+ @client.post(endpoint, opts)
23
+ end
24
+ rescue => e
25
+ retry if self.class.should_retry?(e, tries)
26
+
27
+ raise e
28
+ end
29
+
30
+ status = response.status
31
+ return response if status.between?(200, 299)
32
+
33
+ error_attributes = {
34
+ message: response.body['message'],
35
+ code: status
36
+ }
37
+ error_map = {
38
+ '400' => BadRequestError,
39
+ '401' => UnauthorizedError,
40
+ '402' => PaymentRequiredError,
41
+ '403' => ForbiddenError,
42
+ '404' => NotFoundError,
43
+ '429' => TooManyRequestsError,
44
+ '500' => InternalServerError,
45
+ '503' => ServiceUnavailableError
46
+ }
47
+
48
+ raise error_map[status.to_s].new(error_attributes)
49
+ end
50
+
51
+ def self.should_retry?(error, num_retries)
52
+ return false if num_retries >= Emailable.max_network_retries
53
+
54
+ # Retry on timeout-related problems (either on open or read).
55
+ return true if error.is_a?(Faraday::TimeoutError)
56
+
57
+ # Destination refused the connection, the connection was reset, or a
58
+ # variety of other connection failures. This could occur from a single
59
+ # saturated server, so retry in case it's intermittent.
60
+ return true if error.is_a?(Faraday::ConnectionFailed)
61
+
62
+ if error.is_a?(Faraday::ClientError) && error.response
63
+ # 409 conflict
64
+ return true if error.response[:status] == 409
65
+ end
66
+
67
+ false
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,70 @@
1
+ # ActiveRecord validator for validating an email address with Emailable
2
+ #
3
+ # Usage:
4
+ # validates :email, presence: true, email: {
5
+ # smtp: true, states: %i[deliverable risky unknown],
6
+ # free: true, role: true, disposable: false, accept_all: true,
7
+ # timeout: 3
8
+ # }
9
+ #
10
+ # Define an attr_accessor to access verification results.
11
+ # attr_accessor :email_verification_result
12
+ #
13
+ class EmailValidator < ActiveModel::EachValidator
14
+
15
+ def validate_each(record, attribute, value)
16
+ smtp = boolean_option_or_raise_error(:smtp, true)
17
+
18
+ states = options.fetch(:states, %i(deliverable risky unknown))
19
+ allowed_states = %i[deliverable undeliverable risky unknown]
20
+ unless (states - allowed_states).empty?
21
+ raise ArgumentError, ":states must be an array of symbols containing "\
22
+ "any or all of :#{allowed_states.join(', :')}"
23
+ end
24
+
25
+ free = boolean_option_or_raise_error(:free, true)
26
+ role = boolean_option_or_raise_error(:role, true)
27
+ disposable = boolean_option_or_raise_error(:disposable, false)
28
+ accept_all = boolean_option_or_raise_error(:accept_all, true)
29
+
30
+ timeout = options.fetch(:timeout, 3)
31
+ unless timeout.is_a?(Integer) && timeout > 1
32
+ raise ArgumentError, ":timeout must be an Integer greater than 1"
33
+ end
34
+
35
+ return if record.errors[attribute].present?
36
+ return unless value.present?
37
+ return unless record.changes.include?(attribute.to_sym)
38
+
39
+ api_options = { timeout: timeout, smtp: smtp }
40
+ api_options[:accept_all] = true unless accept_all
41
+ ev = Emailable.verify(value, api_options)
42
+
43
+ result_accessor = "#{attribute}_verification_result"
44
+ if record.respond_to?(result_accessor)
45
+ record.instance_variable_set("@#{result_accessor}", ev)
46
+ end
47
+
48
+ error ||= ev.state.to_sym unless states.include?(ev.state.to_sym)
49
+ error ||= :free if ev.free? && !free
50
+ error ||= :role if ev.role? && !role
51
+ error ||= :disposable if ev.disposable? && !disposable
52
+ error ||= :accept_all if ev.accept_all? && !accept_all
53
+
54
+ record.errors.add(attribute, error) if error
55
+ rescue Emailable::Error
56
+ # silence errors
57
+ end
58
+
59
+ private
60
+
61
+ def boolean_option_or_raise_error(name, default)
62
+ option = options.fetch(name, default)
63
+ unless [true, false].include?(option)
64
+ raise ArgumentError, ":#{name} must by a Boolean"
65
+ end
66
+
67
+ option
68
+ end
69
+
70
+ end
@@ -0,0 +1,5 @@
1
+ module Emailable
2
+ class Account < APIResource
3
+ attr_accessor :owner_email, :available_credits
4
+ end
5
+ end
@@ -0,0 +1,20 @@
1
+ module Emailable
2
+ class APIResource
3
+
4
+ def initialize(attributes = {})
5
+ attributes.each do |attr, value|
6
+ instance_variable_set("@#{attr}", value)
7
+ end
8
+ end
9
+
10
+ def inspect
11
+ ivars = instance_variables.map do |e|
12
+ [e.to_s.delete('@'), instance_variable_get(e)]
13
+ end.to_h
14
+ fmtted_email = @email ? " #{@email}" : ''
15
+ "#<#{self.class}:0x#{(object_id << 1).to_s(16)}#{fmtted_email}> JSON: " +
16
+ JSON.pretty_generate(ivars)
17
+ end
18
+
19
+ end
20
+ end
@@ -0,0 +1,10 @@
1
+ module Emailable
2
+ class BatchStatus < APIResource
3
+ attr_accessor :emails, :id, :message, :reason_counts, :total_counts,
4
+ :processed, :total
5
+
6
+ def complete?
7
+ !emails.nil?
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,15 @@
1
+ module Emailable
2
+ class Verification < APIResource
3
+ attr_accessor :accept_all, :did_you_mean, :disposable, :domain, :duration,
4
+ :email, :free, :mx_record, :reason, :role, :score,
5
+ :smtp_provider, :state, :tag, :user, :first_name, :last_name,
6
+ :full_name, :gender
7
+
8
+ %w(accept_all disposable free role).each do |method|
9
+ define_method("#{method}?") do
10
+ instance_variable_get "@#{method}"
11
+ end
12
+ end
13
+
14
+ end
15
+ end
@@ -0,0 +1,3 @@
1
+ module Emailable
2
+ VERSION = '3.0.1'
3
+ end
data/lib/emailable.rb ADDED
@@ -0,0 +1,65 @@
1
+ require 'faraday'
2
+ require 'faraday_middleware'
3
+ require 'emailable/version'
4
+ require 'emailable/client'
5
+ require 'emailable/batch'
6
+ require 'emailable/resources/api_resource'
7
+ require 'emailable/resources/account'
8
+ require 'emailable/resources/batch_status'
9
+ require 'emailable/resources/verification'
10
+ if defined?(ActiveModel)
11
+ require 'emailable/email_validator'
12
+ I18n.load_path += Dir.glob(File.expand_path('../../config/locales/**/*', __FILE__))
13
+ end
14
+
15
+ module Emailable
16
+ @max_network_retries = 1
17
+
18
+ class << self
19
+ attr_accessor :api_key, :max_network_retries
20
+ end
21
+
22
+ module_function
23
+
24
+ def verify(email, smtp: nil, accept_all: nil, timeout: nil)
25
+ opts = {
26
+ email: email, smtp: smtp, accept_all: accept_all, timeout: timeout
27
+ }
28
+
29
+ client = Emailable::Client.new
30
+ response = client.request(:get, 'verify', opts)
31
+
32
+ if response.status == 249
33
+ raise Emailable::TimeoutError.new(
34
+ code: response.status, message: response.body
35
+ )
36
+ else
37
+ Verification.new(response.body)
38
+ end
39
+ end
40
+
41
+ def account
42
+ client = Emailable::Client.new
43
+ response = client.request(:get, 'account')
44
+ Account.new(response.body)
45
+ end
46
+
47
+
48
+ class Error < StandardError
49
+ attr_accessor :code, :message
50
+
51
+ def initialize(code: nil, message: nil)
52
+ @code = code
53
+ @message = message
54
+ end
55
+ end
56
+ class BadRequestError < Error; end
57
+ class UnauthorizedError < Error; end
58
+ class PaymentRequiredError < Error; end
59
+ class ForbiddenError < Error; end
60
+ class NotFoundError < Error; end
61
+ class TooManyRequestsError < Error; end
62
+ class InternalServerError < Error; end
63
+ class ServiceUnavailableError < Error; end
64
+ class TimeoutError < Error; end
65
+ end
@@ -0,0 +1,85 @@
1
+ require 'test_helper'
2
+
3
+ class EmailValidatorTest < Minitest::Test
4
+
5
+ def user_class(
6
+ smtp: true, states: %i[deliverable risky unknown], free: true, role: true,
7
+ accept_all: true, disposable: true, timeout: 3
8
+ )
9
+ Class.new do
10
+ include ActiveModel::Model
11
+ attr_accessor :email, :email_verification_result
12
+
13
+ validates :email, presence: true, email: {
14
+ smtp: smtp, states: states,
15
+ free: free, role: role, disposable: disposable, accept_all: accept_all,
16
+ timeout: timeout
17
+ }
18
+
19
+ def self.name
20
+ 'TestClass'
21
+ end
22
+
23
+ # stub changes to always be true
24
+ def changes
25
+ { email: true }
26
+ end
27
+ end
28
+ end
29
+
30
+ def setup
31
+ Emailable.api_key = 'test_7aff7fc0142c65f86a00'
32
+ sleep(0.25)
33
+ end
34
+
35
+ def test_valid
36
+ @user = user_class.new(email: 'deliverable@example.com')
37
+
38
+ assert @user.valid?
39
+ assert @user.errors.empty?
40
+ end
41
+
42
+ def test_invalid
43
+ @user = user_class.new(email: 'undeliverable@example.com')
44
+
45
+ assert !@user.valid?
46
+ assert @user.errors[:email].present?
47
+ end
48
+
49
+ def test_verification_result
50
+ @user = user_class.new(email: 'undeliverable@example.com')
51
+ @user.valid?
52
+
53
+ refute_nil @user.email_verification_result
54
+ assert @user.email_verification_result.state, :undeliverable
55
+ end
56
+
57
+ def test_boolean_options
58
+ %i[smtp free role disposable accept_all].each do |option|
59
+ invalid_user = user_class(option => 'string').new
60
+ valid_user = user_class.new
61
+
62
+ assert !valid_user.valid?
63
+ assert_raises(ArgumentError) { invalid_user.valid? }
64
+ end
65
+ end
66
+
67
+ def test_states_option
68
+ invalid_user = user_class(states: %i[invalid_state]).new
69
+ valid_user = user_class.new
70
+
71
+ assert !valid_user.valid?
72
+ assert_raises(ArgumentError) { invalid_user.valid? }
73
+ end
74
+
75
+ def test_timeout_option
76
+ invalid_user1 = user_class(timeout: 'string').new
77
+ invalid_user2 = user_class(timeout: 1).new
78
+ valid_user = user_class.new
79
+
80
+ assert !valid_user.valid?
81
+ assert_raises(ArgumentError) { invalid_user1.valid? }
82
+ assert_raises(ArgumentError) { invalid_user2.valid? }
83
+ end
84
+
85
+ end
@@ -0,0 +1,30 @@
1
+ require 'test_helper'
2
+
3
+ module Emailable
4
+ class BatchTest < Minitest::Test
5
+
6
+ def setup
7
+ sleep(1)
8
+ Emailable.api_key = 'test_7aff7fc0142c65f86a00'
9
+ @emails = ['jarrett@emailable.com', 'support@emailable.com']
10
+ @batch = Emailable::Batch.new(@emails)
11
+ @batch_id ||= @batch.verify
12
+ sleep(1)
13
+ end
14
+
15
+ def test_start_batch
16
+ refute_nil @batch_id
17
+ end
18
+
19
+ def test_batch_status
20
+ status = @batch.status
21
+ refute_nil status.message
22
+ end
23
+
24
+ def test_batch_complete
25
+ complete = @batch.complete?
26
+ assert complete == true || complete == false
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,71 @@
1
+ require 'test_helper'
2
+
3
+ class EmailableTest < Minitest::Test
4
+
5
+ def setup
6
+ Emailable.api_key = 'test_7aff7fc0142c65f86a00'
7
+ @result ||= Emailable.verify('jarrett@emailable.com')
8
+ sleep(0.25)
9
+ end
10
+
11
+ def test_verification
12
+ refute_nil @result.domain
13
+ refute_nil @result.email
14
+ refute_nil @result.reason
15
+ refute_nil @result.score
16
+ refute_nil @result.state
17
+ refute_nil @result.user
18
+ refute_nil @result.duration
19
+ end
20
+
21
+ def test_verification_state
22
+ assert %w(deliverable undeliverable risky unknown).include?(@result.state)
23
+ end
24
+
25
+ def test_verification_role
26
+ result = Emailable.verify('support@emailable.com')
27
+ assert result.role?
28
+ refute @result.role?
29
+ end
30
+
31
+ def test_verification_did_you_mean
32
+ result1 = Emailable.verify('jarrett@gmali.com')
33
+ result2 = Emailable.verify('jarrett@gmail.com')
34
+ assert result1.did_you_mean, 'jarrett@gmail.com'
35
+ assert_nil result2.did_you_mean
36
+ end
37
+
38
+ def test_verification_tag
39
+ result = Emailable.verify('jarrett+marketing@emailable.com')
40
+ assert result.tag == 'marketing'
41
+ end
42
+
43
+ def test_account
44
+ account = Emailable.account
45
+
46
+ refute_nil account.owner_email
47
+ refute_nil account.available_credits
48
+ end
49
+
50
+ def test_name_and_gender
51
+ result = Emailable.verify('johndoe@emailable.com')
52
+ if %w(deliverable risky unknown).include?(result.state)
53
+ assert result.first_name, 'John'
54
+ assert result.last_name, 'Doe'
55
+ assert result.full_name, 'John Doe'
56
+ assert result.gender, 'male'
57
+ else
58
+ assert_nil result.first_name
59
+ assert_nil result.last_name
60
+ assert_nil result.full_name
61
+ assert_nil result.gender
62
+ end
63
+ end
64
+
65
+ def test_slow_verification
66
+ assert_raises(Emailable::TimeoutError) do
67
+ Emailable.verify('slow@example.com')
68
+ end
69
+ end
70
+
71
+ end
@@ -0,0 +1,12 @@
1
+ $LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
2
+ require 'active_model'
3
+ require 'emailable'
4
+
5
+ require 'pry'
6
+ require 'minitest/autorun'
7
+ require 'minitest/reporters'
8
+ Minitest::Reporters.use! [
9
+ Minitest::Reporters::ProgressReporter.new(color: true)
10
+ ]
11
+ Minitest.load_plugins
12
+ Minitest::PrideIO.pride!
metadata ADDED
@@ -0,0 +1,218 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: emailable
3
+ version: !ruby/object:Gem::Version
4
+ version: 3.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Emailable
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-03-19 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: faraday
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: faraday_middleware
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: net-http-persistent
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rake
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '13.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '13.0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: pry
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: awesome_print
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: minitest
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '5.0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '5.0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: minitest-reporters
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: activemodel
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ description: Email Verification that’s astonishingly easy and low-cost. See https://emailable.com
154
+ for details.
155
+ email: support@emailable.com
156
+ executables:
157
+ - console
158
+ - setup
159
+ extensions: []
160
+ extra_rdoc_files: []
161
+ files:
162
+ - ".gitignore"
163
+ - ".ruby-gemset"
164
+ - ".ruby-version"
165
+ - ".travis.yml"
166
+ - Gemfile
167
+ - Gemfile.lock
168
+ - LICENSE.txt
169
+ - README.md
170
+ - Rakefile
171
+ - bin/console
172
+ - bin/setup
173
+ - config/locales/en.yml
174
+ - emailable.gemspec
175
+ - lib/emailable.rb
176
+ - lib/emailable/batch.rb
177
+ - lib/emailable/client.rb
178
+ - lib/emailable/email_validator.rb
179
+ - lib/emailable/resources/account.rb
180
+ - lib/emailable/resources/api_resource.rb
181
+ - lib/emailable/resources/batch_status.rb
182
+ - lib/emailable/resources/verification.rb
183
+ - lib/emailable/version.rb
184
+ - test/email_validator_test.rb
185
+ - test/emailable/batch_test.rb
186
+ - test/emailable_test.rb
187
+ - test/test_helper.rb
188
+ homepage: https://emailable.com
189
+ licenses:
190
+ - MIT
191
+ metadata:
192
+ bug_tracker_uri: https://github.com/emailable/emailable-ruby/issues
193
+ documentation_uri: https://docs.emailable.com/?ruby
194
+ source_code_uri: https://github.com/emailable/emailable-ruby
195
+ post_install_message:
196
+ rdoc_options: []
197
+ require_paths:
198
+ - lib
199
+ required_ruby_version: !ruby/object:Gem::Requirement
200
+ requirements:
201
+ - - ">="
202
+ - !ruby/object:Gem::Version
203
+ version: '0'
204
+ required_rubygems_version: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - ">="
207
+ - !ruby/object:Gem::Version
208
+ version: '0'
209
+ requirements: []
210
+ rubygems_version: 3.0.9
211
+ signing_key:
212
+ specification_version: 4
213
+ summary: Ruby bindings for the Emailable API
214
+ test_files:
215
+ - test/email_validator_test.rb
216
+ - test/emailable/batch_test.rb
217
+ - test/emailable_test.rb
218
+ - test/test_helper.rb