Class: EmailAddress::Exchanger
- Inherits:
-
Object
- Object
- EmailAddress::Exchanger
- Includes:
- Enumerable
- Defined in:
- lib/email_address/exchanger.rb
Class Method Summary collapse
Instance Method Summary collapse
-
#domains ⇒ Object
Returns Array of domain names for the MX’ers, used to determine the Provider.
- #each(&block) ⇒ Object
-
#in_cidr?(cidr) ⇒ Boolean
Given a cidr (ip/bits) and ip address, returns true on match.
-
#initialize(host, config = {}) ⇒ Exchanger
constructor
A new instance of Exchanger.
-
#matches?(rules) ⇒ Boolean
Simple matcher, takes an array of CIDR addresses (ip/bits) and strings.
-
#mx_ips ⇒ Object
Returns an array of MX IP address (String) for the given email domain.
-
#mxers ⇒ Object
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]] If not found, returns [] Returns a dummy record when dns_lookup is turned off since it may exists, though may not find provider by MX name or IP.
-
#provider ⇒ Object
Returns the provider name based on the MX-er host names, or nil if not matched.
Constructor Details
#initialize(host, config = {}) ⇒ Exchanger
Returns a new instance of Exchanger.
24 25 26 27 28 |
# File 'lib/email_address/exchanger.rb', line 24 def initialize(host, config = {}) @host = host @config = config.is_a?(Hash) ? Config.new(config) : config @dns_disabled = @config[:host_validation] == :syntax || @config[:dns_lookup] == :off end |
Class Method Details
.cached(host, config = {}) ⇒ Object
10 11 12 13 14 15 16 17 18 19 20 21 22 |
# File 'lib/email_address/exchanger.rb', line 10 def self.cached(host, config = {}) @host_cache ||= {} @cache_size ||= ENV["EMAIL_ADDRESS_CACHE_SIZE"].to_i || 100 if @host_cache.has_key?(host) o = @host_cache.delete(host) @host_cache[host] = o # LRU cache, move to end elsif @host_cache.size >= @cache_size @host_cache.delete(@host_cache.keys.first) @host_cache[host] = new(host, config) else @host_cache[host] = new(host, config) end end |
Instance Method Details
#domains ⇒ Object
Returns Array of domain names for the MX’ers, used to determine the Provider
77 78 79 |
# File 'lib/email_address/exchanger.rb', line 77 def domains @_domains ||= mxers.map { |m| Host.new(m.first).domain_name }.sort.uniq end |
#each(&block) ⇒ Object
30 31 32 33 34 35 |
# File 'lib/email_address/exchanger.rb', line 30 def each(&block) return if @dns_disabled mxers.each do |m| yield({host: m[0], ip: m[1], priority: m[2]}) end end |
#in_cidr?(cidr) ⇒ Boolean
Given a cidr (ip/bits) and ip address, returns true on match. Caches cidr object.
106 107 108 109 110 |
# File 'lib/email_address/exchanger.rb', line 106 def in_cidr?(cidr) net = IPAddr.new(cidr) found = mx_ips.detect { |ip| net.include?(IPAddr.new(ip)) } !!found end |
#matches?(rules) ⇒ Boolean
Simple matcher, takes an array of CIDR addresses (ip/bits) and strings. Returns true if any MX IP matches the CIDR or host name ends in string. Ex: match?(%w(127.0.0.1/32 0:0:1/64 .yahoodns.net)) Note: Your networking stack may return IPv6 addresses instead of IPv4 when both are available. If matching on IP, be sure to include both IPv4 and IPv6 forms for matching for hosts running on IPv6 (like gmail).
93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/email_address/exchanger.rb', line 93 def matches?(rules) rules = Array(rules) rules.each do |rule| if rule.include?("/") return rule if in_cidr?(rule) else each { |mx| return rule if mx[:host].end_with?(rule) } end end false end |
#mx_ips ⇒ Object
Returns an array of MX IP address (String) for the given email domain
82 83 84 85 |
# File 'lib/email_address/exchanger.rb', line 82 def mx_ips return ["0.0.0.0"] if @dns_disabled mxers.map { |m| m[1] } end |
#mxers ⇒ Object
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]] If not found, returns [] Returns a dummy record when dns_lookup is turned off since it may exists, though may not find provider by MX name or IP. I’m not sure about the “0.0.0.0” ip, it should be good in this context, but in “listen” context it means “all bound IP’s”
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/email_address/exchanger.rb', line 53 def mxers return [["example.com", "0.0.0.0", 1]] if @dns_disabled @mxers ||= Resolv::DNS.open { |dns| dns.timeouts = @config[:dns_timeout] if @config[:dns_timeout] ress = begin dns.getresources(@host, Resolv::DNS::Resource::IN::MX) rescue Resolv::ResolvTimeout [] end records = ress.map { |r| if r.exchange.to_s > " " [r.exchange.to_s, IPSocket.getaddress(r.exchange.to_s), r.preference] end } records.compact } # not found, but could also mean network not work or it could mean one record doesn't resolve an address rescue SocketError [["example.com", "0.0.0.0", 1]] end |
#provider ⇒ Object
Returns the provider name based on the MX-er host names, or nil if not matched
38 39 40 41 42 43 44 45 46 |
# File 'lib/email_address/exchanger.rb', line 38 def provider return @provider if defined? @provider Config.providers.each do |provider, config| if config[:exchanger_match] && matches?(config[:exchanger_match]) return @provider = provider end end @provider = :default end |