Created
May 18, 2017 19:10
-
-
Save Sohair63/05dc155eb65cc9243e6eef0fd4f53c62 to your computer and use it in GitHub Desktop.
This is custom email format validation service that hold all the cases.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'resolv.rb' | |
class EmailValidationService | |
DOMAIN_LENGTH = 255 | |
LOCAL_LENGTH = 64 | |
LOCAL_PART_SPECIAL_CHAR = /[\!\#\$\%\&\'\*\-\/\=\?\+\-\^\_\`\{\|\}\~]/ | |
def self.valid_email_format?(email) | |
begin | |
domain, local = email.reverse.split('@', 2) | |
rescue | |
return false | |
end | |
return false if local.blank? | |
return false if domain.blank? | |
return false if local.length > LOCAL_LENGTH | |
return false if domain.length > DOMAIN_LENGTH | |
local.reverse! | |
domain.reverse! | |
return false unless self.validate_local_part_syntax(local) && self.validate_domain_part_syntax(domain) | |
return false unless self.validate_email_domain(email) | |
true | |
end | |
def self.validate_email_domain(email) | |
domain = email.to_s.downcase.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 | |
def self.validate_local_part_syntax(local) | |
in_quoted_pair = false | |
in_quoted_string = false | |
(0..local.length-1).each do |i| | |
ord = local[i].ord | |
# accept anything if it's got a backslash before it | |
if in_quoted_pair | |
in_quoted_pair = false | |
next | |
end | |
# backslash signifies the start of a quoted pair | |
if ord == 92 && i < local.length - 1 | |
return false unless in_quoted_string # must be in quoted string per http://www.rfc-editor.org/errata_search.php?rfc=3696 | |
in_quoted_pair = true | |
next | |
end | |
# double quote delimits quoted strings | |
if ord == 34 | |
in_quoted_string = !in_quoted_string | |
next | |
end | |
next if local[i, 1] =~ /[a-z0-9]/i | |
next if local[i, 1] =~ LOCAL_PART_SPECIAL_CHAR | |
# period must be followed by something | |
if ord == 46 | |
return false if i == 0 || i == local.length - 1 # can't be first or last char | |
next unless local[i+1].ord == 46 # can't be followed by a period | |
end | |
return false | |
end | |
return false if in_quoted_string # unbalanced quotes | |
return true | |
end | |
def self.validate_domain_part_syntax(domain) | |
parts = domain.downcase.split('.', -1) | |
return false if parts.length <= 1 # Only one domain part | |
# Empty parts (double period) or invalid chars | |
return false if parts.any? { | |
|part| | |
part.nil? || | |
part.empty? || | |
!(part =~ /\A[[:alnum:]\-]+\Z/) || | |
part[0, 1] == '-' || part[-1, 1] == '-' # hyphen at beginning or end of part | |
} | |
# ipv4 | |
return true if parts.length == 4 && parts.all? { |part| part =~ /\A[0-9]+\Z/ && part.to_i.between?(0, 255) } | |
return false if parts[-1].length < 2 || !(parts[-1] =~ /[a-z\-]/) # TLD is too short or does not contain a char or hyphen | |
return true | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
After research of many gems I compiled this service, light weight and easy to integrate in code.
These are some of the results, let me know if there is any case that is not working as per expectation; any missing case indication will be appreciated.