暇人じゃない

Rails のメールアドレスバリデーション

いくつかの Rails プロジェクトのメールアドレスのバリデートは、正規表現ではなく mail gem と treetop gem を組み合わせて 行なっている。

しかし、mail gem のバージョン 2.6.0 から treetop gem が依存関係から削除されたため、ドメイン部分のエレメントの検証が出来なくなった。

そこで、以下のように処理を変更した。

require 'mail'
require 'resolv'

class EmailValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    begin
      m = Mail::Address.new(value)
      r = m.domain && m.address == value

      mx = []
      Resolv::DNS.open do |dns|
        domain = m.domain.downcase

        mx = dns.getresources(domain, Resolv::DNS::Resource::IN::MX) +
          dns.getresources(domain, Resolv::DNS::Resource::IN::A)
      end

      r &&= mx.size > 0
    rescue Exception
      r = false
    end

    record.errors[attribute] << (options[:message] || I18n.t('activerecord.errors.messages.invalid')) unless r
  end
end

これらをすべて満たした場合に、バリデーションをパスできる。
(spec 実行時にインターネットへアクセスが走るので工夫する必要がある。)


メールアドレスに厳しめのバリデーションをかけて、ユーザーが登録できなくて残念な思いをするぐらいなら、 スペルミスを教えてあげたりした方が幸せになれるのかな、と思う。

例えば mailcheck.js を使うと、フォーム上でスペルミスがある場合にサジェストしてくれる。


ちなみに、DNS を引く処理については、メールアドレスのバリデーションを行う gem である validates_email_format_of gem から拝借した。

この gem は厳しめのバリデーションがかかるので、キャリアメールが使われることの多い(?)日本のサービスで使用するのは厳しいかもしれないが、それが問題なければ導入は簡単だしメンテナンスもされているので良い選択肢かなと思う。

Rails のメールアドレスバリデーション、皆さんどうやっているのでしょうか。