2009-07-20 7 views
95

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

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

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

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

+0

रेगेक्स से निपटने के बिना यहां एक सुपर-आसान तरीका है: [पता लगाने-वैध-ईमेल-पता] (http: // lindsaar।नेट/2008/4/14/टिप -4-डिटेक्टिंग-ए-वैध-ईमेल-पता) – Zabba

+0

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

उत्तर

67

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

यहां my implementation (packaged as a gem) है।

+0

अच्छा, मैं आपके मणि का उपयोग कर रहा हूं। धन्यवाद। – jasoncrawford

+0

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

+1

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

1

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

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

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

106

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

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

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

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

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

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

+35

एर, वह संग्रहालय और नए अंतरराष्ट्रीय टीएलडी पर उस बारफ नहीं होगा? यह regex * कई वैध ईमेल पते * रोक देगा। – Elijah

+3

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

+8

** पर संग्रहालय ** संग्रहालय ** और इस तरह - जब मैंने पहली बार 200 9 में उस उत्तर को पोस्ट किया तो यह कोई मुद्दा नहीं था। मैंने रेगेक्स बदल दिया। यदि आपके पास और सुधार हैं, तो आप इसे भी संपादित कर सकते हैं, या इसे एक समुदाय विकी पोस्ट बना सकते हैं। – SFEley

6

अद्यतन: TMail Mail gem

ने ले लिया है जैसा SFEley ने कहा कि यह पूरी तरह से कैसे आप होना चाहते हैं पर निर्भर करता है।ज्यादातर मामलों में, उसका regex पर्याप्त है। मैं को किसी भी कानूनी ईमेल पते को मान्य करने के लिए शायद कुछ सीपीयू चक्रों की कीमत पर, रूबी की टीएमएल लाइब्रेरी का उपयोग करता हूं।

begin 
    TMail::Address.parse(email_address) 
    return true 
rescue 
    return false 
end 
+0

एक नोट के रूप में, टीएमएएल मणि अब मेल मणि (उसी लेखक द्वारा) से अधिक है। – lulalala

12

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

http://github.com/balexand/email_validator

+8

यह अनिवार्य रूप से रेगेक्स के चारों ओर एक रैपर है। –

+0

क्या आप इसका उदाहरण दे सकते हैं कि इसका उपयोग 'if' या 'till' कथन के साथ कैसे किया जाए? दस्तावेज़ीकरण अस्पष्ट लगता है। – cwd

+0

@cwd मुझे लगता है कि दस्तावेज़ीकरण पूरा हो गया है। यदि आप रेल 3+ मान्यताओं से परिचित नहीं हैं, तो इस रेलस्कास्ट (http://railscasts.com/episodes/211- validations-in-rails-3) या http://guides.rubyonrails.org/active_record_validations देखें .html – balexand

1

मेल मणि एक पते पार्सर में निर्माण किया है।

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

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

+0

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

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 
4

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 ([email protected]) 
    # 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 के (उच्च स्तरीय डोमेन) this list में हैं द्वारा सख्त हो सकता है, फिर भी आप नए TLD के पॉप अप (2012 की तरह के रूप में है कि सूची को अद्यतन करने के लिए मजबूर किया जाएगा इसके अलावा .mobi और .tel)

पार्सर प्रत्यक्ष hooking के लाभ यह है कि rules in Mail grammar अंश मेल मणि का उपयोग करता है के लिए काफी विस्तृत हैं, यह यह user<[email protected]> की तरह एक पते जो एसएमटीपी के लिए आम है पार्स करने के लिए अनुमति देने के लिए बनाया गया है। इसे Mail::Address से उपभोग करके आपको अतिरिक्त चेक का एक गुच्छा करने के लिए मजबूर होना पड़ता है।

मेल मणि के बारे में एक और नोट, भले ही कक्षा को आरएफसी 2822 कहा जाता है, व्याकरण में RFC5322 के कुछ तत्व हैं, उदाहरण के लिए this test

+1

इस स्निपेट के लिए धन्यवाद, सैम। मैं थोड़ा आश्चर्यचकित हूं कि मेल मणि द्वारा प्रदान की जाने वाली वैध "सामान्य" पर्याप्त "पर्याप्त नहीं है"। –

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._%+-][email protected][A-Za-z0-9.-]+\.[A-Za-z]+\z/.match(value).nil? 
     false 
    else 
     true 
    end 

    end 
end 
3

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

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

मुझे लगता है कि सवाल यह है कि 'मैं क्या स्वीकार करने की कोशिश कर रहा हूं?', भले ही आप ईमेल पते को 'मान्य' करते हैं, आप वास्तव में मान्य नहीं हैं कि यह एक कार्यरत ईमेल पता है।

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

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

7

Rails 4 docs से:

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 कहा जाता है) और फिर आपकी आवश्यकताओं के अनुरूप करने के लिए एक सरल (या जटिल †) लिखने 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 

यह सहित में चिह्नित ईमेल जैसी "परीक्षण + no_really मान्य ईमेल को हर तरह की अनुमति देगा, @ test.tes "और इसी तरह से।

अपने 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) { '[email protected]' } 
    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) { '[email protected]' } 
    it "is accepted as valid" do 
     model.errors[].should_not_receive('<<')  
     validator.validate_each(model, "email", valid_tagged_email) 
    end 
    end 
end 

में rspec के साथ इस परीक्षण करने के लिए इस तरह मैं इसे किसी भी तरह से किया है है। वाईएमएमवी

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

+1

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

+0

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

+1

यह बढ़िया है कि आपने परीक्षण भी पोस्ट किए हैं! लेकिन वास्तव में मुझे क्या मिला शक्ति-उद्धरण था! :) –

1

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

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

मैं थोड़ा एक रूबी 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 <[email protected]>, [email protected]; David G. <[email protected]>' 

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

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

संबंधित मुद्दे

 संबंधित मुद्दे