我正在使用Rails进行电子邮件验证:
validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i
另外,我在前端进行HTML5验证,但是电子邮件地址如
..abc@gmail.com
.abc@gmail.com
仍然有效。我错过了什么?
答案 0 :(得分:93)
我在标准ruby库中使用常量内置的URI
validates :email, format: { with: URI::MailTo::EMAIL_REGEXP }
答案 1 :(得分:19)
请勿使用正则表达式进行电子邮件地址验证。这是一个陷阱。有比您想象的更有效的电子邮件地址格式。然而! 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)
尝试validates_email_format_of gem。
答案 5 :(得分:4)
如果有其他人非常关注TDD:我想要一些我可以编写测试的东西,如果需要的话可以在以后进行改进,而不需要将测试绑定到另一个模型。
建立Nate和tongueroo代码(感谢Nate和tongueroo!),这是在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 }
答案 7 :(得分:2)
简单的答案是:不要使用正则表达式。边缘情况太多,漏报和误报都很多。检查@符号并发送邮件到该地址进行验证:
答案 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)
请注意,目前 email_validator gem尚不具有复杂的验证规则,而仅具有:
-1
https://github.com/balexand/email_validator/blob/master/lib/email_validator.rb#L13
参数在https://medium.com/hackernoon/the-100-correct-way-to-validate-email-addresses-7c4818f24643
中答案 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'
}
答案 14 :(得分:-1)
我遇到了同样的问题,并且用一个简单的单行gem进行了修复
gem 'validates_email_format_of'
在我添加的模型中
validates :email, email_format: { message: 'Invalid email format' }
我希望这可以帮助像我这样的新手:)