email_address 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/README.md +99 -32
- data/email_address.gemspec +2 -1
- data/lib/email_address.rb +14 -142
- data/lib/email_address/address.rb +70 -0
- data/lib/email_address/config.rb +75 -0
- data/lib/email_address/domain_matcher.rb +90 -0
- data/lib/email_address/domain_parser.rb +71 -0
- data/lib/email_address/exchanger.rb +67 -0
- data/lib/email_address/host.rb +71 -1
- data/lib/email_address/local.rb +97 -0
- data/lib/email_address/validator.rb +135 -0
- data/lib/email_address/version.rb +1 -1
- data/test/email_address/test_address.rb +30 -0
- data/test/email_address/test_config.rb +13 -0
- data/test/email_address/test_domain_matcher.rb +15 -0
- data/test/email_address/test_domain_parser.rb +29 -0
- data/test/email_address/test_exchanger.rb +19 -0
- data/test/email_address/test_host.rb +43 -0
- data/test/email_address/test_local.rb +27 -0
- data/test/email_address/test_validator.rb +16 -0
- data/test/test_email_address.rb +12 -0
- metadata +40 -27
- data/lib/email_address/esp.rb +0 -4
- data/lib/email_address/providers/default.rb +0 -8
- data/lib/email_address/providers/google.rb +0 -8
- data/lib/email_providers/address.rb +0 -102
- data/lib/email_providers/config.rb +0 -36
- data/lib/email_providers/factory.rb +0 -17
- data/lib/email_providers/host.rb +0 -87
- data/lib/email_providers/mail_exchanger.rb +0 -60
- data/lib/email_providers/mailbox.rb +0 -44
- data/lib/email_providers/providers/default.rb +0 -55
- data/lib/email_providers/providers/google.rb +0 -27
- data/lib/email_providers/version.rb +0 -3
- data/test/email_address.rb +0 -52
- data/test/email_address/address.rb +0 -16
- data/test/email_address/config.rb +0 -13
- data/test/email_address/host.rb +0 -29
- data/test/email_address/mail_exchanger.rb +0 -9
@@ -1,36 +0,0 @@
|
|
1
|
-
module EmailAddress
|
2
|
-
class Config
|
3
|
-
|
4
|
-
# EmailAddress::Config.add_provider(:google, domain_names:["gmail.com", "googlemail.com", "google.com"])
|
5
|
-
def self.add_provider(provider, matches={})
|
6
|
-
@pmatch ||= []
|
7
|
-
@pmatch << matches
|
8
|
-
end
|
9
|
-
|
10
|
-
# EmailAddress::Config.config do .... end
|
11
|
-
def self.setup(&block)
|
12
|
-
@config = Config::DSL.new(&block)
|
13
|
-
@config.instance_eval(&block)
|
14
|
-
end
|
15
|
-
|
16
|
-
def self.get
|
17
|
-
@config
|
18
|
-
end
|
19
|
-
|
20
|
-
class DSL
|
21
|
-
attr_accessor :provider_matching_rules
|
22
|
-
def add_provider(provider, matches={})
|
23
|
-
puts provider, matches
|
24
|
-
@provider_matching_rules ||= []
|
25
|
-
@provider_matching_rules << {provider:provider, matches:matches}
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
|
32
|
-
#EmailAddress::Config.setup do
|
33
|
-
# add_provider :google, domain_names:["gmail.com", "googlemail.com", "google.com"]
|
34
|
-
#end
|
35
|
-
|
36
|
-
#puts EmailAddress::Config.provider_matching_rules
|
@@ -1,17 +0,0 @@
|
|
1
|
-
module EmailAddress
|
2
|
-
|
3
|
-
# EmailAddress::Address - Inspects a Email Address.
|
4
|
-
#
|
5
|
-
# Format: mailbox@hostname
|
6
|
-
#
|
7
|
-
class Factory
|
8
|
-
attr_reader :mailbox, :host
|
9
|
-
|
10
|
-
def address(address)
|
11
|
-
(@mailbox, host) = address.strip.split(/\@/)
|
12
|
-
return unless host
|
13
|
-
@host = EmailAddress::Host.new(host)
|
14
|
-
@mailbox = @host.provider_address(@mailbox)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
data/lib/email_providers/host.rb
DELETED
@@ -1,87 +0,0 @@
|
|
1
|
-
# EmailAddress::Address
|
2
|
-
# EmailAddress::Host
|
3
|
-
# EmailAddress::MailExchanger
|
4
|
-
# EmailAddress::Config
|
5
|
-
# EmailAddress::EspMapping
|
6
|
-
# EmailAddress::Esp::Base, Yahoo, Msn, ...
|
7
|
-
|
8
|
-
require 'simpleidn'
|
9
|
-
|
10
|
-
module EmailAddress
|
11
|
-
|
12
|
-
# EmailAddress::Host handles mail host properties of an email address
|
13
|
-
# The host is typically the data to the right of the @ in the address
|
14
|
-
# and consists of:
|
15
|
-
#
|
16
|
-
# * hostname - full name of DNS host with the MX record.
|
17
|
-
# * domain_name - generally, the name and TLD without subdomain
|
18
|
-
# * base_domain - the identity name of the domain name, without the tld
|
19
|
-
# * tld (top-level-domain), like .com, .co.jp, .com.xx, etc.
|
20
|
-
# * subdomain - optional name of server/service under the domain
|
21
|
-
# * esp (email service provider) a name of the provider: yahoo, msn, etc.
|
22
|
-
# * dns_hostname - Converted hostname Unicode to Punycode
|
23
|
-
|
24
|
-
class Host
|
25
|
-
attr_reader :host, :domain_name, :tld, :base_domain, :subdomains, :dns_hostname
|
26
|
-
|
27
|
-
def initialize(host)
|
28
|
-
host.gsub!(/\A.*@/, '')
|
29
|
-
host.downcase!
|
30
|
-
self.host = host
|
31
|
-
end
|
32
|
-
|
33
|
-
def address(mailbox)
|
34
|
-
# Determine EmailAddress::Provider::Xxxx
|
35
|
-
EmailAddress::Address.new(mailbox, self)
|
36
|
-
end
|
37
|
-
|
38
|
-
def host=(host)
|
39
|
-
@host = host
|
40
|
-
# Patterns: *.com, *.xx.cc, *.cc
|
41
|
-
if @host =~ /(.+)\.(\w{3,10})\z/ || @host =~ /(.+)\.(\w{1,3}\.\w\w)\z/ || @host =~ /(.+)\.(\w\w)\z/
|
42
|
-
@tld = $2;
|
43
|
-
sld = $1 # Second level domain
|
44
|
-
if @sld =~ /(.+)\.(.+)$/ # is subdomain?
|
45
|
-
@subdomains = $1
|
46
|
-
@base_domain = $2
|
47
|
-
else
|
48
|
-
@subdomains = ""
|
49
|
-
@base_domain = sld
|
50
|
-
end
|
51
|
-
@domain_name = @base_domain + '.' + @tld
|
52
|
-
@dns_hostname = SimpleIDN.to_ascii(@host)
|
53
|
-
@host
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
# Resets the host to the domain name, dropping any subdomain
|
58
|
-
def drop_subdomain!
|
59
|
-
self.hostname = domain_name
|
60
|
-
end
|
61
|
-
|
62
|
-
def valid?
|
63
|
-
return false unless valid_format?
|
64
|
-
return false unless valid_mx?
|
65
|
-
true
|
66
|
-
end
|
67
|
-
|
68
|
-
def valid_format?
|
69
|
-
Host.valid_format?(@host)
|
70
|
-
end
|
71
|
-
|
72
|
-
def self.valid_format?(host)
|
73
|
-
return false unless host.match(/\A([0-9a-z\-]{1,63}\.)+[a-z0-9\-]{2,15}\z/)
|
74
|
-
return false unless host.length <= 253
|
75
|
-
true
|
76
|
-
end
|
77
|
-
|
78
|
-
def valid_mx?
|
79
|
-
Host.valid_mx?(@host)
|
80
|
-
end
|
81
|
-
|
82
|
-
def self.valid_mx?(host)
|
83
|
-
true
|
84
|
-
end
|
85
|
-
|
86
|
-
end
|
87
|
-
end
|
@@ -1,60 +0,0 @@
|
|
1
|
-
require 'resolv'
|
2
|
-
require 'netaddr'
|
3
|
-
require 'socket'
|
4
|
-
|
5
|
-
class MailExchanger
|
6
|
-
cattr_accessor :domains, :lookups
|
7
|
-
|
8
|
-
def self.valid_mx?(domain)
|
9
|
-
dns_a_record_exists?(domain) || mxers(domain).size > 0
|
10
|
-
end
|
11
|
-
|
12
|
-
def self.dns_a_record_exists?(domain)
|
13
|
-
@dns_a_record ||= {}
|
14
|
-
@dns_a_record[domain] = false
|
15
|
-
if Socket.gethostbyname(domain)
|
16
|
-
return @dns_a_record[domain] = true
|
17
|
-
end
|
18
|
-
rescue SocketError # not found
|
19
|
-
@dns_a_record[domain] = false
|
20
|
-
end
|
21
|
-
|
22
|
-
# Returns DNS A record results for the domain as: [[domain, ip, 0],...]
|
23
|
-
def self.domain_hosts(domain)
|
24
|
-
@domain_hosts ||= {}
|
25
|
-
@domain_hosts[domain] = []
|
26
|
-
res = TCPSocket.gethostbyname(domain)
|
27
|
-
res = res.slice(3, res.size)
|
28
|
-
res.each { |r| @domain_hosts[domain] << [domain, r, 0] }
|
29
|
-
@domain_hosts[domain]
|
30
|
-
|
31
|
-
rescue SocketError
|
32
|
-
return []
|
33
|
-
end
|
34
|
-
|
35
|
-
# 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]]
|
36
|
-
# If not found, returns []
|
37
|
-
def self.mxers(domain)
|
38
|
-
@domains ||= {}
|
39
|
-
return @domains[domain] if @domains.key?(domain)
|
40
|
-
@lookups = @lookups ? @lookups + 1 : 1
|
41
|
-
mx = nil
|
42
|
-
mxs = Resolv::DNS.open do |dns|
|
43
|
-
ress = dns.getresources domain, Resolv::DNS::Resource::IN::MX
|
44
|
-
ress.map { |r| [r.exchange.to_s, IPSocket::getaddress(r.exchange.to_s), r.preference] }
|
45
|
-
end
|
46
|
-
@domains[domain] = mxs
|
47
|
-
end
|
48
|
-
|
49
|
-
# Returns an array of MX IP address (String) for the given email domain
|
50
|
-
def self.mx_ips(domain)
|
51
|
-
mxers(domain).map {|m| m[1] }
|
52
|
-
end
|
53
|
-
|
54
|
-
# Given a cidr (ip/bits) and ip address, returns true on match. Caches cidr object.
|
55
|
-
def self.in_cidr?(cidr, ip)
|
56
|
-
@cidrs ||= {}
|
57
|
-
@cidrs[cidr] ||= NetAddr::CIDR.create(cidr)
|
58
|
-
@cidrs[cidr].matches?(ip)
|
59
|
-
end
|
60
|
-
end
|
@@ -1,44 +0,0 @@
|
|
1
|
-
module EmailAddress
|
2
|
-
|
3
|
-
# EmailAddress::Mailbox - Left side of the @
|
4
|
-
#
|
5
|
-
# * mailbox - Everything to the left of the @
|
6
|
-
# * account - part of the mailbox typically sent to a user
|
7
|
-
# * tags - Address tags appended to the account for tracking
|
8
|
-
#
|
9
|
-
class Mailbox
|
10
|
-
attr_reader :mailbox, :account, :tags, :provider
|
11
|
-
|
12
|
-
def initialize(mailbox, mail_provider=nil)
|
13
|
-
@provider = mail_provider
|
14
|
-
@mailbox = mailbox
|
15
|
-
end
|
16
|
-
|
17
|
-
def to_s
|
18
|
-
@mailbox
|
19
|
-
end
|
20
|
-
|
21
|
-
def mailbox=(mailbox)
|
22
|
-
@mailbox = mailbox.strip.downcase
|
23
|
-
(@account, @tags) = @mailbox.split(@provider.tag_separator)
|
24
|
-
@mailbox
|
25
|
-
end
|
26
|
-
|
27
|
-
def valid?
|
28
|
-
return false unless provider.valid?(mailbox)
|
29
|
-
true
|
30
|
-
end
|
31
|
-
|
32
|
-
def valid_format?
|
33
|
-
return false unless provider.valid_format?(mailbox)
|
34
|
-
#return false unless @mailbox =~ /\A\w[\w\.\-\+\']*\z/
|
35
|
-
true
|
36
|
-
end
|
37
|
-
|
38
|
-
# Returns true if the email account is a standard reserved address
|
39
|
-
def reserved?
|
40
|
-
%Q(postmaster abuse).include?(account)
|
41
|
-
end
|
42
|
-
|
43
|
-
end
|
44
|
-
end
|
@@ -1,55 +0,0 @@
|
|
1
|
-
module EmailAddress
|
2
|
-
module Providers
|
3
|
-
class Default
|
4
|
-
def initialize(address)
|
5
|
-
@mailbox = mailbox
|
6
|
-
end
|
7
|
-
|
8
|
-
def account(mailbox)
|
9
|
-
mailbox
|
10
|
-
end
|
11
|
-
|
12
|
-
def provider
|
13
|
-
'default'
|
14
|
-
end
|
15
|
-
|
16
|
-
def tag_separator
|
17
|
-
'+'
|
18
|
-
end
|
19
|
-
|
20
|
-
def case_sensitive_mailbox
|
21
|
-
false
|
22
|
-
end
|
23
|
-
|
24
|
-
def max_domain_length
|
25
|
-
253
|
26
|
-
end
|
27
|
-
|
28
|
-
def max_email_length
|
29
|
-
254
|
30
|
-
end
|
31
|
-
|
32
|
-
# Letters, numbers, period (no start) 6-30chars
|
33
|
-
def max_mailbox_length
|
34
|
-
64
|
35
|
-
end
|
36
|
-
|
37
|
-
# Letters, numbers, period (no start) 6-30chars
|
38
|
-
def user_pattern
|
39
|
-
/\A[a-z0-9][\.\'a-z0-9]{5,29}\z/i
|
40
|
-
end
|
41
|
-
|
42
|
-
def valid?
|
43
|
-
return false unless valid_format?
|
44
|
-
end
|
45
|
-
|
46
|
-
def valid_format?
|
47
|
-
return false if mailbox.length > max_mailbox_length
|
48
|
-
return false if address.length > max_email_length
|
49
|
-
return false unless mailbox.to_s.match(user_pattern)
|
50
|
-
true
|
51
|
-
end
|
52
|
-
|
53
|
-
end
|
54
|
-
end
|
55
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
module EmailAddress
|
2
|
-
module Providers
|
3
|
-
class Google < Default
|
4
|
-
def account
|
5
|
-
account.gsub(/\./. '')
|
6
|
-
end
|
7
|
-
|
8
|
-
def provider
|
9
|
-
'google'
|
10
|
-
end
|
11
|
-
|
12
|
-
def tag_separator
|
13
|
-
'+'
|
14
|
-
end
|
15
|
-
|
16
|
-
def case_sensitive_mailbox
|
17
|
-
false
|
18
|
-
end
|
19
|
-
|
20
|
-
# Letters, numbers, period (no start) 6-30chars
|
21
|
-
def user_pattern
|
22
|
-
/\A[a-z0-9][\.a-z0-9]{5,29}\z/i
|
23
|
-
end
|
24
|
-
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
data/test/email_address.rb
DELETED
@@ -1,52 +0,0 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
require_relative 'test_helper'
|
3
|
-
|
4
|
-
class TestEmailAddress < MiniTest::Unit::TestCase
|
5
|
-
def test_address
|
6
|
-
a = EmailAddress.new('user@example.com')
|
7
|
-
assert_equal a.local, 'user'
|
8
|
-
assert_equal a.tag, ''
|
9
|
-
assert_equal a.comment, ''
|
10
|
-
assert_equal a.domain, 'example.com'
|
11
|
-
assert_equal a.subdomains, ''
|
12
|
-
assert_equal a.base_domain, 'example'
|
13
|
-
assert_equal a.dns_hostname, 'example.com'
|
14
|
-
assert_equal a.top_level_domain, 'com'
|
15
|
-
assert_equal a.to_s, 'user@example.com'
|
16
|
-
end
|
17
|
-
|
18
|
-
def test_foreign_address
|
19
|
-
a = EmailAddress.new("user@sub.example.co.jp")
|
20
|
-
assert_equal a.domain, "sub.example.co.jp"
|
21
|
-
assert_equal a.subdomains, "sub"
|
22
|
-
assert_equal a.domain_name, "example.co.jp"
|
23
|
-
assert_equal a.base_domain, "example"
|
24
|
-
assert_equal a.top_level_domain, "co.jp"
|
25
|
-
end
|
26
|
-
|
27
|
-
def test_address_tag
|
28
|
-
a = EmailAddress.new('user+etc@example.com')
|
29
|
-
assert_equal a.account, 'user'
|
30
|
-
assert_equal a.tag, 'etc'
|
31
|
-
assert_equal a.unique_address, 'user@example.com'
|
32
|
-
end
|
33
|
-
|
34
|
-
def test_address_comment
|
35
|
-
a = EmailAddress.new('(comment)user@example.com')
|
36
|
-
assert_equal a.comment, 'comment'
|
37
|
-
assert_equal a.account, 'user'
|
38
|
-
assert_equal a.unique_address, 'user@example.com'
|
39
|
-
end
|
40
|
-
|
41
|
-
def test_user_validation
|
42
|
-
a = EmailAddress.new("user@example.co.jp")
|
43
|
-
assert a.valid? == true
|
44
|
-
end
|
45
|
-
|
46
|
-
def test_unicode_domain
|
47
|
-
a = EmailAddress.new("User@København.eu")
|
48
|
-
assert_equal a.dns_hostname, 'xn--kbenhavn-54a.eu'
|
49
|
-
assert_equal a.unique_address, 'user@xn--kbenhavn-54a.eu'
|
50
|
-
end
|
51
|
-
|
52
|
-
end
|
@@ -1,16 +0,0 @@
|
|
1
|
-
#encoding: utf-8
|
2
|
-
require_relative '../test_helper'
|
3
|
-
|
4
|
-
class TestAddress < MiniTest::Unit::TestCase
|
5
|
-
def test_address
|
6
|
-
a = EmailAddress.new("User+tag@example.com")
|
7
|
-
assert_equal "user", a.account
|
8
|
-
assert_equal "user+tag", a.local
|
9
|
-
assert_equal "user@example.com", a.unique_address
|
10
|
-
end
|
11
|
-
|
12
|
-
def test_unicode_user
|
13
|
-
a = EmailAddress.new("å@example.com")
|
14
|
-
assert_equal false, a.valid_format?
|
15
|
-
end
|
16
|
-
end
|
@@ -1,13 +0,0 @@
|
|
1
|
-
#encoding: utf-8
|
2
|
-
require_relative '../test_helper'
|
3
|
-
#require 'minitest/autorun'
|
4
|
-
|
5
|
-
class TestConfig < MiniTest::Unit::TestCase
|
6
|
-
def test_config
|
7
|
-
EmailAddress::Config.setup do
|
8
|
-
add_provider :google, domain_names: %w(gmail.com googlemail.com google.com)
|
9
|
-
end
|
10
|
-
assert_equal EmailAddress::Config.get.provider_matching_rules.first[:provider], :google
|
11
|
-
end
|
12
|
-
|
13
|
-
end
|
data/test/email_address/host.rb
DELETED
@@ -1,29 +0,0 @@
|
|
1
|
-
# encoding: UTF-8
|
2
|
-
require_relative '../test_helper'
|
3
|
-
|
4
|
-
|
5
|
-
class TestHost < MiniTest::Unit::TestCase
|
6
|
-
def test_host
|
7
|
-
a = EmailAddress::Host.new("example.com")
|
8
|
-
assert_equal "example.com", a.host
|
9
|
-
assert_equal "example.com", a.domain_name
|
10
|
-
assert_equal "example", a.base_domain
|
11
|
-
assert_equal ".com", a.tld
|
12
|
-
assert_equal "", a.subdomains
|
13
|
-
end
|
14
|
-
|
15
|
-
def test_foreign_host
|
16
|
-
a = EmailAddress::Host.new("yahoo.co.jp")
|
17
|
-
assert_equal "yahoo.co.jp", a.host
|
18
|
-
assert_equal "yahoo.co.jp", a.domain_name
|
19
|
-
assert_equal "yahoo", a.base_domain
|
20
|
-
assert_equal "co.jp", a.tld
|
21
|
-
assert_equal "", a.subdomains
|
22
|
-
end
|
23
|
-
|
24
|
-
def test_unicode_host
|
25
|
-
a = EmailAddress::Host.new("å.com")
|
26
|
-
assert_equal "xn--5ca.com", a.dns_hostname
|
27
|
-
end
|
28
|
-
|
29
|
-
end
|