Validating Emails in Ruby on Rails

It’s time to validate e-mail addresses and you’re sitting in a Ruby on Rails application. Fortunately, there are a few methods to tackle such a task, and a combination of them can yield a pretty nice solution.

The first idea is to use some lengthy regular expressions. But why enumerate/describe in regular expressions what we are looking for when TMail has it built in… Using TMail, it is possible to let our Ruby Net SMTP wrapper class parse the email address and decide if it is correct or not.

The second task is to make up for some of TMail’s odd shortcomings: the fact that the text “bob” passes as valid for TMail is alarming, but throwing in some simple regular expression to get past this provides a pretty solid solution. (For the curious, “bob” is a valid e-mail to TMail because you could be sending messages to the local domain.)

First, here is our regular expression for a basic e-mail address…

/^([^@\s'"]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i

Next, we create a TMail object with our e-mail address…

tmail = TMail::Address.parse(address.to_s) rescue nil

I am rescuing nil here. You can rescue whatever error message you want, but for example sake I am not so concerned if the TMail fails to parse the e-mail address. You can pass in a multitude of e-mail formats and TMail will do its best to match the RFC standard for e-mail addresses.

You now have access to a TMail object with a flurry of options (TMail & documentation). Let’s proceed.

My simply method calls TMail and then follows it with the regular expression match to ensure this e-mail address in question is ready to be used on the web. Here is my final result to a pretty safe-proof (so far, tested on a rather large web site) e-mail handler. This method will return the TMail object.

def validate_email e-mail
  tmail = TMail::Address.parse(address.to_s) rescue nil
  tmail if tmail.address =~ /^([^@\s'"]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
end

And for those of you who want the extra step, I have attached a helper method that takes a TMail object and gives you back the e-mail address in string format fully qualified.

def formatted_email tmail
  if !email.blank?
    friendly_name = (tmail.name.blank? ? "" : tmail.name.blank?).tr('"',"'")
    quote = '"' if friendly_name =~ /[<,@;]/
    "#{quote}#{friendly_name}#{quote} <#{address}>"
  end
end

As always, test this code and do not trust it blindly. I could have fat fingered something…