How Validate Emails in Ruby on Rails

Last Updated Jan 15, 2021
Emma Jagger

Engineer, maker, Google alumna, CMU grad

A developer should never trust users' data and must test every form field before saving them in the database. Fortunately, Ruby on Rails provides several mechanisms that allow you to perform these validations efficiently.

How to validate fields in Ruby on Rails

In most cases, the fields of a form are injected into an ActiveRecord model, which performs the validation. The ActiveRecord::Validations API allows to easily define rules to validate various aspects of these fields: format, inclusion, length, uniqueness, and many others.

Let's take as an example a contact form allowing your visitors to send a message to your staff. Such a form would contain Last and First Name, Email Address, and Message fields. Let's write a model and its validation mechanism to check the presence and length of each field and the email address format. Here is the code:


class ContactData < ApplicationRecord
  validates_presence_of :first_name, :last_name, :email, :message
  validates_length_of :first_name, :last_name, maximum: 150
  validates_format_of :email, with: A_MAGIC_REGEXP
end

ActiveRecord calls all validation methods defined in the model during the saving process. If they are successful, then the model is saved in the database. But if there is at least one error, the model won't be saved in the database. You can then check the content of its errors field to obtain details about the validation errors.

Here are the details of the methods used in the code above:

  • validates_presence_of: check that the fields contain something. Note that if the value for this field is a simple space, the validation will succeed.
  • validates_length_of: checks the length of the value. The acceptable length of a field depends on the application's needs and the database's field type.
  • validates_format_of: checks that the format of the field value matches the regular expression provided in the parameter

While the first two validation methods are easy to understand, the third requires a little more attention.

Validating an email address in Ruby on Rails

The first step of email validation consists of checking the format of the email address. To do this, it is sufficient to use the validates_format_of method mentioned earlier in this document along with an efficient regular expression.

The standard Ruby library provides the URI::MailTo class, which declares the regular expression EMAIL_REGEXP. This is suitable in most cases.


URI::MailTo::EMAIL_REGEXP
=> /\A[a-zA-Z0-9.!\#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*\z/


Here is how to use it in our model:


class ContactData < ApplicationRecord
  validates_presence_of :first_name, :last_name, :email, :message
  validates_length_of :first_name, :last_name, maximum: 150
  validates_format_of :email, with: URI::MailTo::EMAIL_REGEXP
end

Now that this is done, it is important to understand that validating the format of an email address is not enough. Indeed, the address aaaaa@aaaaa.aa, although having a valid format, would certainly not exist. This is why it is necessary to verify not only the format of an email address but also its existence.

Check that an email address exists in Ruby on Rails.

The method for checking the existence of an email address is to extract the server FQDN (the part after the @ sign); to query the corresponding DNS servers to confirm that the server exists; to query the MX records from the DNS entries. A well-made verification method will also match the server name against a list of known disposable email services to determine if the visitor is using a disposable email address.

Setting up such a complex verification method is beyond this document's scope. But fortunately, there is a solution, easy to implement, which we will discuss in the next chapter.

How to efficiently verify and validate an email address in Ruby

Abstract API provides several free services accessible via simple HTTP calls, one of them being email validation. This service verifies email format and queries the DNS records and email servers to verify that the address actually exists. It also checks if the mailbox is a disposable email service.

You will have to create a free account to get your private API key, and then you can implement email validation in your model like this:


class ContactData < ApplicationRecord
  validates_presence_of :first_name, :last_name, :email, :message
  validates_length_of :first_name, :last_name, maximum: 150
  validate :check_email

  private def check_email
    uri = URI "https://emailvalidation.abstractapi.com/v1/?api_key=#{API_KEY}&email=#{self.email}"

    http = Net::HTTP.new uri.host, uri.port
    http.use_ssl = true
    http.verify_mode = OpenSSL::SSL::VERIFY_PEER

    request = Net::HTTP::Get.new uri
    response = JSON.parse http.request(request)

    if ! response['is_valid_format']['value'] || ! response['is_mx_found']['value'] || ! response['is_smtp_valid']['value']
      errors.add :email, 'is not valid'
    end
  end
end

Related articles