diff --git a/lib/validates_email_format_of.rb b/lib/validates_email_format_of.rb index 92e5c4b..3e03e08 100644 --- a/lib/validates_email_format_of.rb +++ b/lib/validates_email_format_of.rb @@ -11,9 +11,10 @@ def self.load_i18n_locales LocalPartSpecialChars = /[\!\#\$\%\&\'\*\-\/\=\?\+\^\_\`\{\|\}\~]/ - def self.validate_email_domain(email) + def self.validate_email_domain(email, check_mx_timeout: 3) domain = email.to_s.downcase.match(/\@(.+)/)[1] Resolv::DNS.open do |dns| + dns.timeouts = check_mx_timeout @mx = dns.getresources(domain, Resolv::DNS::Resource::IN::MX) + dns.getresources(domain, Resolv::DNS::Resource::IN::A) end @mx.size > 0 ? true : false @@ -34,6 +35,7 @@ def self.default_message # Configuration options: # * message - A custom error message (default is: "does not appear to be valid") # * check_mx - Check for MX records (default is false) + # * check_mx_timeout - Timeout in seconds for checking MX records before a `ResolvTimeout` is raised (default is 3 # * mx_message - A custom error message when an MX record validation fails (default is: "is not routable.") # * with The regex to use for validating the format of the email address (deprecated) # * local_length Maximum number of characters allowed in the local part (default is 64) @@ -42,6 +44,7 @@ def self.default_message def self.validate_email_format(email, options={}) default_options = { :message => options[:generate_message] ? ERROR_MESSAGE_I18N_KEY : default_message, :check_mx => false, + :check_mx_timeout => 3, :mx_message => options[:generate_message] ? ERROR_MX_MESSAGE_I18N_KEY : (defined?(I18n) ? I18n.t(ERROR_MX_MESSAGE_I18N_KEY, :scope => [:activemodel, :errors, :messages], :default => DEFAULT_MX_MESSAGE) : DEFAULT_MX_MESSAGE), :domain_length => 255, :local_length => 64, @@ -70,7 +73,7 @@ def self.validate_email_format(email, options={}) return [ opts[:message] ] unless self.validate_local_part_syntax(local) and self.validate_domain_part_syntax(domain) end - if opts[:check_mx] and !self.validate_email_domain(email) + if opts[:check_mx] and !self.validate_email_domain(email, check_mx_timeout: opts[:check_mx_timeout]) return [ opts[:mx_message] ] end diff --git a/spec/validates_email_format_of_spec.rb b/spec/validates_email_format_of_spec.rb index 667586e..d660a9c 100644 --- a/spec/validates_email_format_of_spec.rb +++ b/spec/validates_email_format_of_spec.rb @@ -175,12 +175,14 @@ def initialize(email) describe "mx record" do domain = "example.com" email = "valid@#{domain}" + check_mx_timeout = 3 describe "when testing" do let(:dns) { double(Resolv::DNS) } let(:mx_record) { [double] } let(:a_record) { [double] } before(:each) do allow(Resolv::DNS).to receive(:open).and_yield(dns) + expect(dns).to receive(:"timeouts=").with(3).once allow(dns).to receive(:getresources).with(domain, Resolv::DNS::Resource::IN::MX).once.and_return(mx_record) allow(dns).to receive(:getresources).with(domain, Resolv::DNS::Resource::IN::A).once.and_return(a_record) end