Class: EmailAddress::Address

Inherits:
Object
  • Object
show all
Includes:
Comparable, Rewriter
Defined in:
lib/email_address/address.rb

Overview

Implements the Email Address container, which hold the Local (EmailAddress::Local) and Host (EmailAddress::Host) parts.

Constant Summary collapse

CONVENTIONAL_REGEX =
/\A#{Local::CONVENTIONAL_MAILBOX_WITHIN}
@#{Host::DNS_HOST_REGEX}\z/x
STANDARD_REGEX =
/\A#{Local::STANDARD_LOCAL_WITHIN}
@#{Host::DNS_HOST_REGEX}\z/x
RELAXED_REGEX =
/\A#{Local::RELAXED_MAILBOX_WITHIN}
@#{Host::DNS_HOST_REGEX}\z/x

Constants included from Rewriter

Rewriter::PRVS_REGEX, Rewriter::SRS_FORMAT_REGEX

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Rewriter

#batv_prvs, #parse_prvs, #parse_rewritten, #parse_srs, #prvs_day, #prvs_sign, #srs, #srs?, #srs_hash, #srs_tt, #verp

Constructor Details

#initialize(email_address, config = {}, locale = "en") ⇒ Address

Given an email address of the form “local@hostname”, this sets up the instance, and initializes the address to the “normalized” format of the address. The original string is available in the #original method.



26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/email_address/address.rb', line 26

def initialize(email_address, config = {}, locale = "en")
  @config = Config.new(config)
  @original = email_address
  @locale = locale
  email_address = (email_address || "").strip
  email_address = parse_rewritten(email_address) unless config[:skip_rewrite]
  local, host = Address.split_local_host(email_address)

  @host = Host.new(host, @config, locale)
  @local = Local.new(local, @config, @host, locale)
  @error = @error_message = nil
end

Instance Attribute Details

#configObject

Returns the value of attribute config.



14
15
16
# File 'lib/email_address/address.rb', line 14

def config
  @config
end

#error_messageObject (readonly)

Returns the value of attribute error_message.



293
294
295
# File 'lib/email_address/address.rb', line 293

def error_message
  @error_message
end

#hostObject

Returns the value of attribute host.



14
15
16
# File 'lib/email_address/address.rb', line 14

def host
  @host
end

#localObject

Returns the value of attribute local.



14
15
16
# File 'lib/email_address/address.rb', line 14

def local
  @local
end

#localeObject

Returns the value of attribute locale.



14
15
16
# File 'lib/email_address/address.rb', line 14

def locale
  @locale
end

#originalObject

Returns the value of attribute original.



14
15
16
# File 'lib/email_address/address.rb', line 14

def original
  @original
end

#reasonObject

Returns the value of attribute reason.



14
15
16
# File 'lib/email_address/address.rb', line 14

def reason
  @reason
end

Class Method Details

.split_local_host(email) ⇒ Object

Given an email address, this returns an array of [local, host] parts



40
41
42
43
44
45
46
# File 'lib/email_address/address.rb', line 40

def self.split_local_host(email)
  if (lh = email.match(/(.+)@(.+)/))
    lh.to_a[1, 2]
  else
    [email, ""]
  end
end

Instance Method Details

#<=>(other) ⇒ Object

Return the <=> or CMP comparison operator result (-1, 0, +1) on the comparison of this addres with another, using the normalized form.



210
211
212
# File 'lib/email_address/address.rb', line 210

def <=>(other)
  to_s <=> other.to_s
end

#==(other) ⇒ Object Also known as: eql?, equal?

Equal matches the normalized version of each address. Use the Threequal to check for match on canonical or redacted versions of addresses



189
190
191
# File 'lib/email_address/address.rb', line 189

def ==(other)
  to_s == other.to_s
end

#baseObject

The base address is the mailbox, without tags, and host.



138
139
140
# File 'lib/email_address/address.rb', line 138

def base
  mailbox + "@" + hostname
end

#canonicalObject

Returns the canonical email address according to the provider uniqueness rules. Usually, this downcases the address, removes spaves and comments and tags, and any extraneous part of the address not considered a unique account by the provider.



126
127
128
129
130
# File 'lib/email_address/address.rb', line 126

def canonical
  c = local.canonical
  c += "@" + host.canonical if host.canonical && host.canonical > " "
  c
end

#canonical?Boolean

True if the given address is already in it’s canonical form.

Returns:

  • (Boolean)


133
134
135
# File 'lib/email_address/address.rb', line 133

def canonical?
  canonical == to_s
end

#commentObject

Retuns any comments parsed from the local part of the email address. This is retained for inspection after construction, even if it is removed from the normalized email address.



76
77
78
# File 'lib/email_address/address.rb', line 76

def comment
  local.comment
end

#connectObject

Connects to host to test if user can receive email. This should NOT be performed as an email address check, but is provided to assist in problem resolution. If you abuse this, you could be blocked by the ESP.

NOTE: As of Ruby 3.1, Net::SMTP was moved from the standard library to the ‘net-smtp’ gem. In order to avoid adding that dependency for this experimental feature, please add the gem to your Gemfile and require it to use this feature.



265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
# File 'lib/email_address/address.rb', line 265

def connect
  smtp = Net::SMTP.new(host_name || ip_address)
  smtp.start(@config[:smtp_helo_name] || "localhost")
  smtp.mailfrom @config[:smtp_mail_from] || "postmaster@localhost"
  smtp.rcptto to_s
  # p [:connect]
  smtp.finish
  true
rescue Net::SMTPUnknownError => e
  set_error(:address_unknown, e.to_s)
rescue Net::SMTPFatalError => e
  set_error(:address_unknown, e.to_s)
rescue SocketError => e
  set_error(:address_unknown, e.to_s)
ensure
  if smtp&.started?
    smtp.finish
  end
  !!@error
end

#errorObject



295
296
297
# File 'lib/email_address/address.rb', line 295

def error
  valid? ? nil : @error_message
end

#host_nameObject Also known as: right, hostname

Returns the host name, the part to the right of the @ sign.



88
89
90
# File 'lib/email_address/address.rb', line 88

def host_name
  @host.host_name
end

#inspectObject



118
119
120
# File 'lib/email_address/address.rb', line 118

def inspect
  "#<#{self.class}:0x#{object_id.to_s(16)} address=\"#{self}\">"
end

#leftObject

Everything to the left of the @ in the address, called the local part.



57
58
59
# File 'lib/email_address/address.rb', line 57

def left
  local.to_s
end

#mailboxObject

Returns the mailbox portion of the local port, with no tags. Usually, this can be considered the user account or role account names. Some systems employ dynamic email addresses which don’t have the same meaning.



64
65
66
# File 'lib/email_address/address.rb', line 64

def mailbox
  local.mailbox
end

#matches?(*rules) ⇒ Boolean

Address matches one of these Matcher rule patterns

Returns:

  • (Boolean)


215
216
217
218
219
220
221
222
223
224
225
226
227
228
# File 'lib/email_address/address.rb', line 215

def matches?(*rules)
  rules.flatten!
  match = local.matches?(rules)
  match ||= host.matches?(rules)
  return match if match

  # Does "root@*.com" match "[email protected]" domain name
  rules.each do |r|
    if /.+@.+/.match?(r)
      return r if File.fnmatch?(r, to_s)
    end
  end
  false
end

#mungeObject

Returns the munged form of the address, by default “[email protected]” returns “ma*****@do*****”.



160
161
162
# File 'lib/email_address/address.rb', line 160

def munge
  [local.munge, host.munge].join("@")
end

#normalObject Also known as: to_s

Returns the string representation of the normalized email address.



105
106
107
108
109
110
111
112
113
114
115
# File 'lib/email_address/address.rb', line 105

def normal
  if !@original
    @original
  elsif local.to_s.size == 0
    ""
  elsif host.to_s.size == 0
    local.to_s
  else
    "#{local}@#{host}"
  end
end

#providerObject

Returns the ESP (Email Service Provider) or ISP name derived using the provider configuration rules.



96
97
98
# File 'lib/email_address/address.rb', line 96

def provider
  @host.provider
end

#redact(digest = :sha1) ⇒ Object

Returns the redacted form of the address This format is defined by this libaray, and may change as usage increases. Takes either :sha1 (default) or :md5 as the argument



145
146
147
148
149
150
151
# File 'lib/email_address/address.rb', line 145

def redact(digest = :sha1)
  raise "Unknown Digest type: #{digest}" unless %i[sha1 md5].include?(digest)
  return to_s if local.redacted?
  r = %({#{send(digest)}})
  r += "@" + host.to_s if host.to_s && host.to_s > " "
  r
end

#redacted?Boolean

True if the address is already in the redacted state.

Returns:

  • (Boolean)


154
155
156
# File 'lib/email_address/address.rb', line 154

def redacted?
  local.redacted?
end

#reference(form = :base) ⇒ Object Also known as: md5

Returns and MD5 of the base address form. Some cross-system systems use the email address MD5 instead of the actual address to refer to the same shared user identity without exposing the actual address when it is not known in common.



168
169
170
# File 'lib/email_address/address.rb', line 168

def reference(form = :base)
  Digest::MD5.hexdigest(send(form))
end

#same_as?(other_email) ⇒ Boolean Also known as: include?

Return the <=> or CMP comparison operator result (-1, 0, +1) on the comparison of this addres with another, using the canonical or redacted forms.

Returns:

  • (Boolean)


197
198
199
200
201
202
203
204
205
# File 'lib/email_address/address.rb', line 197

def same_as?(other_email)
  if other_email.is_a?(String)
    other_email = Address.new(other_email)
  end

  canonical == other_email.canonical ||
    redact == other_email.canonical ||
    canonical == other_email.redact
end

#set_error(err, reason = nil) ⇒ Object



286
287
288
289
290
291
# File 'lib/email_address/address.rb', line 286

def set_error(err, reason = nil)
  @error = err
  @reason = reason
  @error_message = Config.error_message(err, locale)
  false
end

#sha1(form = :base) ⇒ Object

This returns the SHA1 digest (in a hex string) of the base email address. See #md5 for more background.



175
176
177
# File 'lib/email_address/address.rb', line 175

def sha1(form = :base)
  Digest::SHA1.hexdigest((send(form) || "") + (@config[:sha1_secret] || ""))
end

#sha256(form = :base) ⇒ Object



179
180
181
# File 'lib/email_address/address.rb', line 179

def sha256(form = :base)
  Digest::SHA256.hexdigest((send(form) || "") + (@config[:sha256_secret] || ""))
end

#tagObject

Returns the tag part of the local address, or nil if not given.



69
70
71
# File 'lib/email_address/address.rb', line 69

def tag
  local.tag
end

#valid?(options = {}) ⇒ Boolean

Returns true if this address is considered valid according to the format configured for its provider, It test the normalized form.

Returns:

  • (Boolean)


236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
# File 'lib/email_address/address.rb', line 236

def valid?(options = {})
  @error = nil
  unless local.valid?
    return set_error local.error
  end
  unless host.valid?
    return set_error host.error_message
  end
  if @config[:address_size] && !@config[:address_size].include?(to_s.size)
    return set_error :exceeds_size
  end
  if @config[:address_validation].is_a?(Proc)
    unless @config[:address_validation].call(to_s)
      return set_error :not_allowed
    end
  else
    return false unless local.valid?
    return false unless host.valid?
  end
  true
end