In Rails 3.0, you can use custom validator in your active_record model.
So I wanted to manage email validations without regexp matching like others do.
I find a new way to make this work thanks to ruby mail gem, a dependency of Rails 3.0
I use this with devise, see my blogpost here : Ruby Rails : How to bypass skip validation in Devise
Edit : Here is a gem https://github.com/hallelujah/valid_email
class User < ActiveRecord::Base validates :email, :presence => true, :email => true end
Just put a file in app/validators/email_validator.rb
require 'mail' class EmailValidator < ActiveModel::EachValidator def validate_each(record,attribute,value) begin m = Mail::Address.new(value) # We must check that value contains a domain and that value is an email address r = m.domain && m.address == value t = m.__send__(:tree) # We need to dig into treetop # A valid domain must have dot_atom_text elements size > 1 # user@localhost is excluded # treetop must respond to domain # We exclude valid email values like <user@localhost.com> # Hence we use m.__send__(tree).domain r &&= (t.domain.dot_atom_text.elements.size > 1) rescue Exception => e r = false end record.errors[attribute] << (options[:message] || "is invalid") unless r end end
No regexp !! And beautiful !!
Here is the version without activerecord
require 'rubygems' require 'active_model' require 'active_support/all' require 'active_model/validations' require 'mail' class EmailValidator < ActiveModel::EachValidator def validate_each(record,attribute,value) begin m = Mail::Address.new(value) # We must check that value contains a domain and that value is an email address r = m.domain && m.address == value t = m.__send__(:tree) # We need to dig into treetop # A valid domain must have dot_atom_text elements size > 1 # user@localhost is excluded # treetop must respond to domain # We exclude valid email values like <user@localhost.com> # Hence we use m.__send__(tree).domain r &&= (t.domain.dot_atom_text.elements.size > 1) rescue Exception => e r = false end record.errors[attribute] << (options[:message] || "is invalid") unless r end end class Person include ActiveModel::Validations attr_accessor :name, :email validates :name, :presence => true, :length => { :maximum => 100 } validates :email, :presence => true, :email => true end


27 comments
2 pings
Sohan says:
July 21, 2010 at 16:31 (UTC 2 )
Your post has been linked at the Drink Rails blog as one of the top ruby on rails blogs of the day.
Hallelujah says:
July 21, 2010 at 18:07 (UTC 2 )
Thanks a lot
Steve Root says:
January 1, 2011 at 16:56 (UTC 2 )
Thanks for the post, just the solution I was looking for!
David K says:
February 3, 2011 at 12:58 (UTC 2 )
Thanks for the post. I’m having trouble figuring out why this email: grass_1293770498_per@yahoo.com doesn’t pass validation. Any ideas?
Hallelujah says:
February 4, 2011 at 01:02 (UTC 2 )
Well this email passes the validation …
What’s wrong?
David K says:
February 7, 2011 at 02:32 (UTC 2 )
Never mind, it works now. I am not sure why, but I got an “invalid email” error when I tried before.
King says:
February 27, 2011 at 15:12 (UTC 2 )
You should make a gem out of this. I’d like to be able to simply mention it in my Gemfile and begin using it.
sean says:
March 19, 2011 at 06:21 (UTC 2 )
you created your own folder ‘validators’ right? I’m using rails 3.03 but want to make sure that wasn’t one of the provided skeleton folders. sorry kinda of a newb question, but appreciate your reply.
Hallelujah says:
March 19, 2011 at 09:25 (UTC 2 )
Yes I did.
imohan says:
June 20, 2011 at 02:24 (UTC 2 )
How do we check email with subdomain like sg.domain.com if you use above validation it will true if somebody puts sg.domain where as it is invalid in real business case.
-imohan
Hallelujah says:
June 20, 2011 at 10:20 (UTC 2 )
Do you have an example ?
Because it works for me :
In “real business” nothing prevents you to set up an email on a subdomain : http://bit.ly/jzRLCz
Ramiro Jr. Franco says:
July 8, 2011 at 18:45 (UTC 2 )
Wow, this is actually really cool, if you haven’t already you should think about making a gem out of this.
HP says:
August 11, 2011 at 23:05 (UTC 2 )
Nicely done. I like being able to avoid using regexp and haven’t seen a way to do that before now. I’d making a gem out of this”.have to second the motion of “
haxney says:
August 12, 2011 at 03:05 (UTC 2 )
This method seems to fail for valid email addresses like
“name”
Also, treetop.domain doesn’t exist in my version of Ruby (1.9.2p290), and it seems like this would suffice (sorry, I don’t know how to input code to WordPress):
def is_valid_email?(e)
m = Mail::Address.new(e)
m.domain && m.address
rescue Mail::Field::ParseError => e
false
end
This method also has the advantage of returning the “addressy” part of the address (name plus domain), with any comments stripped.
haxney says:
August 12, 2011 at 03:06 (UTC 2 )
Whoops, forgot an extra “end” at the end of the method.
Adam says:
August 17, 2011 at 09:40 (UTC 2 )
This is great, especially for a newbie like myself. But I’m trying to write a test to prevent duplicate email addresses with different case, and it seems to fail.
Does this validation allow for case insensitivity?
Adam says:
August 17, 2011 at 09:44 (UTC 2 )
ha. sorry. got a little ahead of myself. i see why i was confused. Thanks for the great validator!
James Conroy-Finn says:
September 2, 2011 at 12:50 (UTC 2 )
I’ve refactored the validation and added support for specifying a message or using I18n.
I’ve gisted it for now, but plan to stick it in a gem at some point.
https://gist.github.com/1188367
Hallelujah says:
September 2, 2011 at 14:01 (UTC 2 )
As many want to make it a gem, it seems to be a good idea.
However I wonder how consistent it will be in a future since it relies on the “tree” private method
Hallelujah says:
September 4, 2011 at 01:58 (UTC 2 )
Yep but a validation don’t need to return anything else than true or false.
This piece of code was originally intended to rails application
If you want some more features , it might be useful to create a gem upon
Anyway for the most use cases, we do not type such rfc valid email like below in a text field (as in a signup form)
“John Doe”
This email is valid and the mail gem can extract the user and domain part but iMHO this is not the purpose
James Ferguson says:
November 4, 2011 at 02:17 (UTC 2 )
This validator seems to allow multiple email addresses:
p = Person.new
p.name = “Test”
p.email = “test@example.com, test2@example.com”
p.valid? # => true
Is that intended?
José Valim says:
November 8, 2011 at 17:23 (UTC 2 )
Nice! Have you considered providing a patch to the Mail gem that adds a valid? method to Mail::Address? This way, we could just use the valid? method instead of explicitly checking the dots or worrying about Treetop details.
Hallelujah says:
November 8, 2011 at 19:37 (UTC 2 )
Thanks you all for your feedbacks !!
It seems that since this post has become quiet popular so we should create a project in github.
@jose I don’t know yet if I will patch the mail gem but it is a good Idea
The first step is maybe a gem (for backward compatibility) then pull request a patch to Mail gem.
If you want to follow the project status here is the github repository :
https://github.com/hallelujah/valid_email
Paco Guzmán says:
November 9, 2011 at 15:41 (UTC 2 )
I was using this for a while
https://github.com/cesario/activevalidators/blob/master/lib/active_model/validations/email_validator.rb
Hallelujah says:
November 10, 2011 at 20:01 (UTC 2 )
I know that. Many gems use what I found : email_validator, validate_email etc …
)
But who cares !!! It is opensource and I am happy with it !! (a quote or a WWR vote may help me
Himesh says:
January 20, 2012 at 15:14 (UTC 2 )
This email is getting validated:
cool_123@gmail.commmm
cool_123@gmail.commmm.sahb
Hallelujah says:
January 20, 2012 at 20:14 (UTC 2 )
Yes it is valid even if it does not exist yet.
See new ICANN gTLDs
Rails : How to skip or remove validations in a Model « La rolls des blogs says:
October 20, 2010 at 18:25 (UTC 2 )
[...] my last post with email validations, I was looking for a solution to integrate it with [...]
Email Validator for Rails 3 Without Regex | Rob Conery says:
November 11, 2011 at 00:18 (UTC 2 )
[...] read about this over here but thought I’d add it here as I want to make sure I remember it. Works like a [...]