email_address 0.1.9 → 0.1.10

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 3825a1fafdf4659a5bc444b2bea01e83d4a52a0ae3faf57042c2cf83cae0d364
4
- data.tar.gz: e9c2f046f52648f7f7f2e0326457f1aaa11f36e075e87d40818a34de7a84f2f3
3
+ metadata.gz: b7864361d639e8c0d2609782b1d4d02a2d8c497bf3080a6bb563e5a8eac7bdc6
4
+ data.tar.gz: 1145528c90a7845ce092fae5791a8dde9d81a66709188d3a53eb9310a8e49e7e
5
5
  SHA512:
6
- metadata.gz: 39f199aab0bd33b42a57841df03a033142217aa5a39fe0652b779c4522509d450660178fc51eee23bc3111905a967475ac3625718d020d275ef9d697b672fe79
7
- data.tar.gz: e3ee79489ea98a0b6c11a3b438e84087833ce9782f16bf3865d7169514cd9a939f383a17e6ef2b695273351cbd427de2f36332d0d63e693c99c6f3fa7173430b
6
+ metadata.gz: a04d299269c34d29dc630335462bd8a6b778c9ce4eefa12ee5bb5a5f0e22fb6e435b4c84f413f6f194f8a2e8e4d94831d96f0cee3eef7fd28e8028bd839ffc85
7
+ data.tar.gz: 44184ef5b1c631e9a7cde11b8570c49473cceda7649cc625a386bd6c5ec8cd9fae5b024db82c06a99d237b025a249db92835492f99cc781a44654fb56d6999cf
@@ -1,7 +1,7 @@
1
1
  language: ruby
2
2
  rvm:
3
3
  - ruby-head
4
- - 2.2.2
4
+ - 2.3.7
5
5
  - jruby-9.0.4.0
6
6
  #- rbx
7
7
 
data/README.md CHANGED
@@ -22,6 +22,9 @@ address validator and attributes API custom datatypes.
22
22
 
23
23
  Requires Ruby 2.0 or later.
24
24
 
25
+ Looking for a Javascript version of this library? Check out the
26
+ [email_address](https://www.npmjs.com/package/email_address) npm module.
27
+
25
28
  ## Quick Start
26
29
 
27
30
  To quickly validate email addresses, use the valid? and error helpers.
@@ -20,12 +20,12 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_development_dependency "rake"
22
22
  spec.add_development_dependency "minitest", "~> 5.11"
23
- spec.add_development_dependency "bundler", "~> 1.3"
23
+ spec.add_development_dependency "bundler", "~> 1.16.0"
24
24
  if RUBY_PLATFORM == 'java'
25
- spec.add_development_dependency "activerecord", "= 4.2.5"
26
- spec.add_development_dependency "activerecord-jdbcsqlite3-adapter", '=1.3.19'
25
+ spec.add_development_dependency "activerecord", "= 4.2.10"
26
+ spec.add_development_dependency "activerecord-jdbcsqlite3-adapter", '~> 1.3.24'
27
27
  else
28
- spec.add_development_dependency "activerecord", "~> 5.2.0.rc2"
28
+ spec.add_development_dependency "activerecord", "~> 5.2.0"
29
29
  spec.add_development_dependency "sqlite3"
30
30
  end
31
31
  spec.add_development_dependency "codeclimate-test-reporter"
@@ -1,4 +1,7 @@
1
+ # frozen_string_literal: true
1
2
 
3
+ # EmailAddress parses and validates email addresses against RFC standard,
4
+ # conventional, canonical, formats and other special uses.
2
5
  module EmailAddress
3
6
 
4
7
  require "email_address/config"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module EmailAddress
2
4
 
3
5
  # ActiveRecord validator class for validating an email
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'digest/sha1'
2
4
  require 'digest/md5'
3
5
 
@@ -30,6 +32,7 @@ module EmailAddress
30
32
  @host = EmailAddress::Host.new(host, config)
31
33
  @config = @host.config
32
34
  @local = EmailAddress::Local.new(local, @config, @host)
35
+ @error = @error_message = nil
33
36
  end
34
37
 
35
38
  # Given an email address, this returns an array of [local, host] parts
@@ -228,7 +231,7 @@ module EmailAddress
228
231
  def valid?(options={})
229
232
  @error = nil
230
233
  unless self.local.valid?
231
- return set_error :invalid_mailbox
234
+ return set_error self.local.error
232
235
  end
233
236
  unless self.host.valid?
234
237
  return set_error self.host.error_message
@@ -259,7 +262,7 @@ module EmailAddress
259
262
  smtp.start(@config[:smtp_helo_name] || 'localhost')
260
263
  smtp.mailfrom @config[:smtp_mail_from] || 'postmaster@localhost'
261
264
  smtp.rcptto self.to_s
262
- p [:connect]
265
+ #p [:connect]
263
266
  smtp.finish
264
267
  true
265
268
  rescue Net::SMTPUnknownError => e
@@ -277,17 +280,18 @@ module EmailAddress
277
280
  end
278
281
 
279
282
  def set_error(err, reason=nil)
280
- @error = EmailAddress::Config.error_messages.fetch(err) { err }
283
+ @error = err
281
284
  @reason= reason
285
+ @error_message = EmailAddress::Config.error_message(err)
282
286
  false
283
287
  end
284
288
 
285
289
  def error_message
286
- @error
290
+ @error_message
287
291
  end
288
292
 
289
293
  def error
290
- self.valid? ? nil : @error
294
+ self.valid? ? nil : @error_message
291
295
  end
292
296
 
293
297
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ################################################################################
2
4
  # ActiveRecord v5.0 Custom Type
3
5
  #
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module EmailAddress
2
4
  # Global configurations and for default/unknown providers. Settings are:
3
5
  #
@@ -92,6 +94,8 @@ module EmailAddress
92
94
  # * exchanger_match: %w(google.com 127.0.0.1 10.9.8.0/24 ::1/64)
93
95
  #
94
96
 
97
+ require 'yaml'
98
+
95
99
  class Config
96
100
  @config = {
97
101
  dns_lookup: :mx, # :mx, :a, :off
@@ -121,6 +125,7 @@ module EmailAddress
121
125
  address_fqdn_domain: nil, # Fully Qualified Domain Name = [host].[domain.tld]
122
126
  }
123
127
 
128
+ # 2018-04: AOL and Yahoo now under "oath.com", owned by Verizon. Keeping separate for now
124
129
  @providers = {
125
130
  aol: {
126
131
  host_match: %w(aol. compuserve. netscape. aim. cs.),
@@ -142,14 +147,10 @@ module EmailAddress
142
147
  },
143
148
  }
144
149
 
145
- @errors = {
146
- invalid_address: "Invalid Email Address",
147
- invalid_mailbox: "Invalid Recipient/Mailbox",
148
- invalid_host: "Invalid Host/Domain Name",
149
- exceeds_size: "Address too long",
150
- not_allowed: "Address is not allowed",
151
- incomplete_domain: "Domain name is incomplete",
152
- }
150
+
151
+ # Loads messages: {"en"=>{"email_address"=>{"invalid_address"=>"Invalid Email Address",...}}}
152
+ # Rails/I18n gem: t(email_address.error, scope: "email_address")
153
+ @errors = YAML.load_file(File.dirname(__FILE__)+"/messages.yaml")
153
154
 
154
155
  # Set multiple default configuration settings
155
156
  def self.configure(config={})
@@ -177,6 +178,10 @@ module EmailAddress
177
178
  @providers[name]
178
179
  end
179
180
 
181
+ def self.error_message(name, locale="en")
182
+ @errors[locale]["email_address"][name.to_s] || name.to_s
183
+ end
184
+
180
185
  # Customize your own error message text.
181
186
  def self.error_messages(hash=nil)
182
187
  @errors = @errors.merge(hash) if hash
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  ################################################################################
2
4
  # ActiveRecord v5.0 Custom Type
3
5
  #
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'resolv'
2
4
  require 'netaddr'
3
5
  require 'socket'
@@ -6,7 +8,7 @@ module EmailAddress
6
8
  class Exchanger
7
9
  include Enumerable
8
10
 
9
- def self.cached(host)
11
+ def self.cached(host, config={})
10
12
  @host_cache ||= {}
11
13
  @cache_size ||= ENV['EMAIL_ADDRESS_CACHE_SIZE'].to_i || 100
12
14
  if @host_cache.has_key?(host)
@@ -14,9 +16,9 @@ module EmailAddress
14
16
  @host_cache[host] = o # LRU cache, move to end
15
17
  elsif @host_cache.size >= @cache_size
16
18
  @host_cache.delete(@host_cache.keys.first)
17
- @host_cache[host] = new(host)
19
+ @host_cache[host] = new(host, config)
18
20
  else
19
- @host_cache[host] = new(host)
21
+ @host_cache[host] = new(host, config)
20
22
  end
21
23
  end
22
24
 
@@ -44,7 +46,11 @@ module EmailAddress
44
46
 
45
47
  # Returns: [["mta7.am0.yahoodns.net", "66.94.237.139", 1], ["mta5.am0.yahoodns.net", "67.195.168.230", 1], ["mta6.am0.yahoodns.net", "98.139.54.60", 1]]
46
48
  # If not found, returns []
49
+ # Returns a dummy record when dns_lookup is turned off since it may exists, though
50
+ # may not find provider by MX name or IP. I'm not sure about the "0.0.0.0" ip, it should
51
+ # be good in this context, but in "listen" context it means "all bound IP's"
47
52
  def mxers
53
+ return [["example.com", "0.0.0.0", 1]] if @config[:dns_lookup] == :off
48
54
  @mxers ||= Resolv::DNS.open do |dns|
49
55
  ress = dns.getresources(@host, Resolv::DNS::Resource::IN::MX)
50
56
  records = ress.map do |r|
@@ -69,6 +75,7 @@ module EmailAddress
69
75
 
70
76
  # Returns an array of MX IP address (String) for the given email domain
71
77
  def mx_ips
78
+ return ["0.0.0.0"] if @config[:dns_lookup] == :off
72
79
  mxers.map {|m| m[1] }
73
80
  end
74
81
 
@@ -1,3 +1,4 @@
1
+
1
2
  require 'simpleidn'
2
3
  require 'resolv'
3
4
  require 'netaddr'
@@ -88,6 +89,7 @@ module EmailAddress
88
89
  @original = host_name ||= ''
89
90
  config[:host_type] ||= :email
90
91
  @config = config
92
+ @error = @error_message = nil
91
93
  parse(host_name)
92
94
  end
93
95
 
@@ -334,6 +336,7 @@ module EmailAddress
334
336
 
335
337
  # Returns: [official_hostname, alias_hostnames, address_family, *address_list]
336
338
  def dns_a_record
339
+ @_dns_a_record = "0.0.0.0" if @config[:dns_lookup] == :off
337
340
  @_dns_a_record ||= Socket.gethostbyname(self.dns_name)
338
341
  rescue SocketError # not found, but could also mean network not work
339
342
  @_dns_a_record ||= []
@@ -343,7 +346,7 @@ module EmailAddress
343
346
  # The array will be empty if none are configured.
344
347
  def exchangers
345
348
  return nil if @config[:host_type] != :email || !self.dns_enabled?
346
- @_exchangers ||= EmailAddress::Exchanger.cached(self.dns_name)
349
+ @_exchangers ||= EmailAddress::Exchanger.cached(self.dns_name, @config)
347
350
  end
348
351
 
349
352
  # Returns a DNS TXT Record
@@ -398,11 +401,6 @@ module EmailAddress
398
401
  end
399
402
  end
400
403
 
401
- # The inverse of valid? -- Returns nil (falsey) if valid, otherwise error message
402
- def error
403
- valid? ? nil : @error_message
404
- end
405
-
406
404
  # True if the host name has a DNS A Record
407
405
  def valid_dns?
408
406
  bool = dns_a_record.size > 0 || set_error(:domain_unknown)
@@ -414,7 +412,9 @@ module EmailAddress
414
412
 
415
413
  # True if the host name has valid MX servers configured in DNS
416
414
  def valid_mx?
417
- if self.exchangers.mx_ips.size > 0
415
+ if self.exchangers.blank?
416
+ set_error(:domain_unknown)
417
+ elsif self.exchangers.mx_ips.size > 0
418
418
  if self.localhost? && !@config[:host_local]
419
419
  set_error(:domain_no_localhost)
420
420
  else
@@ -457,11 +457,11 @@ module EmailAddress
457
457
  if self.ip_address
458
458
  rel =
459
459
  if self.ip_address.include?(":")
460
- NetAddr::IPv6Net.parse("::1").rel(
460
+ NetAddr::IPv6Net.parse(""+"::1").rel(
461
461
  NetAddr::IPv6Net.parse(self.ip_address)
462
462
  )
463
463
  else
464
- NetAddr::IPv4Net.parse("127.0.0.0/8").rel(
464
+ NetAddr::IPv4Net.parse(""+"127.0.0.0/8").rel(
465
465
  NetAddr::IPv4Net.parse(self.ip_address)
466
466
  )
467
467
  end
@@ -492,10 +492,16 @@ module EmailAddress
492
492
  end
493
493
 
494
494
  def set_error(err, reason=nil)
495
- @error_message = EmailAddress::Config.error_messages.fetch(err) { err }
495
+ @error = err
496
496
  @reason = reason
497
+ @error_message = EmailAddress::Config.error_message(err)
497
498
  false
498
499
  end
499
500
 
501
+ # The inverse of valid? -- Returns nil (falsey) if valid, otherwise error message
502
+ def error
503
+ self.valid? ? nil : @error_message
504
+ end
505
+
500
506
  end
501
507
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module EmailAddress
2
4
  ##############################################################################
3
5
  # EmailAddress Local part consists of
@@ -103,6 +105,7 @@ module EmailAddress
103
105
  self.config = config.empty? ? EmailAddress::Config.all_settings : config
104
106
  self.local = local
105
107
  @host = host
108
+ @error = @error_message = nil
106
109
  end
107
110
 
108
111
  def local=(raw)
@@ -189,7 +192,7 @@ module EmailAddress
189
192
  self.conventional
190
193
  elsif form == :canonical
191
194
  self.canonical
192
- elsif form == :relax
195
+ elsif form == :relaxed
193
196
  self.relax
194
197
  elsif form == :standard
195
198
  self.standard
@@ -301,21 +304,23 @@ module EmailAddress
301
304
  end
302
305
 
303
306
  def valid_size?
307
+ return set_error(:local_size_long) if self.local.size > STANDARD_MAX_SIZE
304
308
  if @host && @host.hosted_service?
305
- return false if @config[:local_private_size] &&
306
- !@config[:local_private_size].include?(self.local.size)
307
- else
308
- return false if @config[:local_size] &&
309
- !@config[:local_size].include?(self.local.size)
309
+ return false if @config[:local_private_size] && !valid_size_checks(@config[:local_private_size])
310
310
  end
311
- return false if @config[:mailbox_size] && !@config[:mailbox_size].include?(self.mailbox.size)
312
- return false if self.local.size > STANDARD_MAX_SIZE
311
+ return false if @config[:local_size] && !valid_size_checks(@config[:local_size])
312
+ return false if @config[:mailbox_size] && !valid_size_checks(@config[:mailbox_size])
313
+ true
314
+ end
315
+
316
+ def valid_size_checks(range)
317
+ return set_error(:local_size_short) if self.mailbox.size < range.first
318
+ return set_error(:local_size_long) if self.mailbox.size > range.last
313
319
  true
314
320
  end
315
321
 
316
322
  def valid_encoding?(enc=@config[:local_encoding]||:ascii)
317
323
  return false if enc == :ascii && self.unicode?
318
- #return false if enc == :unicode && self.ascii?
319
324
  true
320
325
  end
321
326
 
@@ -365,5 +370,21 @@ module EmailAddress
365
370
  end
366
371
  false
367
372
  end
373
+
374
+ def set_error(err, reason=nil)
375
+ @error = err
376
+ @reason= reason
377
+ @error_message = EmailAddress::Config.error_message(err)
378
+ false
379
+ end
380
+
381
+ def error_message
382
+ @error_message
383
+ end
384
+
385
+ def error
386
+ self.valid? ? nil : @error
387
+ end
388
+
368
389
  end
369
390
  end
@@ -0,0 +1,20 @@
1
+ en:
2
+ email_address:
3
+ address_unknown: "Unknown Email Address"
4
+ domain_does_not_accept_email: "This domain is not configured to accept email"
5
+ domain_invalid: "Invalid Domain Name"
6
+ domain_no_localhost: "localhost is not allowed for your domain name"
7
+ domain_unknown: "Domain name not registered"
8
+ exceeds_size: "Address too long"
9
+ incomplete_domain: "Domain name is incomplete"
10
+ invalid_address: "Invalid Email Address"
11
+ invalid_host: "Invalid Host/Domain Name"
12
+ invalid_mailbox: "Invalid Mailbox"
13
+ ip_address_forbidden: "IP Addresses are not allowed"
14
+ ip_address_no_localhost: "Localhost IP addresses are not allowed"
15
+ ipv4_address_invalid: "This is not a valid IPv4 address"
16
+ ipv6_address_invalid: "This is not a valid IPv6 address"
17
+ local_size_long: "Mailbox name too long"
18
+ local_size_short: "Mailbox name too short"
19
+ not_allowed: "Address is not allowed"
20
+ server_not_available: "The remote email server is not available"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'base64'
2
4
 
3
5
  module EmailAddress::Rewriter
@@ -1,3 +1,3 @@
1
1
  module EmailAddress
2
- VERSION = "0.1.9"
2
+ VERSION = "0.1.10"
3
3
  end
@@ -77,9 +77,9 @@ class TestAddress < Minitest::Test
77
77
  e = EmailAddress.new("User+tag.gmail.ws") # No domain means localhost
78
78
  assert_equal '', e.hostname
79
79
  assert_equal false, e.valid? # localhost not allowed by default
80
- assert_equal EmailAddress.error("user1"), :domain_invalid
81
- assert_equal EmailAddress.error("user1", host_local:true), :domain_does_not_accept_email
82
- assert_equal EmailAddress.error("user1@localhost", host_local:true), :domain_does_not_accept_email
80
+ assert_equal EmailAddress.error("user1"), "Invalid Domain Name"
81
+ assert_equal EmailAddress.error("user1", host_local:true), "This domain is not configured to accept email"
82
+ assert_equal EmailAddress.error("user1@localhost", host_local:true), "This domain is not configured to accept email"
83
83
  assert_nil EmailAddress.error("user2@localhost", host_local:true, dns_lookup: :off, host_validation: :syntax)
84
84
  end
85
85
 
@@ -112,4 +112,8 @@ class TestAddress < Minitest::Test
112
112
  assert ! EmailAddress.valid?('example.user@foo.com/')
113
113
  end
114
114
 
115
+ def test_relaxed_normal
116
+ assert ! EmailAddress.new('a.c.m.e.-industries@foo.com').valid?
117
+ assert true, EmailAddress.new('a.c.m.e.-industries@foo.com', local_format: :relaxed).valid?
118
+ end
115
119
  end
@@ -114,12 +114,12 @@ class TestHost < MiniTest::Test
114
114
 
115
115
  def test_errors
116
116
  assert_nil EmailAddress::Host.new("yahoo.com").error
117
- assert_equal EmailAddress::Host.new("example.com").error, :domain_does_not_accept_email
118
- assert_equal EmailAddress::Host.new("yahoo.wtf").error, :domain_unknown
117
+ assert_equal EmailAddress::Host.new("example.com").error, "This domain is not configured to accept email"
118
+ assert_equal EmailAddress::Host.new("yahoo.wtf").error, "Domain name not registered"
119
119
  assert_nil EmailAddress::Host.new("ajsdfhajshdfklasjhd.wtf", host_validation: :syntax).error
120
- assert_equal EmailAddress::Host.new("ya hoo.com", host_validation: :syntax).error, :domain_invalid
121
- assert_equal EmailAddress::Host.new("[127.0.0.1]").error, :ip_address_forbidden
122
- assert_equal EmailAddress::Host.new("[127.0.0.666]", host_allow_ip:true).error, :ipv4_address_invalid
123
- assert_equal EmailAddress::Host.new("[IPv6::12t]", host_allow_ip:true).error, :ipv6_address_invalid
120
+ assert_equal EmailAddress::Host.new("ya hoo.com", host_validation: :syntax).error, "Invalid Domain Name"
121
+ assert_equal EmailAddress::Host.new("[127.0.0.1]").error, "IP Addresses are not allowed"
122
+ assert_equal EmailAddress::Host.new("[127.0.0.666]", host_allow_ip:true).error, "This is not a valid IPv4 address"
123
+ assert_equal EmailAddress::Host.new("[IPv6::12t]", host_allow_ip:true).error, "This is not a valid IPv6 address"
124
124
  end
125
125
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: email_address
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.9
4
+ version: 0.1.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Allen Fair
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-03-26 00:00:00.000000000 Z
11
+ date: 2018-07-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -44,28 +44,28 @@ dependencies:
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '1.3'
47
+ version: 1.16.0
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '1.3'
54
+ version: 1.16.0
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: activerecord
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: 5.2.0.rc2
61
+ version: 5.2.0
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: 5.2.0.rc2
68
+ version: 5.2.0
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: sqlite3
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -145,6 +145,7 @@ files:
145
145
  - lib/email_address/exchanger.rb
146
146
  - lib/email_address/host.rb
147
147
  - lib/email_address/local.rb
148
+ - lib/email_address/messages.yaml
148
149
  - lib/email_address/rewriter.rb
149
150
  - lib/email_address/version.rb
150
151
  - test/activerecord/test_ar.rb
@@ -177,7 +178,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
177
178
  version: '0'
178
179
  requirements: []
179
180
  rubyforge_project:
180
- rubygems_version: 2.7.3
181
+ rubygems_version: 2.7.6
181
182
  signing_key:
182
183
  specification_version: 4
183
184
  summary: This gem provides a ruby language library for working with and validating