कॉन्फ़िगरेशन
क्लाइंट बनाने के तीन तरीके, हर option, और रिक्वेस्ट भेजे जाने से पहले वह क्या अस्वीकार करता है।
विकल्प
require "openemail" OpenEmail.init(api_key: ENV.fetch("OPENEMAIL_API_KEY"))OpenEmail.me.ping pinned = OpenEmail::Client.new(api_key: ENV.fetch("OPENEMAIL_API_KEY"), base_url: "https://api.openemail.uk")quick = OpenEmail::Client.new(ENV.fetch("OPENEMAIL_API_KEY"))billing = OpenEmail.create_client(api_key: ENV.fetch("BILLING_API_KEY")) p pinned.mode, quick.mode, billing.mode| प्रवेश बिंदु | यह आपको क्या देता है |
|---|---|
| OpenEmail.init(...) | साझा क्लाइंट को कॉन्फ़िगर करके उसे लौटाता है। इसके बाद हर फ़ाइल और हर थ्रेड में OpenEmail.client वही क्लाइंट होता है, और जो कुछ आप छोड़ देते हैं वह एनवायरनमेंट से पढ़ा जाता है। |
| OpenEmail.client, OpenEmail.emails, OpenEmail.threads और हर दूसरा namespace | साझा क्लाइंट और उसके namespaces के शॉर्टकट। init से पहले इस्तेमाल करने पर यह पहली कॉल पर ख़ुद को OPENEMAIL_API_KEY और OPENEMAIL_BASE_URL से बना लेता है। |
| OpenEmail.reset_client | साझा क्लाइंट को हटा देता है, ताकि अगली कॉल एनवायरनमेंट से एक नया क्लाइंट बनाए। |
| OpenEmail.create_client(...) | उसी एनवायरनमेंट फ़ॉलबैक वाला एक अलग क्लाइंट, साझा क्लाइंट के साथ दूसरी कुंजी के लिए, या ऐसे क्लाइंट के लिए जिसे आपका अपना कोड रखता और आगे पास करता है। |
| OpenEmail::Client.new(...) or OpenEmail::Client.new(api_key) | एक अलग क्लाइंट जो ठीक उसी से बनता है जो आप पास करते हैं। यह कोई एनवायरनमेंट नहीं पढ़ता, इसलिए इसे api_key: या access_token: चाहिए। OpenEmail.new भी यही कॉल है। |
OpenEmail.init( api_key: ENV.fetch("OPENEMAIL_API_KEY"), base_url: "https://api.openemail.uk", timeout: 30, max_retries: 2, adapter: OpenEmail::NetHttpAdapter.new(max_idle: 8, keep_alive_timeout: 2), headers: {"X-Team" => "billing"}, user_agent: "billing-service/1.4", disable_update_notice: true)| विकल्प | डिफ़ॉल्ट | टिप्पणियाँ |
|---|---|---|
| api_key: | OPENEMAIL_API_KEY | init, create_client और साझा क्लाइंट इसे एनवायरनमेंट से पढ़ते हैं। oe_live_ या oe_test_ से शुरू होना चाहिए। यह पहला argument भी हो सकता है, पर दोनों नहीं। |
| access_token: | OPENEMAIL_ACCESS_TOKEN | एक OAuth एक्सेस टोकन, या कुछ भी जो call का जवाब दे और टोकन लौटाए। नीचे “OAuth एक्सेस टोकन” देखें। कुंजी या टोकन में से एक पास करें, दोनों कभी नहीं। |
| base_url: | https://api.openemail.uk | या OPENEMAIL_BASE_URL। आख़िर के slash हटा दिए जाते हैं, और init तथा create_client सादे होस्ट के आगे https:// लगाते हैं, और इसी मशीन के होस्ट के आगे http://: localhost, कोई 127.x.x.x पता या ::1। कोई क्रेडेंशियल कभी सादे http पर किसी दूसरे होस्ट को नहीं भेजा जाता, और 0.0.0.0 या [::] क्लाइंट बनते समय raise करते हैं, क्योंकि ये वे पते हैं जिन पर सर्वर सुनता है, रिक्वेस्ट भेजने के पते नहीं। |
| timeout: | 30 | हर प्रयास के लिए सेकंड, हर कॉल के लिए नहीं। डिफ़ॉल्ट एडैप्टर के साथ यह कनेक्ट होने और पूरी बॉडी पढ़ने को कवर करता है, सिर्फ़ हेडर को नहीं। 0 इसे बंद कर देता है। files.upload कम से कम 600 सेकंड इंतज़ार करता है, जब तक आप उसी कॉल पर timeout: पास न करें। |
| max_retries: | 2 | पहली कोशिश के बाद के अतिरिक्त प्रयास, उन कॉलों पर जिन्हें दोहराना सुरक्षित है। यह क्लाइंट पर सेट होता है, प्रति कॉल नहीं। 0 पुनः प्रयास बंद कर देता है। |
| adapter: | OpenEmail::NetHttpAdapter.new | HTTP परत। डिफ़ॉल्ट हर होस्ट के लिए 8 तक निष्क्रिय कनेक्शन, हर एक को 2 सेकंड तक, रखता है, और max_idle: तथा keep_alive_timeout: इसे बदलते हैं। जो कुछ भी call(request) का जवाब दे वह इसकी जगह ले सकता है, और इसी तरह टेस्ट बिना नेटवर्क के चलता है। |
| headers: | {} | हर रिक्वेस्ट पर भेजा जाता है। |
| user_agent: | openemail-ruby/<version> | हर रिक्वेस्ट पर भेजा जाता है। |
| disable_update_notice: | false | RubyGems पर नए वर्शन की प्रति-प्रोसेस-एक-बार वाली जाँच को छोड़ देता है। यह जाँच तभी चलती है जब standard output कोई terminal हो, और OPENEMAIL_DISABLE_UPDATE_NOTICE भी इसे बंद कर देता है। |
एनवायरनमेंट वेरिएबल
| वेरिएबल | यह क्या करता है |
|---|---|
| OPENEMAIL_API_KEY | वह कुंजी जिसे init, create_client और साझा क्लाइंट तब इस्तेमाल करते हैं जब आप न api_key: पास करते हैं और न access_token:। |
| OPENEMAIL_ACCESS_TOKEN | एक OAuth एक्सेस टोकन, जिसे सिर्फ़ तब पढ़ा जाता है जब आप दोनों में से कोई क्रेडेंशियल नहीं देते और OPENEMAIL_API_KEY सेट नहीं है, यानी एनवायरनमेंट में मौजूद कुंजी को प्राथमिकता मिलती है। |
| OPENEMAIL_BASE_URL | बेस URL, जब आप कोई नहीं देते। localhost:2222 जैसे सादे होस्ट में उसकी scheme जोड़ दी जाती है। |
| OPENEMAIL_DISABLE_UPDATE_NOTICE | कोई भी ग़ैर-ख़ाली मान प्रोसेस के हर क्लाइंट के लिए अपडेट सूचना बंद कर देता है। |
| HTTPS_PROXY और NO_PROXY, या https_proxy और no_proxy | वह प्रॉक्सी जिसके ज़रिए डिफ़ॉल्ट एडैप्टर जुड़ता है, और वे होस्ट जो सीधे जुड़ते हैं। नीचे “प्रॉक्सी” देखें। |
OpenEmail::Client.new पहले तीन में से कोई नहीं पढ़ता, इसलिए इस तरह बना क्लाइंट कभी ग़लती से एनवायरनमेंट से कुंजी नहीं उठाता। जो वेरिएबल सेट है पर ख़ाली है, उसे सेट नहीं माना जाता।
भेजने से पहले यह क्या अस्वीकार करता है
ये आपके पहले send पर किसी उलझाऊ विफलता के रूप में सामने आने के बजाय उसी पंक्ति से ArgumentError raise करते हैं जिसमें ग़लत मान था। संदेश बताता है कि क्या ग़लत था और उसकी जगह क्या पास करना है, और वह कभी कोई क्रेडेंशियल नहीं दोहराता।
| अस्वीकृत | क्यों |
|---|---|
| कोई क्रेडेंशियल ही नहीं | न api_key: पास किया गया और न access_token:, और init तथा create_client के लिए कोई भी वेरिएबल सेट नहीं था, इसलिए प्रमाणित करने के लिए कुछ नहीं है। क्लाइंट बनते समय raise होता है। |
| एक कुंजी और एक टोकन एक साथ | हर रिक्वेस्ट एक ही क्रेडेंशियल ले जाती है, इसलिए क्लाइंट यह नहीं बता सकता कि आपका मतलब कौन-सा था। जो कुंजी पहले argument के रूप में भी और api_key: के रूप में भी पास की गई हो, उसे इसी कारण अस्वीकार किया जाता है। |
| सेशन कुकी, सेशन टोकन या किसी दूसरी सेवा की कुंजी | यहाँ केवल oe_live_ और oe_test_ ही प्रमाणित होते हैं, और API भी यही कहता है। यह जाँच सिर्फ़ prefix देखती है, इससे ज़्यादा कुछ नहीं, इसलिए रद्द की गई कुंजी फिर भी नेटवर्क पर जाकर ही विफल होती है, OpenEmail::AuthenticationError के रूप में। |
| ऐसा base_url: जो http या https URL नहीं है, या जिसमें यूज़र नाम या पासवर्ड हो | किसी और चीज़ तक पहुँचा नहीं जा सकता, और क्रेडेंशियल की जगह api_key: या access_token: में है, URL में नहीं। क्लाइंट बनते समय raise होता है। |
| सादे http पर ऐसे होस्ट को क्रेडेंशियल जो इस मशीन पर नहीं है | कुछ भी भेजे जाने से पहले कॉल ही इसे raise करती है। https वाला बेस URL इस्तेमाल करें। |
| ऐसा timeout: जो सेकंड की संख्या नहीं है, या ऋणात्मक है | सेकंड पास करें, या टाइमआउट न चाहिए तो 0। क्लाइंट बनते समय raise होता है। |
| ऐसा हेडर नाम जो HTTP token नहीं है, या हेडर मान में लाइन ब्रेक | headers:, user_agent: और idempotency_key: में जाँचा जाता है, क्योंकि लाइन ब्रेक एक दूसरा हेडर शुरू कर देता। |
| किसी भी method पर खाली या सिर्फ़ बिंदुओं वाला id | मेथड कॉल होते ही raise होता है। सिर्फ़ बिंदुओं वाले path segment को हर URL parser हटा देता है, इसलिए रिक्वेस्ट किसी दूसरे endpoint पर पहुँच जाती। जो id वैध UTF-8 नहीं है, उसे भी अस्वीकार किया जाता है। |
| ऐसी रिक्वेस्ट बॉडी जो Hash नहीं है | keyword arguments या एक Hash पास करें। जो कुछ भी to_hash का जवाब दे, उसे Hash ही माना जाता है। |
test_mode: नाम का कोई विकल्प नहीं है और न होगा। कुंजी की योजना संकेत नहीं, बल्कि क्रेडेंशियल का हिस्सा है, इसलिए mode कुंजी का ही गुण है। client.mode prefix पढ़ता है, "live" या "test", और तय कुछ नहीं करता।
एक क्लाइंट, कई कुंजियाँ
क्लाइंट एक बार बनाइए और उसी को साझा कीजिए। हर रिक्वेस्ट पर नया क्लाइंट अपने खुले कनेक्शन बेवजह फेंक देता है, और उस पर रखी कोई भी स्थिति प्रति-कॉलर नहीं होती। बनने के बाद क्लाइंट frozen हो जाता है और एक साथ कई थ्रेड्स से इस्तेमाल करना सुरक्षित है, इसलिए Puma या Sidekiq प्रोसेस को सिर्फ़ एक चाहिए, और fork के बाद चाइल्ड अपने कनेक्शन खोलता है।
जिस स्थिति में वरना हर कुंजी के लिए एक क्लाइंट बनाना पड़ता, जैसे कई वर्कस्पेस की ओर से भेजने वाला कोई जॉब, वहाँ कॉल पर ही api_key: पास करें। यह उस रिक्वेस्ट के लिए Authorization हेडर बदल देता है और क्लाइंट पर कुछ भी पीछे नहीं छोड़ता।
message = {from: "[email protected]", to: "[email protected]", subject: "Your invoice", text: "Attached."}workspace_key = ENV.fetch("OPENEMAIL_API_KEY") client.emails.send(message) client.emails.send(message, api_key: workspace_key) client.threads.list(folder: "inbox", api_key: workspace_key)client.webhooks.list(api_key: workspace_key)temp_mail के बाहर हर मेथड इसे keyword argument के रूप में लेता है, सूची पर फ़िल्टरों के साथ, और temp_mail के मेथड इसकी जगह inbox_token: लेते हैं। रिक्वेस्ट भेजे जाने से पहले इसकी जाँच उसी नियम से होती है जो क्लाइंट इस्तेमाल करता है, इसलिए टाइपो पर किसी ऐसे क्रेडेंशियल के बारे में 401 के बजाय, जिसे फिर आपको ढूँढना पड़े, इस कॉल को पास की गई api_key के बारे में एक ArgumentError raise होता है। दोबारा आज़माई गई कॉल वही कुंजी रखती है जो उसे दी गई थी।
client.mode उस कुंजी का वर्णन करता है जिससे क्लाइंट “बनाया” गया था, और यह किसी override के पीछे नहीं चलता। जब एक ही क्लाइंट कई कुंजियों को सेवा देता है तो बताने लायक कोई एक mode रहता ही नहीं, इसलिए इसे उसी कुंजी से पढ़ें जो आपने पास की थी। client.inspect mode और बेस URL दिखाता है, कुंजी कभी नहीं।
ऐसे endpoints जिन्हें कोई मेथड नहीं लपेटता
client.raw वह transport है जिससे हर मेथड गुज़रता है। client.raw.request ऐसे path को कॉल करता है जिसे अभी कोई मेथड नहीं लपेटता, क्लाइंट के क्रेडेंशियल, बेस URL, टाइमआउट और पुनः प्रयास नीति को लागू करते हुए, और पार्स की गई बॉडी उसी तरह लौटाता है जैसे कोई मेथड लौटाता है।
ping = client.raw.request("/ping") label = client.raw.request("/labels", method: :post, body: {name: "Invoices"}) p ping[:ok], label[:id]| कीवर्ड | यह क्या करता है |
|---|---|
| method: | :get, जब तक आप कुछ और न कहें: :post, :put, :patch या :delete। |
| query: | query पैरामीटर का एक Hash। nil और ख़ाली मान छोड़ दिए जाते हैं, Array या Set को कॉमा से जोड़ा जाता है, और Time को ISO 8601 क्षण के रूप में भेजा जाता है। |
| body: | एक Hash, जो JSON के रूप में भेजा जाता है। |
| raw: और content_type: | जैसे हैं वैसे भेजे जाने वाले बाइट्स, binary String, IO या Pathname के रूप में, application/octet-stream के साथ जब तक आप कोई टाइप न बताएँ। |
| accept: और binary: | JSON के अलावा कोई accept: बॉडी को टेक्स्ट के रूप में लौटाता है, और binary: true उसे binary String के रूप में लौटाता है। |
| idempotent: और idempotency_key: | idempotent: true एक Idempotency-Key जोड़ता है, जो तब बनाई जाती है जब आप अपनी न दें। |
| repeatable: | क्या किसी विफलता पर पुनः प्रयास होता है। सिर्फ़ GET पर होता है, जब तक आप repeatable: true पास न करें। |
| api_key: और timeout: | वही प्रति-कॉल कुंजी, और सिर्फ़ इसी कॉल के लिए सेकंड में एक टाइमआउट। |
path एक अकेले / से शुरू होना चाहिए, और ऐसा path जिसका पूरा बना URL बेस URL के origin से बाहर चला जाए, कुछ भी भेजे जाने से पहले ArgumentError raise करता है, ताकि क्रेडेंशियल कभी किसी दूसरे होस्ट तक न पहुँचे।
डिस्पोज़ेबल इनबॉक्स
OpenEmail.create_temp_mail डिस्पोज़ेबल इनबॉक्स के लिए ऐसा क्लाइंट बनाता है जो कोई API कुंजी नहीं रखता और एनवायरनमेंट से भी कोई नहीं पढ़ता। यह गुमनाम रूप से इनबॉक्स बनाता है, और हर पढ़ाई वह इनबॉक्स टोकन भेजती है जो create ने लौटाया था, या वह नया टोकन जो extend ने लौटाया, या तो प्रति कॉल inbox_token: के रूप में या एक बार OpenEmail.create_temp_mail(inbox_token:) के रूप में।
temp_mail = OpenEmail.create_temp_mail inbox = temp_mail.createpage = temp_mail.list_messages(inbox[:id], inbox_token: inbox[:token]) p page.items.size, page.expires_atcreate_temp_mail किसी भी क्लाइंट की तरह base_url:, adapter:, max_retries:, timeout:, user_agent:, headers: और disable_update_notice: लेता है, और जब आप कोई बेस URL नहीं देते तो OPENEMAIL_BASE_URL पढ़ता है।
OAuth एक्सेस टोकन
किसी व्यक्ति का OAuth से जोड़ा गया ऐप, जैसे कमांड लाइन टूल या कोई एजेंट, API कुंजी के बजाय एक्सेस टोकन रखता है। उसे access_token: के रूप में दें: या तो ख़ुद टोकन, या कुछ भी जो call का जवाब दे और टोकन लौटाए, जैसे कोई lambda या Method। यह हर कॉल के लिए एक बार चलता है, और उस कॉल के पुनः प्रयास वही इस्तेमाल करते हैं जो इसने लौटाया, इसलिए टोकन की मियाद ख़त्म होने के क़रीब हो तो उसे इसी के अंदर नया करें, और क्लाइंट को कभी दोबारा बनाना नहीं पड़ेगा।
tokens = {current: "token-from-your-oauth-flow"} oauth_client = OpenEmail::Client.new(access_token: -> { tokens.fetch(:current) }) me = oauth_client.me.get puts me[:clientId], me[:expiresAt] if me[:object] == "oauth_token"| स्थिति | क्या होता है |
|---|---|
| api_key: और access_token: एक साथ, या दोनों में से कोई नहीं | क्लाइंट बनते समय ArgumentError raise करता है। दोनों में से कोई न हो तो संदेश OPENEMAIL_API_KEY और OPENEMAIL_ACCESS_TOKEN का नाम लेता है। |
| ऐसा मान जो टोकन नहीं है | टोकन 1 से 512 अक्षरों का होता है और oe_ से शुरू नहीं होता, यही जाँच OpenEmail.access_token? करता है। इसमें विफल String क्लाइंट बनते समय raise करती है, और ऐसा मान लौटाने वाला callable कुछ भी भेजे जाने से पहले कॉल से ArgumentError raise करता है। |
| OPENEMAIL_ACCESS_TOKEN | जब आप दोनों में से कोई क्रेडेंशियल नहीं देते और OPENEMAIL_API_KEY सेट नहीं है, तब init, create_client और साझा क्लाइंट इसे पढ़ते हैं, यानी एनवायरनमेंट में मौजूद कुंजी को प्राथमिकता मिलती है। |
| ऐसा callable जो raise करे | कॉल वही त्रुटि, बिना बदले, raise करती है, और कुछ नहीं भेजा जाता। |
| प्रति-कॉल api_key: | सिर्फ़ उस एक रिक्वेस्ट के लिए टोकन की जगह लेता है, और callable नहीं चलता। |
| client.mode | टोकन के साथ हमेशा "live"। |
| OpenEmail.create_temp_mail | वातावरण में जो भी हो, कोई क्रेडेंशियल नहीं भेजता। |
| me.get और me.ping | टोकन के लिए, get इस तरह जवाब देता है: object का मान oauth_token, id और roleId nil, जुड़े ऐप का clientId, और expiresAt, यानी जब ऐप के लिए व्यक्ति की मंज़ूरी ख़त्म होती है। ping जवाब देता है: kind का मान oauth, keyId nil और clientId। id या keyId पढ़ने से पहले object या kind जाँचें। |
टोकन किसी व्यक्ति की ओर से काम करता है और उसका मेल वैसे ही पढ़ता है जैसे वह ख़ुद पढ़ सकता है, इसलिए इसे कुंजी की तरह सर्वर पर ही रखें।
सत्यापन कोड
किसी संवेदनशील बदलाव से पहले, जैसे डोमेन हटाना या वेबहुक बदलना, API एक्सेस टोकन से वह सत्यापन कोड माँगता है जो वेब ऐप व्यक्ति से माँगता। कॉल एक OpenEmail::PermissionError raise करती है, एक 403 जिसका step_up_required? true होता है, और कुछ नहीं बदला गया। कोड माँगें, व्यक्ति से मिला कोड सत्यापित करें, फिर कॉल दोबारा करें। API कुंजी से कभी नहीं माँगा जाता।
domain_id = "b3e1f0a4-6c2d-4e8a-9f17-2d5c8a0b4e6f" begin client.domains.delete(domain_id)rescue OpenEmail::ApiError => error raise unless error.step_up_required? challenge = client.security.begin_step_up if challenge[:method] == "email" puts "Enter the code we emailed to #{challenge[:sentTo]}" else puts "Enter the code from your authenticator app, or a backup code" end client.security.verify_step_up(code: $stdin.gets.to_s.strip) client.domains.delete(domain_id)end| मेथड | यह क्या करता है |
|---|---|
| security.step_up_status | ऐप अभी सत्यापित है या नहीं (elevated, elevatedUntil), अगला कोड कैसे जाँचा जाएगा (method, email या totp), और minutes, यानी अवधि की लंबाई। यह कुछ नहीं भेजता और रोक की जानकारी नहीं देता। |
| security.begin_step_up | एक सत्यापन शुरू करता है। email में उस पते पर छह अंकों का कोड जाता है जिससे व्यक्ति साइन इन करता है, और sentTo उसे छिपे रूप में दिखाता है। totp में व्यक्ति अपने ऑथेंटिकेटर ऐप से कोड पढ़ता है या बैकअप कोड इस्तेमाल करता है। अभी खुला सत्यापन, जिसकी कोशिशें बाकी हों, दोबारा इस्तेमाल होता है, जब तक आप resend: true पास न करें, और लॉक या समाप्त हो चुके सत्यापन की जगह एक सादी कॉल नया बना देती है। हर ऐप हर व्यक्ति के लिए घंटे में 5 और 24 घंटे में 20 सत्यापन शुरू कर सकता है, और अगला 429 step_up_throttled raise करता है। |
| security.verify_step_up(code:) | कोड जाँचता है और इस ऐप के लिए संवेदनशील बदलावों को 60 मिनट तक, elevatedUntil तक, REST पर और वही बदलाव करने वाले MCP टूल के ज़रिए खोल देता है। इस ऐप से 24 घंटे में 10 ग़लत कोड, या व्यक्ति के सभी ऐप से मिलाकर 20, के बाद यह कॉल और begin_step_up एक 429 step_up_locked raise करते हैं, एक संदेश के साथ जो बताता है कि सत्यापन कब फिर शुरू होगा। |
क्लाइंट ख़ुद कभी कोड नहीं माँगता और न कॉल दोहराता है, और तीनों में से कोई मेथड अपने-आप दोबारा नहीं आज़माया जाता, क्योंकि खोए जवाब के बाद दोबारा कोशिश दूसरा ईमेल भेज सकती है या दूसरी कोशिश ख़र्च कर सकती है। इन्हें scope की ज़रूरत नहीं, और इनमें से किसी को कॉल करने वाली API कुंजी को 400 step_up_not_applicable मिलता है। OpenEmail::STEP_UP_ERROR_CODES हर उस तरीके का नाम लेता है जिससे सत्यापन विफल हो सकता है, और API त्रुटियों वाला पेज बताता है कि हर एक पर क्या करना है।
अपडेट सूचना
जब RubyGems पर gem का नया वर्शन होता है, तो क्लाइंट यह बात हर प्रोसेस में एक बार, standard error पर, ℹ openemail 0.0.2 is available, you are on 0.0.1. जैसी एक पंक्ति के रूप में बताता है, और उसके बाद gem का पेज। यह जाँच पहला क्लाइंट बनते समय, दो सेकंड के टाइमआउट वाले एक बैकग्राउंड थ्रेड में, सिर्फ़ तब चलती है जब standard output कोई terminal हो, और RubyGems तक न पहुँच पाने को अनदेखा कर दिया जाता है।
यह जाँच क्लाइंट के एडैप्टर से होकर जाती है, इसलिए जब टेस्ट किसी terminal में चलते हैं तो टेस्ट एडैप्टर RubyGems को जाती रिक्वेस्ट देख सकता है। टेस्ट क्लाइंट disable_update_notice: true के साथ बनाएँ, या OPENEMAIL_DISABLE_UPDATE_NOTICE सेट करें।
प्रॉक्सी
डिफ़ॉल्ट एडैप्टर अपना प्रॉक्सी Ruby के अपने URI#find_proxy से ढूँढता है, इसलिए वह बाक़ी मानक लाइब्रेरी जैसे ही नियम मानता है: https_proxy या HTTPS_PROXY प्रॉक्सी का नाम बताता है, और no_proxy या NO_PROXY उन होस्ट की सूची देता है जो सीधे जुड़ते हैं। प्रॉक्सी URL में यूज़र नाम और पासवर्ड प्रॉक्सी को भेजे जाते हैं, और इस मशीन पर चल रहे सर्वर तक कभी प्रॉक्सी के ज़रिए नहीं पहुँचा जाता।
कनेक्शन TLS 1.2 या उसके बाद का इस्तेमाल करते हैं और सर्वर का सर्टिफ़िकेट जाँचते हैं, इसलिए TLS की जाँच करने वाले प्रॉक्सी के लिए ज़रूरी है कि उसकी सर्टिफ़िकेट अथॉरिटी पर उस मशीन का OpenSSL भरोसा करे।
बिना नेटवर्क के टेस्टिंग
adapter: HTTP परत की जगह लेता है। यह कुछ भी हो सकता है जो call(request) का जवाब दे, lambda भी, और status, headers और body वाला OpenEmail::HttpResponse लौटाए। रिक्वेस्ट method, url, headers, body और timeout वाला एक OpenEmail::HttpRequest होती है, इसलिए टेस्ट ठीक-ठीक जाँच सकता है कि क्या बाहर जाता।
requests = [] adapter = lambda do |request| requests << request OpenEmail::HttpResponse.new( status: 200, headers: {"content-type" => "application/json"}, body: JSON.generate({id: "msg_test", status: "sent", replayed: false}) )end test_client = OpenEmail::Client.new(api_key: "oe_test_fake", adapter:, max_retries: 0, disable_update_notice: true) sent = test_client.emails.send(from: "[email protected]", to: "[email protected]", subject: "Hi", text: "Hello") p sent[:status], requests.first.method, requests.first.url, requests.first.headers["Idempotency-Key"]p requests.firstकिसी रिक्वेस्ट को प्रिंट करने पर उसका Authorization हेडर [redacted] के रूप में दिखता है, इसलिए टेस्ट लॉग में कभी कुंजी नहीं होती।
- मेल खाती
OpenEmail::ApiErrorsubclass पाने के लिए 2xx से बाहर का कोई status लौटाएँ, जिसकी बॉडी API का error envelope हो, जैसे{"error": {"type": "validation_error", "code": "invalid_parameter", "message": "..."}}। - ऐसा
OpenEmail::NetworkErrorपाने के लिए जिसकाtimeout?true हो,callसेTimeout::Errorraise करें, याNet::ReadTimeout, जो उसी का एक प्रकार है। कोई भी दूसरा StandardError, जैसेErrno::ECONNREFUSED, ऐसाNetworkErrorबन जाता है जिसकाtimeout?false होता है। - एडैप्टर के अंदर raise हुए
NameError,TypeErrorऔरArgumentErrorउसी के bug माने जाते हैं। वे बिना बदले raise होते हैं और उन पर कभी पुनः प्रयास नहीं होता।
जब आप विफलताओं की स्क्रिप्ट लिखें, तो टेस्ट क्लाइंट max_retries: 0 के साथ बनाएँ। वरना दोहराने में सुरक्षित कॉल पर पुनः प्रयास योग्य status या नेटवर्क विफलता तीन बार आज़माई जाती है, बीच में असली sleep के साथ।