lib/truemail/validate/mx.rb in truemail-0.1.3 vs lib/truemail/validate/mx.rb in truemail-0.1.4

- old
+ new

@@ -3,24 +3,65 @@ module Truemail module Validate class Mx < Truemail::Validate::Base require 'resolv' - ERROR = 'mx records not found' + ERROR = 'target host(s) not found' def run return false unless Truemail::Validate::Regex.check(result) result.domain = result.email[Truemail::RegexConstant::REGEX_DOMAIN_FROM_EMAIL, 1] - return true if success(!result.mail_servers.push(*mx_records).empty?) + return true if success(mx_lookup) add_error(Truemail::Validate::Mx::ERROR) false end private - def mx_records - mx_records = Resolv::DNS.open { |dns| dns.getresources(result.domain, Resolv::DNS::Resource::IN::MX) } - mx_records.sort_by(&:preference).map { |mx_record| mx_record.exchange.to_s } + def host_extractor_methods + %i[hosts_from_mx_records? hosts_from_cname_records? host_from_a_record?] + end + + def mx_lookup + host_extractor_methods.any? do |method| + Truemail::Validate::ResolverExecutionWrapper.call { send(method) } + end + end + + def fetch_target_hosts(hosts) + result.mail_servers.push(*hosts) + end + + def mx_records(domain) + Resolv::DNS.new.getresources(domain, Resolv::DNS::Resource::IN::MX).sort_by(&:preference).map do |mx_record| + Resolv.getaddress(mx_record.exchange.to_s) + end + end + + def mail_servers_found? + !result.mail_servers.empty? + end + + def hosts_from_mx_records? + fetch_target_hosts(mx_records(result.domain)) + mail_servers_found? + end + + def hosts_from_cname_records? + cname_records = Resolv::DNS.new.getresources(result.domain, Resolv::DNS::Resource::IN::CNAME) + return if cname_records.empty? + cname_records.each do |cname_record| + host = Resolv.getaddress(cname_record.name.to_s) + hostname = Resolv.getname(host) + found_hosts = mx_records(hostname) + fetch_target_hosts(found_hosts.empty? ? [host] : found_hosts) + end + mail_servers_found? + end + + def host_from_a_record? + fetch_target_hosts([Resolv.getaddress(result.domain)]) + mail_servers_found? end end end end