Skip to content

Instantly share code, notes, and snippets.

@andywenk
Created September 3, 2014 10:34
Show Gist options
  • Save andywenk/db295194310fb6003f26 to your computer and use it in GitHub Desktop.
Save andywenk/db295194310fb6003f26 to your computer and use it in GitHub Desktop.
simple email adress validator; checks if the server responds and has an MX or A record
require 'mail'
require 'resolv'
require 'net/telnet'
class EmailAddressValidator < ActiveModel::EachValidator
attr_reader :mail
def validate_each(record, attribute, value)
return if options[:allow_nil] && value.nil?
return if options[:allow_blank] && value.blank?
begin
@mail = Mail::Address.new(value)
ok = has_correct_syntax?(value)
ok &&= is_not_banned_domain?
ok &&= has_top_level_domain?
ok &&= is_valid_domain?
rescue Exception => e
ok = false
end
record.errors.add attribute, (options[:message] || :email_address) unless ok
end
private
def domain
mail.domain
end
def address
mail.address
end
def has_correct_syntax?(value)
domain && address == value
end
def is_not_banned_domain?
options[:banned_domains] ? !options[:banned_domains].include?(domain) : true
end
def has_top_level_domain?
mail.__send__(:tree).domain.dot_atom_text.elements.size > 1
end
def is_valid_domain?
has_domain_record(Resolv::DNS::Resource::IN::MX) || (has_domain_record(Resolv::DNS::Resource::IN::A) && is_port_open?)
end
def has_domain_record(type)
Resolv::DNS.open.getresources(domain, type).size > 0
end
def is_port_open?
unless (options[:no_port_check])
telnet = Net::Telnet::new(
'Host' => domain,
'Port' => '25',
'Timeout' => 5,
'Telnetmode' => false
)
telnet.close
true
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment