如何在Ruby on Rails中进行电子邮件验证?

时间:2016-07-27 11:14:57

标签: ruby-on-rails ruby email

我正在使用Rails进行电子邮件验证:

validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i

另外,我在前端进行HTML5验证,但是电子邮件地址如

..abc@gmail.com
.abc@gmail.com

仍然有效。我错过了什么?

15 个答案:

答案 0 :(得分:93)

我在标准ruby库中使用常量内置的URI

validates :email, format: { with: URI::MailTo::EMAIL_REGEXP } 

答案 1 :(得分:19)

更新:我刚发现valid_email2宝石看起来非常棒。

请勿使用正则表达式进行电子邮件地址验证。这是一个陷阱。有比您想象的更有效的电子邮件地址格式。然而! mail gem(ActionMailer需要它,所以你拥有它)将为您解析电子邮件地址 - 使用适当的解析器:

require 'mail'
a = Mail::Address.new('foo@example.com')

如果是不合规的电子邮件地址,则会抛出Mail::Field::ParseError。 (我们没有涉及像进行MX地址查询等任何事情。)

如果您想获得良好的'Rails验证器体验,您可以app/models/concerns/email_validatable.rb

require 'mail'

module EmailValidatable
  extend ActiveSupport::Concern

  class EmailValidator < ActiveModel::EachValidator
    def validate_each(record, attribute, value)
      begin
        a = Mail::Address.new(value)
      rescue Mail::Field::ParseError
        record.errors[attribute] << (options[:message] || "is not an email")
      end
    end
  end
end

然后在你的模型中,你可以:

include EmailValidatable
validates :email, email: true

正如Iwo Dziechciarow在下面提到的评论所提到的,这传递了任何有效的“To:”地址。所以像Foo Bar <foo.bar@example.com>这样的东西是有效的。这对你来说可能是个问题,也可能不是;毕竟 是一个有效的地址。

如果你只想要它的地址部分:

a = Mail::Address.new('Foo Bar <foobar@example.com>')
a.address
=> "foobar@example.com"

正如BjörnWeinbrenne在下面指出的那样,有效的RFC2822 addresses比您预期的更有效(我非常确定那里列出的所有地址都是合规的,并且可能会根据系统配置接收邮件) - 这就是为什么我不建议尝试使用正则表达式,而是使用兼容的解析器。

如果您真的关心是否可以向某个地址发送电子邮件,那么您最好的选择 - 到目前为止 - 实际上是发送带有验证链接的邮件。

答案 2 :(得分:13)

如果您已在应用中使用Devise gem,则可能适合使用

email =~ Devise.email_regexp

...这也意味着应用程序的不同位置使用相同的验证。

答案 3 :(得分:7)

@Nate非常感谢您将这个答案放在一起。在我查看您的代码片段之前,我没有意识到电子邮件验证有如此多的细微差别。

我注意到当前邮件gem:mail-2.6.5不会为“abc”的电子邮件抛出错误。例子:

>> a = Mail::Address.new('abc')
=> #<Mail::Address:70343701196060 Address: |abc| >
>> a.address # this is weird
=> "abc"
>> a = Mail::Address.new('"Jon Doe" <jon@doe.com>')
=> #<Mail::Address:70343691638900 Address: |Jon Doe <jon@doe.com>| >
>> a.address
=> "jon@doe.com"
>> a.display_name
=> "Jon Doe"
>> Mail::Address.new('"Jon Doe <jon')
Mail::Field::ParseError: Mail::AddressList can not parse |"Jon Doe <jon|
Reason was: Only able to parse up to "Jon Doe <jon
  from (irb):3:in `new'
  from (irb):3
>>

它会为Mail::Field::ParseError抛出"Jon Doe <jon错误,这很好。我相信也会检查简单的“abc模式”。

app/models/concerns/pretty_email_validatable.rb

require 'mail'

module PrettyEmailValidatable
  extend ActiveSupport::Concern

  class PrettyEmailValidator < ActiveModel::EachValidator

    def validate_each(record, attribute, value)
      begin
        a = Mail::Address.new(value)
      rescue Mail::Field::ParseError
        record.errors[attribute] << (options[:message] || "is not an email")
      end

      # regexp from http://guides.rubyonrails.org/active_record_validations.html
      value = a.address
      unless value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
        record.errors[attribute] << (options[:message] || "is not an email")
      end
    end

  end
end

然后在你的模型中,你可以:

include PrettyEmailValidatable
validates :pretty_email, email: true

所以我使用上面的“漂亮的电子邮件”验证和https://github.com/balexand/email_validator标准的电子邮件验证。

答案 4 :(得分:5)

答案 5 :(得分:4)

如果有其他人非常关注TDD:我想要一些我可以编写测试的东西,如果需要的话可以在以后进行改进,而不需要将测试绑定到另一个模型。

建立Natetongueroo代码(感谢Natetongueroo!),这是在Rails 5中完成的,{ {1}}。这是我投入Ruby 2.4.1

的内容
app/validators/email_validator.rb

这绝不是全面的,但这是我投入require 'mail' class EmailValidator < ActiveModel::EachValidator def add_error(record, attribute) record.errors.add(attribute, (options[:message] || "is not a valid email address")) end def validate_each(record, attribute, value) begin a = Mail::Address.new(value) rescue Mail::Field::ParseError add_error(record, attribute) end # regexp from http://guides.rubyonrails.org/active_record_validations.html value = a.address unless a.nil? unless value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i add_error(record, attribute) end end end 的内容:

spec/validators/email_validator_spec.rb

希望它有所帮助!

答案 6 :(得分:2)

以下是执行电子邮件验证的新rails方式:

validates :email, format: { with: /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i, on: :create }

请参阅Rails valications doc

答案 7 :(得分:2)

简单的答案是:不要使用正则表达式。边缘情况太多,漏报和误报都很多。检查@符号并发送邮件到该地址进行验证:

https://www.youtube.com/watch?v=xxX81WmXjPg

答案 8 :(得分:2)

VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
!("yourmail@example.com" =~ VALID_EMAIL_REGEX).nil?

答案 9 :(得分:2)

答案 10 :(得分:1)

你可以试试这个

VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z]+)*\.[a-z]+\z/i

答案 11 :(得分:1)

试试这个。

validates_format_of  :email, :with => /^[\+A-Z0-9\._%-]+@([A-Z0-9-]+\.)+[A-Z]{2,4}$/i

答案 12 :(得分:1)

最好遵循Rails文档:

https://guides.rubyonrails.org/active_record_validations.html#custom-validators

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 < ApplicationRecord
  validates :email, presence: true, email: true
end

答案 13 :(得分:1)

Ruby具有内置的正则表达式来验证电子邮件:

validates :email, format: {
    with: URI::MailTo::EMAIL_REGEXP,
    message: 'Only valid emails allowed'
  }

来源:Ruby Standard Library: URI::MailTo

答案 14 :(得分:-1)

我遇到了同样的问题,并且用一个简单的单行gem进行了修复

gem 'validates_email_format_of'

在我添加的模型中

validates :email, email_format: { message: 'Invalid email format' }

我希望这可以帮助像我这样的新手:)