[ruby-on-rails] Rails에 대한 이메일 검증의 최첨단은 무엇입니까?

사용자의 이메일 주소를 확인하기 위해 무엇을 사용하고 있으며 그 이유는 무엇입니까?

validates_email_veracity_of실제로 MX 서버를 쿼리하는 것을 사용했습니다 . 그러나 이는 대부분 네트워크 트래픽 및 안정성과 관련된 다양한 이유로 실패로 가득 차 있습니다.

주위를 둘러 보니 많은 사람들이 이메일 주소에 대한 온 전성 검사를 수행하는 데 사용하고 있다는 분명한 사실을 찾을 수 없었습니다. 이를 위해 유지되고 합리적으로 정확한 플러그인이나 gem이 있습니까?

추신 : 이메일이 작동하는지 확인하기 위해 링크가있는 이메일을 보내라고 말하지 마십시오. “친구에게 보내기”기능을 개발 중이므로 실용적이지 않습니다.



답변

Rails 3.0에서는 Mail gem을 사용하여 regexp없이 이메일 유효성 검사를 사용할 수 있습니다 .

여기에 내 구현이 있습니다 ( gem 패키지 ).


답변

필요 이상으로 어렵게 만들지 마십시오. 귀하의 기능은 중요하지 않습니다. 유효성 검사는 오타를 잡기위한 기본적인 온전한 단계 일뿐입니다. 나는 간단한 정규식으로 그것을 할 것이고 너무 복잡한 것에 CPU 사이클을 낭비하지 않을 것입니다.

/\A[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+\z/

이것은 http://www.regular-expressions.info/email.html 에서 수정되었습니다 -모든 장단점을 정말로 알고 싶다면 읽어야합니다. 더 정확하고 훨씬 더 복잡한 RFC822 호환 정규식을 원한다면 그 페이지에도 있습니다. 그러나 문제는 이것이다 : 당신이 그것을 완전히 옳게 할 필요는 없습니다.

주소가 유효성 검사를 통과하면 이메일을 보내 게됩니다. 이메일이 실패하면 오류 메시지가 표시됩니다. 어느 시점에서 사용자에게 “죄송합니다. 친구가받지 못했습니다. 다시 시도 하시겠습니까?” 라고 말할 수 있습니다.직접 검토를 위해 플래그를 지정하거나 무시할 수 있습니다.

이것은 주소 가 그랬 다면 다루어야 할 것과 동일한 옵션입니다. 유효성 검사를 통과 입니다. 유효성 검사가 완벽하고 주소가 존재한다는 절대적인 증거를 획득하더라도 전송이 여전히 실패 할 수 있기 때문입니다.

검증시 오 탐지 비용은 낮습니다. 더 나은 유효성 검사의 이점도 낮습니다. 관대하게 검증하고 오류가 발생하면 걱정하십시오.


답변

Rails 3에서 이메일 유효성 검사를위한 gem을 만들었습니다. Rails가 기본적으로 이와 같은 것을 포함하지 않는다는 사실에 약간 놀랐습니다.

http://github.com/balexand/email_validator


답변

이 프로젝트에는 현재 github에서 가장 많은 감시자가있는 것 같습니다 (레일의 이메일 유효성 검사 용).

https://github.com/alexdunae/validates_email_format_of


답변

가에서 4 문서를 레일 :

class EmailValidator < ActiveModel::EachValidator
  def validate_each(record, attribute, value)
    unless value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
      record.errors[attribute] << (options[:message] || "is not an email")
    end
  end
end

class Person < ActiveRecord::Base
  validates :email, presence: true, email: true
end


답변

Rails 4에서는 모델에 간단히 추가 validates :email, email:true(필드가라고 가정 email) 한 다음 단순 (또는 복합 †)을 작성합니다.EmailValidator 필요에 맞게 을 작성하십시오.

예 :-모델 :

class TestUser
  include Mongoid::Document
  field :email,     type: String
  validates :email, email: true
end

귀하의 검증 인 (으로 이동 app/validators/email_validator.rb)

class EmailValidator < ActiveModel::EachValidator
  EMAIL_ADDRESS_QTEXT           = Regexp.new '[^\\x0d\\x22\\x5c\\x80-\\xff]', nil, 'n'
  EMAIL_ADDRESS_DTEXT           = Regexp.new '[^\\x0d\\x5b-\\x5d\\x80-\\xff]', nil, 'n'
  EMAIL_ADDRESS_ATOM            = Regexp.new '[^\\x00-\\x20\\x22\\x28\\x29\\x2c\\x2e\\x3a-\\x3c\\x3e\\x40\\x5b-\\x5d\\x7f-\\xff]+', nil, 'n'
  EMAIL_ADDRESS_QUOTED_PAIR     = Regexp.new '\\x5c[\\x00-\\x7f]', nil, 'n'
  EMAIL_ADDRESS_DOMAIN_LITERAL  = Regexp.new "\\x5b(?:#{EMAIL_ADDRESS_DTEXT}|#{EMAIL_ADDRESS_QUOTED_PAIR})*\\x5d", nil, 'n'
  EMAIL_ADDRESS_QUOTED_STRING   = Regexp.new "\\x22(?:#{EMAIL_ADDRESS_QTEXT}|#{EMAIL_ADDRESS_QUOTED_PAIR})*\\x22", nil, 'n'
  EMAIL_ADDRESS_DOMAIN_REF      = EMAIL_ADDRESS_ATOM
  EMAIL_ADDRESS_SUB_DOMAIN      = "(?:#{EMAIL_ADDRESS_DOMAIN_REF}|#{EMAIL_ADDRESS_DOMAIN_LITERAL})"
  EMAIL_ADDRESS_WORD            = "(?:#{EMAIL_ADDRESS_ATOM}|#{EMAIL_ADDRESS_QUOTED_STRING})"
  EMAIL_ADDRESS_DOMAIN          = "#{EMAIL_ADDRESS_SUB_DOMAIN}(?:\\x2e#{EMAIL_ADDRESS_SUB_DOMAIN})*"
  EMAIL_ADDRESS_LOCAL_PART      = "#{EMAIL_ADDRESS_WORD}(?:\\x2e#{EMAIL_ADDRESS_WORD})*"
  EMAIL_ADDRESS_SPEC            = "#{EMAIL_ADDRESS_LOCAL_PART}\\x40#{EMAIL_ADDRESS_DOMAIN}"
  EMAIL_ADDRESS_PATTERN         = Regexp.new "#{EMAIL_ADDRESS_SPEC}", nil, 'n'
  EMAIL_ADDRESS_EXACT_PATTERN   = Regexp.new "\\A#{EMAIL_ADDRESS_SPEC}\\z", nil, 'n'

  def validate_each(record, attribute, value)
    unless value =~ EMAIL_ADDRESS_EXACT_PATTERN
      record.errors[attribute] << (options[:message] || 'is not a valid email')
    end
  end
end

이렇게하면 태그를 포함한 모든 종류의 유효한 이메일이 허용됩니다. “test+no_really@test.tes”등과 같은 이메일을 됩니다.

이것을 테스트하려면 rspecspec/validators/email_validator_spec.rb

require 'spec_helper'

describe "EmailValidator" do
  let(:validator) { EmailValidator.new({attributes: [:email]}) }
  let(:model) { double('model') }

  before :each do
    model.stub("errors").and_return([])
    model.errors.stub('[]').and_return({})
    model.errors[].stub('<<')
  end

  context "given an invalid email address" do
    let(:invalid_email) { 'test test tes' }
    it "is rejected as invalid" do
      model.errors[].should_receive('<<')
      validator.validate_each(model, "email", invalid_email)
    end
  end

  context "given a simple valid address" do
    let(:valid_simple_email) { 'test@test.tes' }
    it "is accepted as valid" do
      model.errors[].should_not_receive('<<')
      validator.validate_each(model, "email", valid_simple_email)
    end
  end

  context "given a valid tagged address" do
    let(:valid_tagged_email) { 'test+thingo@test.tes' }
    it "is accepted as valid" do
      model.errors[].should_not_receive('<<')
      validator.validate_each(model, "email", valid_tagged_email)
    end
  end
end

어쨌든 이것이 내가 한 방법입니다. YMMV

† 정규 표현은 폭력과 같습니다. 작동하지 않으면 충분히 사용하지 않는 것입니다.


답변

Hallelujah가 제안 했듯이 Mail gem을 사용하는 것 같습니다. 을 사용하는 것이 좋은 접근 방식 . 그러나 나는 거기에 몇 가지 농구를 싫어합니다.

나는 사용한다:

def self.is_valid?(email)

  parser = Mail::RFC2822Parser.new
  parser.root = :addr_spec
  result = parser.parse(email)

  # Don't allow for a TLD by itself list (sam@localhost)
  # The Grammar is: (local_part "@" domain) / local_part ... discard latter
  result &&
     result.respond_to?(:domain) &&
     result.domain.dot_atom_text.elements.size > 1
end

TLD (최상위 도메인)를 이 목록 에 포함하도록 요구하면 더 엄격해질 수 있지만 2012 년 추가 .mobi.tel ).

파서를 직접 연결하는 장점은 Mail 문법규칙 이 Mail gem이 사용하는 부분에 대해 상당히 넓다 user<user@example.com>는 것입니다. SMTP에 일반적으로 사용 되는 주소를 구문 분석 할 수 있도록 설계되었습니다 . 그것을 소비함으로써Mail::Address 당신은 많은 추가 검사를해야합니다.

Mail gem에 대한 또 다른 참고 사항은 클래스가 RFC2822이지만 문법에는 RFC5322의 일부 요소가 있습니다 ( 예 : this test) .