Email Address Validation in Rails

by Doug Selph on May 21, 2009

I recently had a need to validate email addresses submitted to a Rails application. I found several plugins/gems that could help with the task, and eventually settled on one. Then I had to figure out how to actually integrate that gem with the validation process of ActiveRecord. As has often been the case in my experience with Rails, once I figured it out it was incredibly easy, but it was less obvious on the front-end how to go about doing what I needed. So let’s begin…

I settled on using theĀ email-veracity gem by Carsten Nielsen for validations. It is available from the gem site at github.


sudo gem sources -a http://gems.github.com
sudo gem install heycarsten-email-veracity
 

Great. Now I was able to play around with validating emails from irb, but what about in my app? Hmm…

I started digging around in the source code for the ActiveRecord class, wondering how I might create my own validation macro to use email-veracity. That was going ok until I couldn’t figure out how to access the error collection for my ActiveRecord object. Thankfully, that sent me back to scouring the web for a lead on another way to skin this cat.

Now with a fresher mind than when I’d last been in the ActiveRecord source, I looked around some more and took a close look at the validates_each macro. This is what I wound up with.

Note: You can get cleanly formatted copies of the code excerpts below from gist.github.com.


class Customer < ActiveRecord::Base
# EmailVeracity is used to validate email addresses submitted
 require ‘email_veracity’

 validates_each :email_address, :on => :save \
    do |record, attr, value|
 
  # create new Address object from string param
  address = EmailVeracity::Address.new(value)
 
  # Add to errors collection unless address is valid
  record.errors.add attr, \
    ’- Does not appear to be a valid email address’ \
    unless address.valid?
 end
end
 

This gives basic validation as to format of the address supplied. Now, in another model, I wanted to confirm that the address not only was of good form, but that the domain in the email address belonged to the customer’s domain as recorded in the database.


class Email < ActiveRecord::Base
 # EmailVeracity is used to validate email addresses submitted
 require 'email_veracity'
 
 validates_each :email_address do |record, attr, value|
  # create new Address object from string param
  address = EmailVeracity::Address.new(value)
  if address.valid?
   # Parse out domain from address
   domain = address.domain
   
   # Is domain in database on customers account?
   domain_count = Domain.count(:conditions => \
     ”domain_name = ‘#{domain}’ and customer_id = \
     #{record[:customer_id]}”)
   record.errors.add attr, \
     ’- The email address submitted is on a domain \
     which is not linked to your customer account’ \
     unless domain_count > 0
  else
   record.errors.add attr, \
     ’- Does not appear to be a valid email address’ \
     unless address.valid?
  end
 end
end
 

Is this a perfect solution? There will be varied opinions on that question. It is a working solution, but comes at the price of adding EmailVeracity to those of your ActiveRecord instances where you want to validate email addresses. You’ll have to judge whether that tradeoff is a reasonable one for your application.

EmailVeracity can do many other things, including finding the MX hosts for a given address’s domain name. Now you’re talking about an operation that necessitates a network call, which could fail or timeout, so you typically would not want to include such methods in a validation sequence.

{ 3 comments… read them below or add one }

optormtogap June 7, 2010 at 4:44 pm

Great tips! I will try it definitely
thanks for sharing this!

kolchina July 24, 2010 at 7:26 am

it was very interesting to read.
I want to quote your post in my blog. It can?
And you et an account on Twitter?

Doug Selph July 29, 2010 at 9:53 am

Quote at will. I’m @dougselph on twitter.

Leave a Comment

Previous post: Umm, hello?

Next post: A Rails3 TabsRenderer