Skip to content

Instantly share code, notes, and snippets.

@Sohair63
Created May 18, 2017 19:10
Show Gist options
  • Save Sohair63/05dc155eb65cc9243e6eef0fd4f53c62 to your computer and use it in GitHub Desktop.
Save Sohair63/05dc155eb65cc9243e6eef0fd4f53c62 to your computer and use it in GitHub Desktop.
This is custom email format validation service that hold all the cases.
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
@Sohair63
Copy link
Author

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.

EmailValidationService.valid_email_format?('sohair@[email protected]')     => false 
EmailValidationService.valid_email_format?('sohair@[email protected]')     => false 
EmailValidationService.valid_email_format?('sohair@gmail')              => false 
EmailValidationService.valid_email_format?('sohair@gmail.')             => false 
EmailValidationService.valid_email_format?('[email protected]')            => false 
EmailValidationService.valid_email_format?('@gmail.co')                 => false 
EmailValidationService.valid_email_format?('aaa@gmail')                 => false 
EmailValidationService.valid_email_format?('[email protected]')          => false 
EmailValidationService.valid_email_format?('[email protected]')            => false 
EmailValidationService.valid_email_format?('[email protected]')             => false 
EmailValidationService.valid_email_format?('[email protected].')             => false 
EmailValidationService.valid_email_format?('[email protected]')            => false 
EmailValidationService.valid_email_format?('[email protected]')           => true 
EmailValidationService.valid_email_format?('[email protected]')            => true 
EmailValidationService.valid_email_format?('[email protected]')          => true 
EmailValidationService.valid_email_format?('[email protected]')             => true 

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment