Rails电子邮件验证的最新技术是什么?

Luk*_*ncl 95 email validation ruby-on-rails

你用什么来验证用户的电子邮件地址,为什么?

我一直在使用validates_email_veracity_of它实际查询MX服务器.但由于各种原因,这种情况充满了失败,主要与网络流量和可靠性有关.

我环顾四周,找不到很多人用来对电子邮件地址进行健全检查的明显事实.是否有一个维护的,相当准确的插件或宝石?

PS:请不要告诉我发送带有链接的电子邮件,看看电子邮件是否有效.我正在开发一个"发送给朋友"的功能,所以这是不切实际的.

SFE*_*ley 106

不要让它比它需要的更难.您的功能非关键; 验证只是一个基本的理智步骤来捕捉拼写错误.我会用一个简单的正则表达式来做,而不是浪费CPU周期的任何太复杂:

/\A[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+\z/
Run Code Online (Sandbox Code Playgroud)

这是改编自http://www.regular-expressions.info/email.html - 如果你真的想知道所有的权衡,你应该阅读.如果你想要一个更正确,更复杂的完全符合RFC822的正则表达式,那也就是在那个页面上.但问题是:你不必完全正确.

如果地址通过验证,您将发送电子邮件.如果电子邮件失败,您将收到错误消息.此时你可以告诉用户"抱歉,你的朋友没有收到,你想再试一次吗?" 或者标记它以供人工审查,或者只是忽略它,或者其他什么.

如果地址确实通过验证,则这些选项与您必须处理的选项相同.因为即使您的验证是完美的并且您获得了地址存在的绝对证据,发送仍然可能失败.

验证的误报成本很低.更好的验证的好处也很低.慷慨地验证,并在发生错误时担心错误.

  • 呃,不会对.museum和新的国际顶级域名的那个barf?这个正则表达式*会阻止*许多有效的电子邮件地址. (35认同)
  • 关于**.博物馆等等的好点 - 当我在2009年首次发布答案时,这不是一个问题.我改变了正则表达式.如果您有进一步的改进,也可以编辑它,或者将其作为社区维基帖. (8认同)
  • 我同意你不应该担心允许通过一些不正确的地址的动机.可悲的是,这个正则表达式将禁止一些正确的地址,我认为这是不可接受的.也许这样的事情会更好吗?/.+@.+\..+/ (6认同)
  • 仅供参考,这仍然会遗漏一些有效的电子邮件地址.不是很多,而是一些.例如,技术上#| @foo.com是一个有效的电子邮件地址,"嘿,如果他们被引用,我可以有空格"@ foo.com.我发现在@之前忽略任何内容最简单,只验证域部分. (5认同)
  • 同意以利亚,这是一个不好的建议.此外,我不确定你认为你怎么能告诉用户他的朋友没有收到电子邮件,因为没有办法判断电子邮件是否成功. (3认同)

小智 67

使用Rails 3.0,您可以使用邮件验证而无需使用Mail gem的 regexp .

这是我的实现(打包为gem).


bal*_*and 12

我在Rails 3中为电子邮件验证创建了一个gem.我很惊讶Rails默认情况下不包含这样的东西.

http://github.com/balexand/email_validator

  • 这基本上是正则表达式的包装. (8认同)

Bri*_*ong 10

这个项目目前似乎在github上拥有最多的观察者(对于rails中的电子邮件验证):

https://github.com/alexdunae/validates_email_format_of


Mik*_*key 7

来自Rails 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
Run Code Online (Sandbox Code Playgroud)


Dav*_*Sag 5

在Rails 4中,只需添加validates :email, email:true(假设您的字段被调用email)到您的模型,然后编写一个简单(或复杂†)EmailValidator以满足您的需求.

例如: - 你的型号:

class TestUser
  include Mongoid::Document
  field :email,     type: String
  validates :email, email: true
end
Run Code Online (Sandbox Code Playgroud)

您的验证员(进入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
Run Code Online (Sandbox Code Playgroud)

这将允许各种有效的电子邮件,包括标记的电子邮件,如"test+no_really@test.tes"等.

rspec你的方式测试一下spec/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
Run Code Online (Sandbox Code Playgroud)

无论如何我就是这样做的.因人而异

†正则表达就像暴力; 如果他们不工作你没有使用足够的.