email_address 0.1.13 → 0.1.18

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 67dd5ab4cf92d131f566e7cf275073dfd80f92f1024adb0a276e08bc81640878
4
- data.tar.gz: fcccbc2f24aa40ee835c3a4cd5ec1a233823c7ab7d08afdb20f94f029b208493
3
+ metadata.gz: 2a5ff67ec79e4de2d356293664296391fc8296ad6a6ba08f1d1256e93f7c729c
4
+ data.tar.gz: 5485014c6f886d9a382c046f9025948eeed6c114accde2957424f1f613d1b51b
5
5
  SHA512:
6
- metadata.gz: 7b28dfd2876f0a01cac862905bdd9b1c30d88505d0457a319469ec4ae35cb87d0b592ac6b028a531c2a115249eb3a6abb527896a63a1e2155ed6712618d2cff4
7
- data.tar.gz: 4734fe3a428b07023963e7a01bf3a2853295a52ea4b308ddda8b82f8a0d09614ffabbc8d63c188b477b4a2f0f464ec76c70f6681b7423f7774b8205cbcefa4ad
6
+ metadata.gz: 336f61eb9e81ccf8fe859b0d05e5e4d1aaf734e06328169ce919a01fdf30caaebdb2f44e673b52cdde99e3790c413c854e486fd97e4c610b5ee6349c1e3dbe40
7
+ data.tar.gz: c08f83be388d6fdb646ea46439c0a65543091e401b9c9d38e312a7d2dc34313c3269f9c16916340d090f48ae224a1cd18631153d6478f87e32073f38e319ff28
@@ -1,9 +1,8 @@
1
1
  language: ruby
2
2
  rvm:
3
3
  - 2.7.0
4
- - 2.3.7
4
+ - 2.3.0
5
5
  - jruby-9.2.9.0
6
- #- rbx
7
6
 
8
7
  addons:
9
8
  code_climate:
data/README.md CHANGED
@@ -50,7 +50,7 @@ It does not check:
50
50
  By default, MX records are required in DNS. MX or "mail exchanger" records
51
51
  tell where to deliver email for the domain. Many domains run their
52
52
  website on one provider (ISP, Heroku, etc.), and email on a different
53
- provider (such as Google Apps). Note that `example.com`, while
53
+ provider (such as G Suite). Note that `example.com`, while
54
54
  a valid domain name, does not have MX records.
55
55
 
56
56
  ```ruby
@@ -248,6 +248,16 @@ EmailAddress.normal("HIRO@こんにちは世界.com")
248
248
  EmailAddress.normal("hiro@xn--28j2a3ar1pp75ovm7c.com", host_encoding: :unicode)
249
249
  #=> "hiro@こんにちは世界.com"
250
250
  ```
251
+ As of release 0.1.17, exchanger_match is no longer used for host provider
252
+ determination, which designated the set of rules for that domain.
253
+ Sometimes, as in Google-hosted domains, the address
254
+ rules are different, notably the optional dots in mailboxes for gmail.com
255
+ accounts do not apply to other private domains hosted at google.
256
+
257
+ To access the provider service, you can now call:
258
+
259
+ EmailAddress.new("user@hosteddomain.com").host.hosted_provider
260
+
251
261
 
252
262
  #### Rails Validator
253
263
 
@@ -446,14 +456,16 @@ EmailAddress::Config.provider(:github,
446
456
  You can override the default error messages as follows:
447
457
 
448
458
  ```ruby
449
- EmailAddress::Config.error_messages(
459
+ EmailAddress::Config.error_messages({
450
460
  invalid_address: "Invalid Email Address",
451
461
  invalid_mailbox: "Invalid Recipient/Mailbox",
452
462
  invalid_host: "Invalid Host/Domain Name",
453
463
  exceeds_size: "Address too long",
454
464
  not_allowed: "Address is not allowed",
455
- incomplete_domain: "Domain name is incomplete")
465
+ incomplete_domain: "Domain name is incomplete"}, 'en')
456
466
  ```
467
+ Note: Release 0.1.14 fixed setting error messages by locale.
468
+ Also, it will accept a ruby "collected" hash as before,
457
469
 
458
470
  Full translation support would be ideal though.
459
471
 
@@ -540,6 +552,33 @@ The value is an array of match tokens.
540
552
  * host_match: %w(.org example.com hotmail. user*@ sub.*.com)
541
553
  * exchanger_match: %w(google.com 127.0.0.1 10.9.8.0/24 ::1/64)
542
554
 
555
+ ### Namespace conflict resolution
556
+
557
+ If your application already uses the `EmailAddress` class name,
558
+ it's possible to create an alias prior to loading your code:
559
+
560
+ For a Rails application, you can do this in `config/application.rb`
561
+ after the `Bundler.require` line, usually:
562
+
563
+ ```ruby
564
+ Bundler.require(*Rails.groups)
565
+ ```
566
+
567
+ Add these lines immediately after that point:
568
+
569
+ ```ruby
570
+ EmailAddressValidator = EmailAddress
571
+ Object.send(:remove_const, :EmailAddress)
572
+ ```
573
+
574
+ Then your application loads with your EmailAddress class. You may
575
+ then use this gem with `EmailAddressValidator` or whatever name you
576
+ gave it above:
577
+
578
+ ```ruby
579
+ EmailAddressValidator.valid?("clark.kent@gmail.com") # => true
580
+ ```
581
+
543
582
  ## Notes
544
583
 
545
584
  #### Internationalization
@@ -13,6 +13,7 @@ Gem::Specification.new do |spec|
13
13
  spec.homepage = "https://github.com/afair/email_address"
14
14
  spec.license = "MIT"
15
15
 
16
+ #spec.required_ruby_version = ">= 2.3.0"
16
17
  spec.files = `git ls-files`.split($/)
17
18
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
19
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
@@ -40,31 +40,30 @@ module EmailAddress
40
40
  # secret to use in options[:secret]
41
41
  class << self
42
42
  (%i[valid? error normal redact munge canonical reference base srs] &
43
- EmailAddress::Address.public_instance_methods
43
+ Address.public_instance_methods
44
44
  ).each do |proxy_method|
45
45
  define_method(proxy_method) do |*args, &block|
46
- EmailAddress::Address.new(*args).public_send(proxy_method, &block)
46
+ Address.new(*args).public_send(proxy_method, &block)
47
47
  end
48
48
  end
49
- end
50
-
51
49
 
52
- # Creates an instance of this email address.
53
- # This is a short-cut to Email::Address::Address.new
54
- def self.new(email_address, config={})
55
- EmailAddress::Address.new(email_address, config)
56
- end
50
+ # Creates an instance of this email address.
51
+ # This is a short-cut to EmailAddress::Address.new
52
+ def new(email_address, config={})
53
+ Address.new(email_address, config)
54
+ end
57
55
 
58
- def self.new_redacted(email_address, config={})
59
- EmailAddress::Address.new(EmailAddress::Address.new(email_address, config).redact)
60
- end
56
+ def new_redacted(email_address, config={})
57
+ Address.new(Address.new(email_address, config).redact)
58
+ end
61
59
 
62
- def self.new_canonical(email_address, config={})
63
- EmailAddress::Address.new(EmailAddress::Address.new(email_address, config).canonical, config)
64
- end
60
+ def new_canonical(email_address, config={})
61
+ Address.new(Address.new(email_address, config).canonical, config)
62
+ end
65
63
 
66
- # Does the email address match any of the given rules
67
- def self.matches?(email_address, rules, config={})
68
- EmailAddress::Address.new(email_address, config).matches?(rules)
64
+ # Does the email address match any of the given rules
65
+ def matches?(email_address, rules, config={})
66
+ Address.new(email_address, config).matches?(rules)
67
+ end
69
68
  end
70
69
  end
@@ -35,10 +35,10 @@ module EmailAddress
35
35
 
36
36
  def validate_email(r,f)
37
37
  return if r[f].nil?
38
- e = EmailAddress.new(r[f])
38
+ e = Address.new(r[f])
39
39
  unless e.valid?
40
40
  r.errors[f] << (@opt[:message] ||
41
- EmailAddress::Config.error_messages[:invalid_address] ||
41
+ Config.error_messages[:invalid_address] ||
42
42
  "Invalid Email Address")
43
43
  end
44
44
  end
@@ -1,46 +1,45 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'digest/sha1'
4
- require 'digest/md5'
3
+ require "digest/sha1"
4
+ require "digest/md5"
5
5
 
6
6
  module EmailAddress
7
7
  # Implements the Email Address container, which hold the Local
8
- # (EmailAddress::Local) and Host (Email::AddressHost) parts.
8
+ # (EmailAddress::Local) and Host (EmailAddress::Host) parts.
9
9
  class Address
10
10
  include Comparable
11
- include EmailAddress::Rewriter
11
+ include Rewriter
12
12
 
13
13
  attr_accessor :original, :local, :host, :config, :reason
14
14
 
15
- CONVENTIONAL_REGEX = /\A#{::EmailAddress::Local::CONVENTIONAL_MAILBOX_WITHIN}
16
- @#{::EmailAddress::Host::DNS_HOST_REGEX}\z/x
17
- STANDARD_REGEX = /\A#{::EmailAddress::Local::STANDARD_LOCAL_WITHIN}
18
- @#{::EmailAddress::Host::DNS_HOST_REGEX}\z/x
19
- RELAXED_REGEX = /\A#{::EmailAddress::Local::RELAXED_MAILBOX_WITHIN}
20
- @#{::EmailAddress::Host::DNS_HOST_REGEX}\z/x
15
+ CONVENTIONAL_REGEX = /\A#{Local::CONVENTIONAL_MAILBOX_WITHIN}
16
+ @#{Host::DNS_HOST_REGEX}\z/x
17
+ STANDARD_REGEX = /\A#{Local::STANDARD_LOCAL_WITHIN}
18
+ @#{Host::DNS_HOST_REGEX}\z/x
19
+ RELAXED_REGEX = /\A#{Local::RELAXED_MAILBOX_WITHIN}
20
+ @#{Host::DNS_HOST_REGEX}\z/x
21
21
 
22
22
  # Given an email address of the form "local@hostname", this sets up the
23
23
  # instance, and initializes the address to the "normalized" format of the
24
24
  # address. The original string is available in the #original method.
25
- def initialize(email_address, config={})
26
- @config = config # This needs refactoring!
27
- @original = email_address
28
- email_address = (email_address || "").strip
29
- email_address = parse_rewritten(email_address) unless config[:skip_rewrite]
30
- local, host = EmailAddress::Address.split_local_host(email_address)
31
-
32
- @host = EmailAddress::Host.new(host, config)
33
- @config = @host.config
34
- @local = EmailAddress::Local.new(local, @config, @host)
35
- @error = @error_message = nil
25
+ def initialize(email_address, config = {})
26
+ @config = Config.new(config)
27
+ @original = email_address
28
+ email_address = (email_address || "").strip
29
+ email_address = parse_rewritten(email_address) unless config[:skip_rewrite]
30
+ local, host = Address.split_local_host(email_address)
31
+
32
+ @host = Host.new(host, @config)
33
+ @local = Local.new(local, @config, @host)
34
+ @error = @error_message = nil
36
35
  end
37
36
 
38
37
  # Given an email address, this returns an array of [local, host] parts
39
38
  def self.split_local_host(email)
40
- if lh = email.match(/(.+)@(.+)/)
41
- lh.to_a[1,2]
39
+ if (lh = email.match(/(.+)@(.+)/))
40
+ lh.to_a[1, 2]
42
41
  else
43
- [email, '']
42
+ [email, ""]
44
43
  end
45
44
  end
46
45
 
@@ -54,26 +53,26 @@ module EmailAddress
54
53
 
55
54
  # Everything to the left of the @ in the address, called the local part.
56
55
  def left
57
- self.local.to_s
56
+ local.to_s
58
57
  end
59
58
 
60
59
  # Returns the mailbox portion of the local port, with no tags. Usually, this
61
60
  # can be considered the user account or role account names. Some systems
62
61
  # employ dynamic email addresses which don't have the same meaning.
63
62
  def mailbox
64
- self.local.mailbox
63
+ local.mailbox
65
64
  end
66
65
 
67
66
  # Returns the tag part of the local address, or nil if not given.
68
67
  def tag
69
- self.local.tag
68
+ local.tag
70
69
  end
71
70
 
72
71
  # Retuns any comments parsed from the local part of the email address.
73
72
  # This is retained for inspection after construction, even if it is
74
73
  # removed from the normalized email address.
75
74
  def comment
76
- self.local.comment
75
+ local.comment
77
76
  end
78
77
 
79
78
  ############################################################################
@@ -87,8 +86,8 @@ module EmailAddress
87
86
  def host_name
88
87
  @host.host_name
89
88
  end
90
- alias :right :host_name
91
- alias :hostname :host_name
89
+ alias right host_name
90
+ alias hostname host_name
92
91
 
93
92
  # Returns the ESP (Email Service Provider) or ISP name derived
94
93
  # using the provider configuration rules.
@@ -104,18 +103,18 @@ module EmailAddress
104
103
  def normal
105
104
  if !@original
106
105
  @original
107
- elsif self.local.to_s.size == 0
106
+ elsif local.to_s.size == 0
108
107
  ""
109
- elsif self.host.to_s.size == 0
110
- self.local.to_s
108
+ elsif host.to_s.size == 0
109
+ local.to_s
111
110
  else
112
- "#{self.local.to_s}@#{self.host.to_s}"
111
+ "#{local}@#{host}"
113
112
  end
114
113
  end
115
- alias :to_s :normal
114
+ alias to_s normal
116
115
 
117
116
  def inspect
118
- "#<EmailAddress::Address:0x#{self.object_id.to_s(16)} address=\"#{self.to_s}\">"
117
+ "#<#{self.class}:0x#{object_id.to_s(16)} address=\"#{self}\">"
119
118
  end
120
119
 
121
120
  # Returns the canonical email address according to the provider
@@ -123,56 +122,56 @@ module EmailAddress
123
122
  # spaves and comments and tags, and any extraneous part of the address
124
123
  # not considered a unique account by the provider.
125
124
  def canonical
126
- c = self.local.canonical
127
- c += "@" + self.host.canonical if self.host.canonical && self.host.canonical > " "
125
+ c = local.canonical
126
+ c += "@" + host.canonical if host.canonical && host.canonical > " "
128
127
  c
129
128
  end
130
129
 
131
130
  # True if the given address is already in it's canonical form.
132
131
  def canonical?
133
- self.canonical == self.to_s
132
+ canonical == to_s
134
133
  end
135
134
 
136
135
  # The base address is the mailbox, without tags, and host.
137
136
  def base
138
- self.mailbox + "@" + self.hostname
137
+ mailbox + "@" + hostname
139
138
  end
140
139
 
141
140
  # Returns the redacted form of the address
142
141
  # This format is defined by this libaray, and may change as usage increases.
143
142
  # Takes either :sha1 (default) or :md5 as the argument
144
- def redact(digest=:sha1)
145
- raise "Unknown Digest type: #{digest}" unless %i(sha1 md5).include?(digest)
146
- return self.to_s if self.local.redacted?
147
- r = %Q({#{send(digest)}})
148
- r += "@" + self.host.to_s if self.host.to_s && self.host.to_s > " "
143
+ def redact(digest = :sha1)
144
+ raise "Unknown Digest type: #{digest}" unless %i[sha1 md5].include?(digest)
145
+ return to_s if local.redacted?
146
+ r = %({#{send(digest)}})
147
+ r += "@" + host.to_s if host.to_s && host.to_s > " "
149
148
  r
150
149
  end
151
150
 
152
151
  # True if the address is already in the redacted state.
153
152
  def redacted?
154
- self.local.redacted?
153
+ local.redacted?
155
154
  end
156
155
 
157
156
  # Returns the munged form of the address, by default "mailbox@domain.tld"
158
157
  # returns "ma*****@do*****".
159
158
  def munge
160
- [self.local.munge, self.host.munge].join("@")
159
+ [local.munge, host.munge].join("@")
161
160
  end
162
161
 
163
162
  # Returns and MD5 of the canonical address form. Some cross-system systems
164
163
  # use the email address MD5 instead of the actual address to refer to the
165
164
  # same shared user identity without exposing the actual address when it
166
165
  # is not known in common.
167
- def reference(form=:base)
168
- Digest::MD5.hexdigest(self.send(form))
166
+ def reference(form = :base)
167
+ Digest::MD5.hexdigest(send(form))
169
168
  end
170
- alias :md5 :reference
169
+ alias md5 reference
171
170
 
172
171
  # This returns the SHA1 digest (in a hex string) of the canonical email
173
172
  # address. See #md5 for more background.
174
- def sha1(form=:base)
175
- Digest::SHA1.hexdigest((self.send(form)||"") + (@config[:sha1_secret]||""))
173
+ def sha1(form = :base)
174
+ Digest::SHA1.hexdigest((send(form) || "") + (@config[:sha1_secret] || ""))
176
175
  end
177
176
 
178
177
  #---------------------------------------------------------------------------
@@ -182,41 +181,41 @@ module EmailAddress
182
181
  # Equal matches the normalized version of each address. Use the Threequal to check
183
182
  # for match on canonical or redacted versions of addresses
184
183
  def ==(other_email)
185
- self.to_s == other_email.to_s
184
+ to_s == other_email.to_s
186
185
  end
187
- alias :eql? :==
188
- alias :equal? :==
186
+ alias eql? ==
187
+ alias equal? ==
189
188
 
190
189
  # Return the <=> or CMP comparison operator result (-1, 0, +1) on the comparison
191
190
  # of this addres with another, using the canonical or redacted forms.
192
191
  def same_as?(other_email)
193
192
  if other_email.is_a?(String)
194
- other_email = EmailAddress::Address.new(other_email)
193
+ other_email = Address.new(other_email)
195
194
  end
196
195
 
197
- self.canonical == other_email.canonical ||
198
- self.redact == other_email.canonical ||
199
- self.canonical == other_email.redact
196
+ canonical == other_email.canonical ||
197
+ redact == other_email.canonical ||
198
+ canonical == other_email.redact
200
199
  end
201
- alias :include? :same_as?
200
+ alias include? same_as?
202
201
 
203
202
  # Return the <=> or CMP comparison operator result (-1, 0, +1) on the comparison
204
203
  # of this addres with another, using the normalized form.
205
204
  def <=>(other_email)
206
- self.to_s <=> other_email.to_s
205
+ to_s <=> other_email.to_s
207
206
  end
208
207
 
209
208
  # Address matches one of these Matcher rule patterns
210
209
  def matches?(*rules)
211
210
  rules.flatten!
212
- match = self.local.matches?(rules)
213
- match ||= self.host.matches?(rules)
211
+ match = local.matches?(rules)
212
+ match ||= host.matches?(rules)
214
213
  return match if match
215
214
 
216
215
  # Does "root@*.com" match "root@example.com" domain name
217
216
  rules.each do |r|
218
- if r =~ /.+@.+/
219
- return r if File.fnmatch?(r, self.to_s)
217
+ if r.match(/.+@.+/)
218
+ return r if File.fnmatch?(r, to_s)
220
219
  end
221
220
  end
222
221
  false
@@ -228,24 +227,24 @@ module EmailAddress
228
227
 
229
228
  # Returns true if this address is considered valid according to the format
230
229
  # configured for its provider, It test the normalized form.
231
- def valid?(options={})
230
+ def valid?(options = {})
232
231
  @error = nil
233
- unless self.local.valid?
234
- return set_error self.local.error
232
+ unless local.valid?
233
+ return set_error local.error
235
234
  end
236
- unless self.host.valid?
237
- return set_error self.host.error_message
235
+ unless host.valid?
236
+ return set_error host.error_message
238
237
  end
239
- if @config[:address_size] && !@config[:address_size].include?(self.to_s.size)
238
+ if @config[:address_size] && !@config[:address_size].include?(to_s.size)
240
239
  return set_error :exceeds_size
241
240
  end
242
241
  if @config[:address_validation].is_a?(Proc)
243
- unless @config[:address_validation].call(self.to_s)
242
+ unless @config[:address_validation].call(to_s)
244
243
  return set_error :not_allowed
245
244
  end
246
245
  else
247
- return false unless self.local.valid?
248
- return false unless self.host.valid?
246
+ return false unless local.valid?
247
+ return false unless host.valid?
249
248
  end
250
249
  true
251
250
  end
@@ -254,42 +253,37 @@ module EmailAddress
254
253
  # as an email address check, but is provided to assist in problem resolution.
255
254
  # If you abuse this, you *could* be blocked by the ESP.
256
255
  def connect
257
- begin
258
- smtp = Net::SMTP.new(self.host_name || self.ip_address)
259
- smtp.start(@config[:smtp_helo_name] || 'localhost')
260
- smtp.mailfrom @config[:smtp_mail_from] || 'postmaster@localhost'
261
- smtp.rcptto self.to_s
262
- #p [:connect]
256
+ smtp = Net::SMTP.new(host_name || ip_address)
257
+ smtp.start(@config[:smtp_helo_name] || "localhost")
258
+ smtp.mailfrom @config[:smtp_mail_from] || "postmaster@localhost"
259
+ smtp.rcptto to_s
260
+ # p [:connect]
261
+ smtp.finish
262
+ true
263
+ rescue Net::SMTPUnknownError => e
264
+ set_error(:address_unknown, e.to_s)
265
+ rescue Net::SMTPFatalError => e
266
+ set_error(:address_unknown, e.to_s)
267
+ rescue SocketError => e
268
+ set_error(:address_unknown, e.to_s)
269
+ ensure
270
+ if smtp&.started?
263
271
  smtp.finish
264
- true
265
- rescue Net::SMTPUnknownError => e
266
- set_error(:address_unknown, e.to_s)
267
- rescue Net::SMTPFatalError => e
268
- set_error(:address_unknown, e.to_s)
269
- rescue SocketError => e
270
- set_error(:address_unknown, e.to_s)
271
- ensure
272
- if smtp && smtp.started?
273
- smtp.finish
274
- end
275
- !!@error
276
272
  end
273
+ !!@error
277
274
  end
278
275
 
279
- def set_error(err, reason=nil)
276
+ def set_error(err, reason = nil)
280
277
  @error = err
281
- @reason= reason
282
- @error_message = EmailAddress::Config.error_message(err)
278
+ @reason = reason
279
+ @error_message = Config.error_message(err)
283
280
  false
284
281
  end
285
282
 
286
- def error_message
287
- @error_message
288
- end
283
+ attr_reader :error_message
289
284
 
290
285
  def error
291
- self.valid? ? nil : @error_message
286
+ valid? ? nil : @error_message
292
287
  end
293
-
294
288
  end
295
289
  end