Email validation in Ruby on Rails?
Here is the new rails way to do email validation:
validates :email, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, on: :create }
Refer to the Rails validations doc.
If you use the Devise gem already in your app, it might be opportune to use
email =~ Devise.email_regexp
...which also means different places of the app use the same validation.
If you want to add it as an attribute validator to your ActiveRecord model:
validates :email, format: { with: Devise.email_regexp }
Update: I just found the valid_email2 gem which looks pretty great.
Don't use a regular expression for email address validation. It's a trap. There are way more valid email address formats than you'll think of. However! The mail
gem (it's required by ActionMailer, so you have it) will parse email addresses — with a proper parser — for you:
require 'mail'
a = Mail::Address.new('[email protected]')
This will throw a Mail::Field::ParseError
if it's a non-compliant email address. (We're not getting into things like doing an MX address lookup or anything.)
If you want the good ol' Rails validator experience, you can make app/models/concerns/email_validatable.rb
:
require 'mail'
module EmailValidatable
extend ActiveSupport::Concern
class EmailValidator < ActiveModel::EachValidator
def validate_each(record, attribute, value)
begin
a = Mail::Address.new(value)
rescue Mail::Field::ParseError
record.errors[attribute] << (options[:message] || "is not an email")
end
end
end
end
and then in your model, you can:
include EmailValidatable
validates :email, email: true
As Iwo Dziechciarow's comment below mentions, this passes anything that's a valid "To:" address through. So something like Foo Bar <[email protected]>
is valid. This might be a problem for you, it might not; it really is a valid address, after all.
If you do want just the address portion of it:
a = Mail::Address.new('Foo Bar <[email protected]>')
a.address
=> "[email protected]"
As Björn Weinbrenne notes below, there are way more valid RFC2822 addresses than you may expect (I'm quite sure all of the addresses listed there are compliant, and may receive mail depending system configurations) — this is why I don't recommend trying a regex, but using a compliant parser.
If you really care whether you can send email to an address then your best bet — by far — is to actually send a message with a verification link.
I use the constant built into URI in the standard ruby library
validates :email, format: { with: URI::MailTo::EMAIL_REGEXP }