Beta privadaMailbeam está en beta privada: la API pública todavía no está abierta.Únete a la lista de espera

Mailbeam
Ruby on RailsIniciación15 minutosActualizado en enero de 2025

Verificación de email en Ruby on Rails

Este tutorial añade verificación de email a una aplicación Rails con un ActiveModel::EachValidator propio. Se engancha a la cadena de validación estándar de Rails, así que funciona con valid?, save! y create!.

Requisitos previos


Preparación

# Gemfile — usa net/http (incluido) o faraday
gem 'faraday'  # opcional, pero más limpio para llamadas a API

Añade esto a config/credentials.yml.enc (con rails credentials:edit):

mailbeam:
  key: mb_live_xxxxxxxxxxxxxxxxxxxx

Crea el validador

# app/validators/mailbeam_validator.rb
require 'faraday'
require 'json'

class MailbeamValidator < ActiveModel::EachValidator
  MIN_SCORE = options[:min_score] || 60

  def validate_each(record, attribute, value)
    return if value.blank?

    result = verify_email(value.downcase.strip)
    return if result.nil? # error de la API: falla en abierto

    unless result['valid'] && result['score'].to_i >= MIN_SCORE
      reason = result['reason']
      message = case reason
                when 'disposable_domain' then 'no puede ser una dirección de email temporal'
                when 'no_mx_records'     then 'tiene un dominio que no puede recibir correo'
                when 'smtp_rejected'     then 'no parece existir'
                else 'no es una dirección de email válida'
                end
      record.errors.add(attribute, message)
    end
  end

  private

  def verify_email(email)
    conn = Faraday.new('https://api.mailbeam.dev') do |f|
      f.request :json
      f.response :json
      f.adapter Faraday.default_adapter
    end

    response = conn.post('/v1/verify', { email: email }) do |req|
      req.headers['Authorization'] = "Bearer #{Rails.application.credentials.mailbeam.key}"
      req.options.timeout = 5
    end

    response.body if response.success?
  rescue StandardError => e
    Rails.logger.error "[Mailbeam] ha fallado la verificación: #{e.message}"
    nil # falla en abierto
  end
end

Añádelo a tu modelo User

# app/models/user.rb
class User < ApplicationRecord
  validates :email,
    presence: true,
    format: { with: URI::MailTo::EMAIL_REGEXP },
    uniqueness: { case_sensitive: false },
    mailbeam: true  # nuestro validador propio
end

Tests con RSpec

# spec/validators/mailbeam_validator_spec.rb
RSpec.describe MailbeamValidator do
  let(:user) { build(:user, email: email) }

  before do
    stub_request(:post, 'https://api.mailbeam.dev/v1/verify')
      .to_return(status: 200, body: response_body.to_json)
  end

  context 'con un email válido' do
    let(:email) { 'user@example.com' }
    let(:response_body) { { valid: true, score: 94, reason: nil } }

    it { expect(user).to be_valid }
  end

  context 'con un email desechable' do
    let(:email) { 'temp@mailinator.com' }
    let(:response_body) { { valid: false, score: 2, reason: 'disposable_domain' } }

    it 'añade un error' do
      user.valid?
      expect(user.errors[:email]).to include('no puede ser una dirección de email temporal')
    end
  end

  context 'cuando la API de Mailbeam está caída' do
    let(:email) { 'user@example.com' }
    before { stub_request(:post, anything).to_raise(Faraday::Error) }

    it 'falla en abierto (no añade ningún error)' do
      expect(user).to be_valid
    end
  end
end

Siguientes pasos