रेल के लिए ईमेल सत्यापन में कला की स्थिति क्या है?


95

आप उपयोगकर्ताओं के ईमेल पते को मान्य करने के लिए क्या उपयोग कर रहे हैं और क्यों?

मैं उपयोग कर रहा था validates_email_veracity_ofजो वास्तव में एमएक्स सर्वरों पर सवाल उठाता है। लेकिन यह विभिन्न कारणों से विफल है, ज्यादातर नेटवर्क ट्रैफ़िक और विश्वसनीयता से संबंधित है।

मैंने चारों ओर देखा और मुझे कुछ भी स्पष्ट नहीं मिला कि बहुत से लोग ईमेल पते पर एक पवित्रता जांच करने के लिए उपयोग कर रहे हैं। क्या इसके लिए एक अनुरक्षित, यथोचित सटीक प्लगइन या मणि है?

PS: कृपया मुझे यह बताने के लिए लिंक के साथ एक ईमेल भेजने के लिए न कहें कि क्या ईमेल काम करता है। मैं "मित्र को भेजें" सुविधा विकसित कर रहा हूं, इसलिए यह व्यावहारिक नहीं है।


यहाँ रेगेक्स से निपटने के बिना, एक सुपर-आसान तरीका है: एक-वैध-ईमेल-पता का पता
लगाना

क्या आप अधिक विस्तृत कारण दे सकते हैं कि एमएक्स सर्वर को क्वेरी करना विफल क्यों है? मैं जानना चाहूंगा कि क्या मैं ये देख सकता हूं कि ये तय करने योग्य हैं या नहीं।
लाललला

जवाबों:


67

रेल 3.0 के साथ आप मेल जेम का उपयोग करके regexp के बिना ईमेल सत्यापन का उपयोग कर सकते हैं ।

यहाँ मेरा कार्यान्वयन ( एक रत्न के रूप में पैक किया गया ) है।


अच्छा, मैं तुम्हारे मणि का उपयोग कर रहा हूं। धन्यवाद।
२०:२२ पर jasoncrawford

लगता है कि ###@domain.comमान्य होगा?
cwd

1
दोस्तों मैं इस मणि को पुनर्जीवित करना चाहूंगा, मेरे पास इसे बनाए रखने के लिए समय नहीं था। लेकिन ऐसा लगता है कि लोग अभी भी इसका उपयोग करते हैं और सुधार की तलाश करते हैं। यदि आप रुचि रखते हैं, तो कृपया मुझे github प्रोजेक्ट पर लिखें: hallelujah / valid_email
Hallelujah

106

इसे जितना कठिन होना चाहिए उतना कठिन मत बनाओ। आपकी सुविधा गैर-महत्वपूर्ण है; वैधीकरण सिर्फ टाइपो को पकड़ने के लिए एक बुनियादी पवित्रता कदम है। मैं इसे एक सरल रीगेक्स के साथ करूंगा, और सीपीयू चक्रों को किसी भी जटिल चीज़ पर बर्बाद न करें:

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

जिसे http : //www. अनियमित-expressions.info/email.html से अनुकूलित किया गया था - जिसे आपको पढ़ना चाहिए यदि आप वास्तव में सभी ट्रेडऑफ़ जानना चाहते हैं। यदि आप RFC822-compliant regex को अधिक सही और अधिक जटिल चाहते हैं, तो वह पृष्ठ पर भी है। लेकिन बात यह है: आपको इसे पूरी तरह से ठीक करने की आवश्यकता नहीं है।

यदि पता सत्यापन से गुजरता है, तो आप एक ईमेल भेजने जा रहे हैं। यदि ईमेल विफल हो जाता है, तो आपको एक त्रुटि संदेश मिलने वाला है। किस बिंदु पर आप उपयोगकर्ता को बता सकते हैं "क्षमा करें, आपके मित्र को वह प्राप्त नहीं हुआ, क्या आप फिर से प्रयास करना चाहेंगे?" या मैन्युअल समीक्षा के लिए इसे ध्वजांकित करें, या इसे अनदेखा करें, या जो भी हो।

ये वही विकल्प हैं जिनसे आपको पता करना होगा कि पते ने सत्यापन किया है या नहीं। क्योंकि भले ही आपकी मान्यता सही है और आप पूर्ण प्रमाण प्राप्त करते हैं कि पता मौजूद है, फिर भी भेजना विफल हो सकता है।

सत्यापन पर झूठे सकारात्मक की लागत कम है। बेहतर सत्यापन का लाभ भी कम है। उदारतापूर्वक मान्य करें, और जब वे होते हैं तो त्रुटियों के बारे में चिंता करें।


36
इर, उस बार पर नहीं होगा। नए और अंतरराष्ट्रीय TLDs? यह regex कई वैध ईमेल पतों को रोकेगा
एलिय्याह

3
एलिजा के साथ सहमत, यह एक बुरी सिफारिश है। इसके अतिरिक्त, मुझे यकीन नहीं है कि आप कैसे सोचते हैं कि आप उपयोगकर्ता को बता सकते हैं कि उसके दोस्त ने ईमेल प्राप्त नहीं किया है क्योंकि यह बताने का कोई तरीका नहीं है कि क्या ईमेल सही तरीके से बल्ले से सफल हुआ है।
Jaryl

8
.Museum पर अच्छा बिंदु और ऐसा - जब मैंने पहली बार 2009 में उस उत्तर को पोस्ट किया था तो यह कोई समस्या नहीं थी। मैंने regex को बदल दिया। यदि आपके पास और सुधार हैं, तो आप इसे संपादित भी कर सकते हैं, या इसे एक सामुदायिक विकि पोस्ट बना सकते हैं।
SFEley

5
FYI करें, यह अभी भी कुछ मान्य ईमेल पते याद करेगा। कई नहीं, लेकिन कुछ। उदाहरण के लिए, तकनीकी रूप से #pg@foo.com एक वैध ईमेल पता है, जैसा कि "अरे मेरे पास रिक्त स्थान हो सकते हैं यदि उन्हें उद्धृत किया जाए" @ foo.com। मुझे @ से पहले कुछ भी अनदेखा करना आसान लगता है और केवल डोमेन भाग को मान्य करना।
22 दिसंबर को Nerdmaster

6
मैं इस प्रेरणा से सहमत हूं कि आपको कुछ गलत पतों के माध्यम से अनुमति देने की चिंता नहीं करनी चाहिए। अफसोस की बात है कि यह रेगेक्स कुछ सही पतों को खारिज कर देगा, जिन्हें मैं अस्वीकार्य मानता हूं। शायद ऐसा कुछ बेहतर होगा? / .+@.
\

12

मैंने Rails 3 में ईमेल सत्यापन के लिए एक मणि बनाया। मुझे आश्चर्य है कि रेल डिफ़ॉल्ट रूप से ऐसा कुछ शामिल नहीं करता है।

http://github.com/balexand/email_validator


8
यह अनिवार्य रूप से रेगेक्स के चारों ओर एक आवरण है।
रॉब डॉसन

क्या आप एक उदाहरण ifया unlessकथन के साथ इसका उपयोग करने का एक उदाहरण दे सकते हैं ? दस्तावेज़ीकरण विरल लगता है।
19

@ मुझे लगता है कि प्रलेखन पूरा हो गया है। यदि आप रेल 3+ सत्यापन से परिचित नहीं हैं, तो इस Railscast ( railscasts.com/episodes/211-validations-in-rails-3 ) या गाइड.rubyonrails.org/active_reverord_validations.html
balexand


7

से रेल 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

5

रेल 4 में बस अपने मॉडल को जोड़ें validates :email, email:true(अपने क्षेत्र को कहा जाता है email) और फिर एक सरल (या जटिल simple) लिखें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" जैसे टैग किए गए ईमेल शामिल हैं।

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

मैंने इसे वैसे भी किया है। YMMV

† नियमित अभिव्यक्ति हिंसा की तरह है; यदि वे काम नहीं करते हैं तो आप उनमें से पर्याप्त का उपयोग नहीं कर रहे हैं।


1
मुझे आपकी मान्यता का उपयोग करने का प्रलोभन है, लेकिन मुझे नहीं पता कि आपको यह कहां से मिला या आपने इसे कैसे बनाया। क्या तुम हमे बता सकते हो?
मौरिसियो मोरेस

मुझे एक Google खोज से नियमित अभिव्यक्ति मिली, और मैंने खुद को रैपर कोड और कल्पना परीक्षण लिखा।
डेव सैग

1
यह बहुत अच्छा है कि आपने परीक्षणों को पोस्ट किया है! लेकिन वास्तव में मुझे जो मिल रहा था, वह वहीं था! :)
मौरिसियो मोरेस

4

जैसा कि हेलीलूजा सुझाव देते हैं कि मुझे लगता है कि मेल रत्न का उपयोग करना एक अच्छा तरीका है। हालाँकि, मुझे वहाँ के कुछ हुप्स नापसंद हैं।

मैं उपयोग करता हूं:

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

आप इस सूची में TLDs (शीर्ष स्तर के डोमेन) की मांग करके सख्त हो सकते हैं , हालाँकि आप उस सूची को नए TLDs के रूप में अपडेट करने के लिए बाध्य होंगे (जैसे 2012 जोड़ .mobiऔर .tel)

पार्सर डायरेक्ट को हुक करने का लाभ यह है कि मेल व्याकरण में मेल जेम का उपयोग करने वाले भागों के लिए नियम काफी विस्तृत हैं, इसे ऐसे पते पर पार्स करने की अनुमति देने के लिए डिज़ाइन किया गया है user<user@example.com>जो SMTP के लिए सामान्य है। इसका सेवन करने से Mail::Addressआप अतिरिक्त जांच करने के लिए मजबूर हो जाते हैं।

मेल रत्न के बारे में एक और टिप्पणी, भले ही वर्ग को RFC2822 कहा जाता है, व्याकरण में RFC5322 के कुछ तत्व हैं , उदाहरण के लिए यह परीक्षण


1
इस स्निपेट के लिए धन्यवाद, सैम। मुझे थोड़ा आश्चर्य है कि मेल जेम द्वारा प्रदान की गई "सामान्य रूप से सबसे अच्छा" अधिकांश समय मान्य नहीं है।
जद।

4

रेल 3 में एक पुन: प्रयोज्य सत्यापनकर्ता लिखना संभव है , क्योंकि यह महान पोस्ट बताता है:

http://archives.ryandaigle.com/articles/2009/8/11/what-s-new-in-edge-rails-independent-model-validators

class EmailValidator < ActiveRecord::Validator   
  def validate()
    record.errors[:email] << "is not valid" unless
    record.email =~ /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i   
  end
end

और इसके साथ प्रयोग करें validates_with:

class User < ActiveRecord::Base   
  validates_with EmailValidator
end

3

अन्य उत्तरों को ध्यान में रखते हुए, यह सवाल अभी भी बना हुआ है - इसके बारे में चतुर होने को परेशान क्यों करें?

किनारे के मामलों की वास्तविक मात्रा जिसे कई रेगेक्स अस्वीकार कर सकते हैं या याद कर सकते हैं समस्याग्रस्त है।

मुझे लगता है कि सवाल यह है कि 'मैं क्या करने की कोशिश कर रहा हूं?'

यदि आप regexp के लिए जाते हैं, तो बस क्लाइंट की तरफ @ की उपस्थिति की जांच करें।

गलत ईमेल परिदृश्य के लिए, अपने कोड में 'संदेश भेजने में विफल' शाखा है।


1

मूल रूप से 3 सबसे आम विकल्प हैं:

  1. Regexp (सभी ई-मेल पते regexp के लिए कोई काम नहीं है, इसलिए अपना खुद का रोल करें)
  2. एमएक्स क्वेरी (जो आप उपयोग करते हैं)
  3. सक्रियण टोकन बनाना और उसे मेल करना (restful_authentication तरीका)

यदि आप मान्य_email_veracity_of और टोकन पीढ़ी दोनों का उपयोग नहीं करना चाहते हैं, तो मैं पुराने स्कूल regexp की जाँच करूँगा।


1

मेल रत्न में एक एड्रेस पार्सर होता है।

begin
  Mail::Address.new(email)
  #valid
rescue Mail::Field::ParseError => e
  #invalid
end

रेल 3.1 में मेरे लिए काम नहीं करता है। मेल :: Address.new ("जॉन") एक अपवाद के बिना मुझे खुशी से एक नया मेल :: पता वस्तु देता है।
jasoncrawford

ठीक है, यह कुछ मामलों में अपवाद फेंक देगा, लेकिन सभी नहीं। @ हलीलूजाह की कड़ी से लगता है कि यहां अच्छा दृष्टिकोण है।
जस्सोन्फोर्ड

1

यह समाधान, रिफ्लेक्टर और उपयोग स्पष्टीकरण के साथ @SFEley और @Alessandro DS के उत्तरों पर आधारित है।

आप अपने मॉडल में इस सत्यापनकर्ता वर्ग का उपयोग कर सकते हैं जैसे:

class MyModel < ActiveRecord::Base
  # ...
  validates :colum, :email => { :allow_nil => true, :message => 'O hai Mark!' }
  # ...
end

आपके app/validatorsफ़ोल्डर में निम्नलिखित दिए गए हैं (रेल 3):

class EmailValidator < ActiveModel::EachValidator

  def validate_each(record, attribute, value)
    return options[:allow_nil] == true if value.nil?

    unless matches?(value)
      record.errors[attribute] << (options[:message] || 'must be a valid email address')
    end
  end

  def matches?(value)
    return false unless value

    if /\A[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]+\z/.match(value).nil?
      false
    else
      true
    end

  end
end

1

के लिए मेलिंग सूची मान्यकरण । (मैं 4.1.6 रेल का उपयोग करता हूं)

मुझे यहाँ से अपना regexp मिला । यह एक बहुत ही पूर्ण प्रतीत होता है, और इसे बड़ी संख्या में संयोजनों के खिलाफ परीक्षण किया गया है। आप उस पृष्ठ पर परिणाम देख सकते हैं।

मैंने इसे थोड़ा रूबी रीजेक्सपी में बदल दिया, और इसे अपने में डाल दिया lib/validators/email_list_validator.rb

यहाँ कोड है:

require 'mail'

class EmailListValidator < ActiveModel::EachValidator

  # Regexp source: https://fightingforalostcause.net/content/misc/2006/compare-email-regex.php
  EMAIL_VALIDATION_REGEXP   = Regexp.new('\A(?!(?:(?:\x22?\x5C[\x00-\x7E]\x22?)|(?:\x22?[^\x5C\x22]\x22?)){255,})(?!(?:(?:\x22?\x5C[\x00-\x7E]\x22?)|(?:\x22?[^\x5C\x22]\x22?)){65,}@)(?:(?:[\x21\x23-\x27\x2A\x2B\x2D\x2F-\x39\x3D\x3F\x5E-\x7E]+)|(?:\x22(?:[\x01-\x08\x0B\x0C\x0E-\x1F\x21\x23-\x5B\x5D-\x7F]|(?:\x5C[\x00-\x7F]))*\x22))(?:\.(?:(?:[\x21\x23-\x27\x2A\x2B\x2D\x2F-\x39\x3D\x3F\x5E-\x7E]+)|(?:\x22(?:[\x01-\x08\x0B\x0C\x0E-\x1F\x21\x23-\x5B\x5D-\x7F]|(?:\x5C[\x00-\x7F]))*\x22)))*@(?:(?:(?!.*[^.]{64,})(?:(?:(?:xn--)?[a-z0-9]+(?:-[a-z0-9]+)*\.){1,126}){1,}(?:(?:[a-z][a-z0-9]*)|(?:(?:xn--)[a-z0-9]+))(?:-[a-z0-9]+)*)|(?:\[(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){7})|(?:(?!(?:.*[a-f0-9][:\]]){7,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,5})?)))|(?:(?:IPv6:(?:(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){5}:)|(?:(?!(?:.*[a-f0-9]:){5,})(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3})?::(?:[a-f0-9]{1,4}(?::[a-f0-9]{1,4}){0,3}:)?)))?(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))(?:\.(?:(?:25[0-5])|(?:2[0-4][0-9])|(?:1[0-9]{2})|(?:[1-9]?[0-9]))){3}))\]))\z', true)

  def validate_each(record, attribute, value)
    begin
      invalid_emails = Mail::AddressList.new(value).addresses.map do |mail_address|
        # check if domain is present and if it passes validation through the regex
        (mail_address.domain.present? && mail_address.address =~ EMAIL_VALIDATION_REGEXP) ? nil : mail_address.address
      end

      invalid_emails.uniq!
      invalid_emails.compact!
      record.errors.add(attribute, :invalid_emails, :emails => invalid_emails.to_sentence) if invalid_emails.present?
    rescue Mail::Field::ParseError => e

      # Parse error on email field.
      # exception attributes are:
      #   e.element : Kind of element that was wrong (in case of invalid addres it is Mail::AddressListParser)
      #   e.value: mail adresses passed to parser (string)
      #   e.reason: Description of the problem. A message that is not very user friendly
      if e.reason.include?('Expected one of')
        record.errors.add(attribute, :invalid_email_list_characters)
      else
        record.errors.add(attribute, :invalid_emails_generic)
      end
    end
  end

end

और मैं इसे मॉडल में इस तरह उपयोग करता हूं:

validates :emails, :presence => true, :email_list => true

यह अलग-अलग विभाजक और सिंटैक्स के साथ मेलिंग सूचियों को इस तरह मान्य करेगा:

mail_list = 'John Doe <john@doe.com>, chuck@schuld.dea.th; David G. <david@pink.floyd.division.bell>'

इस regexp का उपयोग करने से पहले, मैंने उपयोग किया था Devise.email_regexp, लेकिन यह एक बहुत ही सरल rexxp है और मुझे उन सभी मामलों की आवश्यकता नहीं है जो मुझे चाहिए। कुछ ईमेल टकरा गए।

मैं वेब से अन्य regexps की कोशिश की, लेकिन यह एक अब तक का सबसे अच्छा परिणाम है। आशा है कि यह आपके मामले में मदद करता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.