truemail 0.1.6 → 0.1.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.reek.yml +5 -2
- data/Gemfile.lock +1 -1
- data/README.md +26 -2
- data/lib/truemail.rb +13 -5
- data/lib/truemail/audit/base.rb +13 -0
- data/lib/truemail/audit/ptr.rb +41 -0
- data/lib/truemail/auditor.rb +24 -0
- data/lib/truemail/core.rb +12 -1
- data/lib/truemail/validate/base.rb +1 -15
- data/lib/truemail/validate/mx.rb +15 -7
- data/lib/truemail/validate/smtp.rb +1 -1
- data/lib/truemail/version.rb +1 -1
- data/lib/truemail/worker.rb +21 -0
- data/lib/truemail/wrapper.rb +24 -0
- metadata +7 -3
- data/lib/truemail/validate/resolver_execution_wrapper.rb +0 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f597eb293f10835d12b766da633b9d1808424760924a89472416729e60241c23
|
4
|
+
data.tar.gz: a4fe4b473856a44d312bfb15fdd831a412d5764fedc33274f5923b75b59b5ce0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dd936cd55b94200bb344d78236527f31cb298e2a453ca660f4d825ba0538c9d6057e730b975319f68130fe64d847cdacb7937a4dbb0344f3ceaf43efb7f3b7b0
|
7
|
+
data.tar.gz: 3d8814c197319adb5fb8e9fb2e1c5b5d46dee8adb3bab204199d98b78137b9cbdf8ca28873405b65af8c570ff499a93981851a2bd5e962f1c5910c9303c00125
|
data/.reek.yml
CHANGED
@@ -21,18 +21,21 @@ detectors:
|
|
21
21
|
Attribute:
|
22
22
|
exclude:
|
23
23
|
- Truemail::Configuration#smtp_safe_check
|
24
|
-
- Truemail::
|
24
|
+
- Truemail::Wrapper#attempts
|
25
25
|
|
26
26
|
UtilityFunction:
|
27
27
|
exclude:
|
28
28
|
- Truemail::Validate::Smtp::Request#compose_from
|
29
29
|
- Truemail::Validator#select_validation_type
|
30
30
|
- Truemail::Validate::Mx#null_mx?
|
31
|
+
- Truemail::Validate::Mx#a_record
|
32
|
+
- Truemail::Audit::Ptr#current_host_address
|
31
33
|
|
32
34
|
ControlParameter:
|
33
35
|
exclude:
|
34
36
|
- Truemail::GenerateEmailHelper#calculate_email_size
|
35
|
-
- Truemail::
|
37
|
+
- Truemail::Worker#success
|
38
|
+
- Truemail#raise_unless
|
36
39
|
|
37
40
|
FeatureEnvy:
|
38
41
|
exclude:
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
[![Maintainability](https://api.codeclimate.com/v1/badges/657aa241399927dcd2e2/maintainability)](https://codeclimate.com/github/rubygarage/truemail/maintainability) [![Test Coverage](https://api.codeclimate.com/v1/badges/657aa241399927dcd2e2/test_coverage)](https://codeclimate.com/github/rubygarage/truemail/test_coverage) [![Gem Version](https://badge.fury.io/rb/truemail.svg)](https://badge.fury.io/rb/truemail) [![CircleCI](https://circleci.com/gh/rubygarage/truemail/tree/master.svg?style=svg)](https://circleci.com/gh/rubygarage/truemail/tree/master) [![Contributor Covenant](https://img.shields.io/badge/Contributor%20Covenant-v1.4%20adopted-ff69b4.svg)](CODE_OF_CONDUCT.md)
|
4
4
|
|
5
|
-
The Truemail gem helps you validate emails by regex pattern, presence of domain mx-records, and real existence of email account on a current email server.
|
5
|
+
The Truemail gem helps you validate emails by regex pattern, presence of domain mx-records, and real existence of email account on a current email server. Also Truemail gem allows performing an audit of the host in which runs.
|
6
6
|
|
7
7
|
## Features
|
8
8
|
|
@@ -137,7 +137,7 @@ Truemail.configuration
|
|
137
137
|
|
138
138
|
#### Regex validation
|
139
139
|
|
140
|
-
Validation with regex pattern is the first validation level. By default this validation not performs strictly following RFC 5322
|
140
|
+
Validation with regex pattern is the first validation level. By default this validation not performs strictly following RFC 5322 standard, so you can override Truemail default regex pattern if you want.
|
141
141
|
|
142
142
|
Example of usage:
|
143
143
|
|
@@ -383,6 +383,30 @@ Truemail.validate('email@example.com')
|
|
383
383
|
@validation_type=:smtp>
|
384
384
|
```
|
385
385
|
|
386
|
+
### Host audit features
|
387
|
+
|
388
|
+
Truemail gem allows performing an audit of the host in which runs. Only PTR record audit performs for today.
|
389
|
+
|
390
|
+
#### PTR audit
|
391
|
+
|
392
|
+
So what is a PTR record? A PTR record, or pointer record, enables someone to perform a reverse DNS lookup. This allows them to determine your domain name based on your IP address. Because generic domain names without a PTR are often associated with spammers, incoming mail servers identify email from hosts without PTR records as spam and you can't verify yours emails qualitatively.
|
393
|
+
|
394
|
+
```ruby
|
395
|
+
Truemail.host_audit
|
396
|
+
# Everything is good
|
397
|
+
=> #<Truemail::Auditor:0x00005580df358828
|
398
|
+
@result=
|
399
|
+
#<struct Truemail::Auditor::Result
|
400
|
+
warnings={}>>
|
401
|
+
|
402
|
+
# Has PTR warning
|
403
|
+
=> #<Truemail::Auditor:0x00005580df358828
|
404
|
+
@result=
|
405
|
+
#<struct Truemail::Auditor::Result
|
406
|
+
warnings=
|
407
|
+
{:ptr=>"ptr record does not reference to current verifier domain"}>>
|
408
|
+
```
|
409
|
+
|
386
410
|
### Truemail helpers
|
387
411
|
|
388
412
|
#### .valid?
|
data/lib/truemail.rb
CHANGED
@@ -1,9 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require 'truemail/version'
|
4
3
|
require 'truemail/core'
|
5
|
-
require 'truemail/configuration'
|
6
|
-
require 'truemail/validator'
|
7
4
|
|
8
5
|
module Truemail
|
9
6
|
INCOMPLETE_CONFIG = 'verifier_email is required parameter'
|
@@ -15,7 +12,7 @@ module Truemail
|
|
15
12
|
return unless block_given?
|
16
13
|
configuration = Truemail::Configuration.new
|
17
14
|
yield(configuration)
|
18
|
-
|
15
|
+
raise_unless(configuration.complete?, INCOMPLETE_CONFIG)
|
19
16
|
configuration
|
20
17
|
end
|
21
18
|
end
|
@@ -29,12 +26,23 @@ module Truemail
|
|
29
26
|
end
|
30
27
|
|
31
28
|
def validate(email, **options)
|
32
|
-
|
29
|
+
raise_unless(configuration, NOT_CONFIGURED)
|
33
30
|
Truemail::Validator.new(email, **options).run
|
34
31
|
end
|
35
32
|
|
36
33
|
def valid?(email, **options)
|
37
34
|
validate(email, **options).result.valid?
|
38
35
|
end
|
36
|
+
|
37
|
+
def host_audit
|
38
|
+
raise_unless(configuration, NOT_CONFIGURED)
|
39
|
+
Truemail::Auditor.run
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def raise_unless(condition, message)
|
45
|
+
raise ConfigurationError, message unless condition
|
46
|
+
end
|
39
47
|
end
|
40
48
|
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Truemail
|
4
|
+
module Audit
|
5
|
+
class Ptr < Truemail::Audit::Base
|
6
|
+
require 'ipaddr'
|
7
|
+
require 'resolv'
|
8
|
+
|
9
|
+
NOT_FOUND = 'ptr record for current host address was not found'
|
10
|
+
NOT_REFERENCES = 'ptr record does not reference to current verifier domain'
|
11
|
+
|
12
|
+
def run
|
13
|
+
return if ptr_records.empty? && add_warning(Truemail::Audit::Ptr::NOT_FOUND)
|
14
|
+
return if ptr_references_to_verifier_domain?
|
15
|
+
add_warning(Truemail::Audit::Ptr::NOT_REFERENCES)
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def current_host_address
|
21
|
+
Resolv.getaddress(Socket.gethostname)
|
22
|
+
end
|
23
|
+
|
24
|
+
def current_host_reverse_lookup
|
25
|
+
IPAddr.new(current_host_address).reverse
|
26
|
+
end
|
27
|
+
|
28
|
+
def ptr_records
|
29
|
+
@ptr_records ||= Truemail::Wrapper.call do
|
30
|
+
Resolv::DNS.new.getresources(
|
31
|
+
current_host_reverse_lookup, Resolv::DNS::Resource::IN::PTR
|
32
|
+
).map { |ptr_record| ptr_record.name.to_s }
|
33
|
+
end || []
|
34
|
+
end
|
35
|
+
|
36
|
+
def ptr_references_to_verifier_domain?
|
37
|
+
ptr_records.include?(Truemail.configuration.verifier_domain)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Truemail
|
4
|
+
class Auditor
|
5
|
+
Result = Struct.new(:warnings, keyword_init: true) do
|
6
|
+
def initialize(warnings: {}, **args)
|
7
|
+
super
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.run
|
12
|
+
new.run
|
13
|
+
end
|
14
|
+
|
15
|
+
def result
|
16
|
+
@result ||= Truemail::Auditor::Result.new
|
17
|
+
end
|
18
|
+
|
19
|
+
def run
|
20
|
+
Truemail::Audit::Ptr.check(result)
|
21
|
+
self
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/truemail/core.rb
CHANGED
@@ -1,6 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Truemail
|
4
|
+
require 'truemail/version'
|
5
|
+
require 'truemail/configuration'
|
6
|
+
require 'truemail/worker'
|
7
|
+
require 'truemail/wrapper'
|
8
|
+
require 'truemail/auditor'
|
9
|
+
require 'truemail/validator'
|
10
|
+
|
4
11
|
class ConfigurationError < StandardError; end
|
5
12
|
|
6
13
|
class ArgumentError < StandardError
|
@@ -16,10 +23,14 @@ module Truemail
|
|
16
23
|
REGEX_DOMAIN_FROM_EMAIL = /\A.+@(.+)\z/
|
17
24
|
end
|
18
25
|
|
26
|
+
module Audit
|
27
|
+
require 'truemail/audit/base'
|
28
|
+
require 'truemail/audit/ptr'
|
29
|
+
end
|
30
|
+
|
19
31
|
module Validate
|
20
32
|
require 'truemail/validate/base'
|
21
33
|
require 'truemail/validate/regex'
|
22
|
-
require 'truemail/validate/resolver_execution_wrapper'
|
23
34
|
require 'truemail/validate/mx'
|
24
35
|
require 'truemail/validate/smtp'
|
25
36
|
require 'truemail/validate/smtp/response'
|
@@ -2,23 +2,9 @@
|
|
2
2
|
|
3
3
|
module Truemail
|
4
4
|
module Validate
|
5
|
-
class Base
|
6
|
-
attr_reader :result
|
7
|
-
|
8
|
-
def self.check(result)
|
9
|
-
new(result).run
|
10
|
-
end
|
11
|
-
|
12
|
-
def initialize(result)
|
13
|
-
@result = result
|
14
|
-
end
|
15
|
-
|
5
|
+
class Base < Truemail::Worker
|
16
6
|
private
|
17
7
|
|
18
|
-
def success(condition)
|
19
|
-
result.success = condition || false
|
20
|
-
end
|
21
|
-
|
22
8
|
def add_error(message)
|
23
9
|
result.errors[self.class.name.split('::').last.downcase.to_sym] = message
|
24
10
|
end
|
data/lib/truemail/validate/mx.rb
CHANGED
@@ -24,7 +24,7 @@ module Truemail
|
|
24
24
|
|
25
25
|
def mx_lookup
|
26
26
|
host_extractor_methods.any? do |method|
|
27
|
-
Truemail::
|
27
|
+
Truemail::Wrapper.call { send(method) }
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
@@ -41,8 +41,8 @@ module Truemail
|
|
41
41
|
!mail_servers.include?(Truemail::Validate::Mx::NULL_MX_RECORD)
|
42
42
|
end
|
43
43
|
|
44
|
-
def mx_records(
|
45
|
-
domain_mx_records = Resolv::DNS.new.getresources(
|
44
|
+
def mx_records(hostname)
|
45
|
+
domain_mx_records = Resolv::DNS.new.getresources(hostname, Resolv::DNS::Resource::IN::MX)
|
46
46
|
return [Truemail::Validate::Mx::NULL_MX_RECORD] if null_mx?(domain_mx_records)
|
47
47
|
domain_mx_records.sort_by(&:preference).map do |mx_record|
|
48
48
|
Resolv.getaddresses(mx_record.exchange.to_s)
|
@@ -53,16 +53,24 @@ module Truemail
|
|
53
53
|
!mail_servers.empty?
|
54
54
|
end
|
55
55
|
|
56
|
+
def domain
|
57
|
+
result.domain
|
58
|
+
end
|
59
|
+
|
56
60
|
def hosts_from_mx_records?
|
57
|
-
fetch_target_hosts(mx_records(
|
61
|
+
fetch_target_hosts(mx_records(domain))
|
58
62
|
mail_servers_found?
|
59
63
|
end
|
60
64
|
|
65
|
+
def a_record(hostname)
|
66
|
+
Resolv.getaddress(hostname)
|
67
|
+
end
|
68
|
+
|
61
69
|
def hosts_from_cname_records?
|
62
|
-
cname_records = Resolv::DNS.new.getresources(
|
70
|
+
cname_records = Resolv::DNS.new.getresources(domain, Resolv::DNS::Resource::IN::CNAME)
|
63
71
|
return if cname_records.empty?
|
64
72
|
cname_records.each do |cname_record|
|
65
|
-
host =
|
73
|
+
host = a_record(cname_record.name.to_s)
|
66
74
|
hostname = Resolv.getname(host)
|
67
75
|
found_hosts = mx_records(hostname)
|
68
76
|
fetch_target_hosts(found_hosts.empty? ? [host] : found_hosts)
|
@@ -71,7 +79,7 @@ module Truemail
|
|
71
79
|
end
|
72
80
|
|
73
81
|
def host_from_a_record?
|
74
|
-
fetch_target_hosts([
|
82
|
+
fetch_target_hosts([a_record(domain)])
|
75
83
|
mail_servers_found?
|
76
84
|
end
|
77
85
|
end
|
data/lib/truemail/version.rb
CHANGED
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Truemail
|
4
|
+
class Worker
|
5
|
+
attr_reader :result
|
6
|
+
|
7
|
+
def self.check(result)
|
8
|
+
new(result).run
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(result)
|
12
|
+
@result = result
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def success(condition)
|
18
|
+
result.success = condition || false
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Truemail
|
4
|
+
class Wrapper
|
5
|
+
attr_accessor :attempts
|
6
|
+
|
7
|
+
def self.call(&block)
|
8
|
+
new.call(&block)
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@attempts = Truemail.configuration.connection_attempts
|
13
|
+
end
|
14
|
+
|
15
|
+
def call(&block)
|
16
|
+
Timeout.timeout(Truemail.configuration.connection_timeout, &block)
|
17
|
+
rescue Resolv::ResolvError
|
18
|
+
false
|
19
|
+
rescue Timeout::Error
|
20
|
+
retry unless (self.attempts -= 1).zero?
|
21
|
+
false
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: truemail
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Vladislav Trotsenko
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-04-
|
11
|
+
date: 2019-04-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -193,17 +193,21 @@ files:
|
|
193
193
|
- bin/console
|
194
194
|
- bin/setup
|
195
195
|
- lib/truemail.rb
|
196
|
+
- lib/truemail/audit/base.rb
|
197
|
+
- lib/truemail/audit/ptr.rb
|
198
|
+
- lib/truemail/auditor.rb
|
196
199
|
- lib/truemail/configuration.rb
|
197
200
|
- lib/truemail/core.rb
|
198
201
|
- lib/truemail/validate/base.rb
|
199
202
|
- lib/truemail/validate/mx.rb
|
200
203
|
- lib/truemail/validate/regex.rb
|
201
|
-
- lib/truemail/validate/resolver_execution_wrapper.rb
|
202
204
|
- lib/truemail/validate/smtp.rb
|
203
205
|
- lib/truemail/validate/smtp/request.rb
|
204
206
|
- lib/truemail/validate/smtp/response.rb
|
205
207
|
- lib/truemail/validator.rb
|
206
208
|
- lib/truemail/version.rb
|
209
|
+
- lib/truemail/worker.rb
|
210
|
+
- lib/truemail/wrapper.rb
|
207
211
|
- truemail.gemspec
|
208
212
|
homepage: https://github.com/rubygarage/truemail
|
209
213
|
licenses:
|
@@ -1,26 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Truemail
|
4
|
-
module Validate
|
5
|
-
class ResolverExecutionWrapper
|
6
|
-
attr_accessor :attempts
|
7
|
-
|
8
|
-
def self.call(&block)
|
9
|
-
new.call(&block)
|
10
|
-
end
|
11
|
-
|
12
|
-
def initialize
|
13
|
-
@attempts = Truemail.configuration.connection_attempts
|
14
|
-
end
|
15
|
-
|
16
|
-
def call(&block)
|
17
|
-
Timeout.timeout(Truemail.configuration.connection_timeout, &block)
|
18
|
-
rescue Resolv::ResolvError
|
19
|
-
false
|
20
|
-
rescue Timeout::Error
|
21
|
-
retry unless (self.attempts -= 1).zero?
|
22
|
-
false
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|