# Rails Email Validator for ActiveModel

URL: https://email-validation.org/docs/guides/rails/
Updated: 2026-11-10

> Documentation index: https://email-validation.org/llms.txt

An ActiveModel validator that fails an email address that cannot receive email, in any Rails model or form object.
It is built on the official [Ruby client library](https://email-validation.org/docs/sdks/ruby/), checks each address once, and never stops a real person
from signing up when the API cannot answer in time.

```ruby
class User < ApplicationRecord
  validates :email, presence: true, deliverable_email: true
end
```

## Install

The gem is not on RubyGems yet. Download it here and install it from a folder of your app:

1. Download [email-validation-rails-0.1.0.zip](https://email-validation.org/downloads/rails/email-validation-rails-0.1.0.zip) and unzip it into your app's `vendor/` folder, so that you have
   `vendor/email-validation-rails/`.
2. Add it to your Gemfile and run `bundle install` (Bundler installs the Ruby client library from RubyGems):

   ```ruby
   gem "email-validation-rails", path: "vendor/email-validation-rails"
   ```

3. Create an API key on the [API keys page](https://email-validation.org/app/api-keys/) with the permission "Validate addresses", and give it a
   [daily credit cap](https://email-validation.org/docs/authentication/#limits) to limit what a busy form can spend. Set it in your environment
   as `EV_API_KEY`, or read it from your credentials in the initializer below; never put it in code. Each new address
   a visitor sends is a paid check, so also rate-limit the form's action per visitor (the rate limiting built into
   Rails 7.2 controllers, or Rack::Attack).

It needs ActiveModel 7.1 or newer and Ruby 3.2 or newer. It works in any class that includes
`ActiveModel::Validations`, with or without Rails.

## Use it

```ruby
class User < ApplicationRecord
  validates :email, presence: true, deliverable_email: true

  # fail disposable addresses too, and refuse the form when the check cannot finish
  validates :work_email, deliverable_email: { fail_on: %w[invalid disposable], fail_open: false }, allow_blank: true

  # your own message
  validates :billing_email, deliverable_email: { message: "is not an address we can use" }, allow_blank: true
end
```

A malformed address is refused without a request.

## Settings

All optional, in `config/initializers/email_validation.rb`:

```ruby
EmailValidation::Rails.configure do |c|
  # default: ENV["EV_API_KEY"]
  c.api_key = Rails.application.credentials.ev_api_key
  # default: ENV["EV_BASE_URL"], else this
  c.base_url = "https://api.email-validation.org"
  c.fail_on = %w[invalid]
  c.block_disposable = false
  c.fail_open = true
  c.timeout = 5
  c.client_timeout = 8
  # c.cache defaults to Rails.cache
  c.cache_ttl = 3600
end
```

- **Which statuses fail.** Only `invalid` by default. Set the block-disposable setting to `true` to fail `disposable`
  addresses as well. `catch_all` and `unknown` pass unless you add them: see
  [what each status means](https://email-validation.org/docs/statuses/).
- **When the check cannot finish** (it timed out, the API could not be reached, it answered with a 5xx or 429 error,
  the account has no credits or no key is set), the address passes and a warning goes to `Rails.logger` with the
  error code and request id, never the address. With the fail-open setting at `false`, the field gets the error
  "could not be checked right now" instead.
- **EU data residency.** Set the base URL to `https://api-eu.email-validation.org`; the same key works on both.

## Speed and caching

The validator gives the API 5 seconds for the check (the API takes 5 to 15) and waits 8
seconds for the answer, without retrying: a slow mail server then answers `unknown`, which passes and is free.

Each result is kept in `Rails.cache` for an hour, under a SHA-256 hash of the trimmed, lower-cased address, so a form
sent again after fixing another field is not checked or charged again. Only the status is kept, never the address,
and `unknown` results are not kept.

## Messages

The error types and their English messages are under `errors.messages` in the gem's locale file: translate or
override them in your own locale files, or pass `message:` to the validator.

```yaml
en:
  errors:
    messages:
      email_invalid: "cannot receive email. Please check it for typos"
      email_disposable: "must be a permanent address, not a disposable one"
      email_catch_all: "could not be confirmed. Please use another address"
      email_unknown: "could not be confirmed. Please try again or use another address"
      email_unavailable: "could not be checked right now. Please try again in a moment"
```

The messages never show the API's own error text.

## Costs

Each completed check costs one credit. Results with the status `unknown` are free, and so are malformed addresses
and the [test addresses](https://email-validation.org/docs/test-addresses/): try the validator with `accepted@sandbox.email-validation.org` (passes) and
`no_mailbox@sandbox.email-validation.org` (fails) at no cost. See [credits and billing](https://email-validation.org/docs/credits-and-billing/).

## Related

- [Validating sign-up forms](https://email-validation.org/docs/guides/signup-form-validation/): what to block and what to accept
- [The Ruby client library](https://email-validation.org/docs/sdks/ruby/) for other calls, such as bulk lists
