Module: ValidatesEmailFormatOf

Defined in:
lib/validates_email_format_of.rb

Defined Under Namespace

Modules: Validations

Constant Summary collapse

VERSION =
'1.4.7'
MessageScope =
defined?(ActiveModel) ? :activemodel : :activerecord
LocalPartSpecialChars =
Regexp.escape('!#$%&\'*-/=?+-^_`{|}~')
LocalPartUnquoted =
'([[:alnum:]' + LocalPartSpecialChars + ']+[\.]+)*[[:alnum:]' + LocalPartSpecialChars + '+]+'
LocalPartQuoted =
'\"([[:alnum:]' + LocalPartSpecialChars + '\.]|\\\\[\x00-\xFF])*\"'
Regex =
Regexp.new('\A(' + LocalPartUnquoted + '|' + LocalPartQuoted + '+)@(((\w+\-+[^_])|(\w+\.[a-z0-9-]*))*([a-z0-9\-\.]{1,63})\.[a-z]{2,6}(?:\.[a-z]{2,6})?\Z)', Regexp::EXTENDED | Regexp::IGNORECASE, 'n')

Class Method Summary collapse

Class Method Details

.validate_email_domain(email) ⇒ Object



14
15
16
17
18
19
20
# File 'lib/validates_email_format_of.rb', line 14

def self.validate_email_domain(email)
  domain = email.match(/\@(.+)/)[1]
  Resolv::DNS.open do |dns|
    @mx = dns.getresources(domain, Resolv::DNS::Resource::IN::MX) + dns.getresources(domain, Resolv::DNS::Resource::IN::A)
  end
  @mx.size > 0 ? true : false
end

.validate_email_format(email, options = {}) ⇒ Object

Validates whether the specified value is a valid email address. Returns nil if the value is valid, otherwise returns an array containing one or more validation error messages.

Configuration options:

  • message - A custom error message (default is: “does not appear to be valid”)

  • check_mx - Check for MX records (default is false)

  • 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 (default is ValidatesEmailFormatOf::Regex)</tt>

  • local_length Maximum number of characters allowed in the local part (default is 64)

  • domain_length Maximum number of characters allowed in the domain part (default is 255)



32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/validates_email_format_of.rb', line 32

def self.validate_email_format(email, options={})
    default_options = { :message => I18n.t(:invalid_email_address, :scope => [MessageScope, :errors, :messages], :default => 'does not appear to be valid'),
                        :check_mx => false,
                        :mx_message => I18n.t(:email_address_not_routable, :scope => [MessageScope, :errors, :messages], :default => 'is not routable'),
                        :with => ValidatesEmailFormatOf::Regex ,
                        :domain_length => 255,
                        :local_length => 64
                        }
    opts = options.merge(default_options) {|key, old, new| old}  # merge the default options into the specified options, retaining all specified options

    email.strip! if email

    # local part max is 64 chars, domain part max is 255 chars
    # TODO: should this decode escaped entities before counting?
    begin
      domain, local = email.reverse.split('@', 2)
    rescue
      return [ opts[:message] ]
    end

    unless email =~ opts[:with] and not email =~ /\.\./ and domain.length <= opts[:domain_length] and local.length <= opts[:local_length]
      return [ opts[:message] ]
    end

    if opts[:check_mx] and !ValidatesEmailFormatOf::validate_email_domain(email)
      return [ opts[:mx_message] ]
    end

    local.reverse!
        
    # check for proper escaping

    if local[0] == '"'
      local.gsub!(/\A\"|\"\Z/, '')
      escaped = false
      local.each_char do |c|
        if escaped
          escaped = false
        elsif c == '"' # can't have a double quote without a preceding backslash
          return [ opts[:mx_message] ]
        else
          escaped = c == '\\'
        end
      end

      return [ opts[:mx_message] ] if escaped
    end

    return nil    # represents no validation errors
end