नॉलेज बेस
वेबहुक
मेल आने पर आपको पोल कराने के बजाय आपके एंडपॉइंट को बता दें।
विवरण
- आज Settings → Webhooks से और API पर इस्तेमाल के लिए तैयार: एक https एंडपॉइंट रजिस्टर करें, बीस इवेंट में से चुनें कि उसे कौन-से चाहिए, और whsec_ साइनिंग सीक्रेट कॉपी कर लें, जो बनाते समय और घुमाते समय दिखता है और उसके बाद कभी नहीं। डिलीवरी असली, हस्ताक्षरित POST हैं जिन्हें किसी API कॉल के बजाय मेलबॉक्स स्वयं उठाता है, इसलिए वे आने वाली मेल पर तथा opens और clicks पर चलती हैं, चाहे संदेश किसी ने भी भेजा हो। भेजना हर सतह से इवेंट उठाता है, और पहले यह सिर्फ़ कुछ ही सतहों से उठता था: API, MCP, टेम्पलेट या किसी नियम से भेजा गया संदेश email.sent उठाता था जबकि ऐप के अपने कंपोज़र से भेजा गया संदेश नहीं, क्योंकि कंपोज़र उस सेंड सेवा से होकर लिखने के बजाय सीधे मेलबॉक्स में लिखता है जो इवेंट निकालती थी। अब इवेंट मेलबॉक्स पर ही उठाया जाता है, जहाँ वे सब मिलते हैं, इसलिए ऐप में लिखना, मंगलवार के लिए शेड्यूल करना और API पर पोस्ट करना — एक ही वेबहुक पैदा करने के तीन तरीके हैं। टाला गया सेंड यह दो बार कहता है: स्वीकार होने पर email.scheduled या email.queued, वास्तव में जाने पर email.sent, और बीच में वापस ले लेने पर email.cancelled। प्रति मेलबॉक्स दस एंडपॉइंट, जो केवल इसी स्क्रीन पर नहीं बल्कि जहाँ कहीं भी एंडपॉइंट रजिस्टर हो वहाँ लागू होते हैं।
- इवेंट तीन परिवारों में आते हैं। पंद्रह एक संदेश के बारे में हैं: email.received, email.replied, email.sent, email.delivered, email.failed, email.cancelled, email.scheduled, email.queued (scheduled का undo-send भाई), email.delivery_delayed, email.bounced, email.complained, email.suppressed, email.opened, email.clicked और email.downloaded। email.sent का मतलब है कि भेजने वाली सेवा ने संदेश स्वीकार किया, email.delivered का मतलब है कि पाने वाले सर्वर ने स्वीकार किया, और email.delivery_delayed का मतलब है कि वह अभी पहुँचा नहीं है और कोशिश जारी है। जब आने वाला संदेश मेलबॉक्स में पहले से मौजूद किसी संदेश का उत्तर होता है तो email.replied, email.received के साथ-साथ चलता है, इसलिए जो उपभोक्ता दोनों चाहता है उसे दोनों मिलते हैं। email.downloaded तब चलता है जब कोई व्यक्ति डाउनलोड लिंक के रूप में गई फ़ाइल लाता है, और वही क्लासिफ़ायर स्कैनर और लिंक प्रीव्यू को गिनती से बाहर रखता है, और यह किसी प्राप्तकर्ता का नाम नहीं लेता, क्योंकि लिंक उन सबके लिए एक ही होता है जिन्हें संदेश गया था। तीन एक डोमेन के बारे में हैं: मेल लेना शुरू करने पर domain.verified, भेजने का फ़ैसला बदलने पर domain.sending_changed, और हटाए जाने पर domain.deleted — चाहे आपने कहा हो या सात-दिन वाले रीपर ने असत्यापित डोमेन गिरा दिया हो। दो सप्रेशन सूची के बारे में हैं, जो email.suppressed से अलग चीज़ है: कोई पता सूची में आने पर suppression.added, और किसी को फिर से अनुमति मिलने पर suppression.removed। इनमें से किसी की भी सदस्यता न लेने का मतलब है email.replied को छोड़कर हर संदेश इवेंट, आज चौदह, और बाद में जोड़ा गया कोई परिवार कभी नहीं, और API इसे ["*"] के रूप में वापस पढ़ता है। अगर आप स्पष्ट रहना चाहते हैं तो जो इवेंट चाहिए उनके नाम लिख दें। हर डिलीवरी X-OpenEmail-Signature को t=<unix>,v1=<hex> के रूप में ले जाती है, जो टाइमस्टैम्प, एक बिंदु और कच्चे body पर HMAC-SHA-256 है, साथ ही X-OpenEmail-Event और X-OpenEmail-Delivery। सत्यापन उन्हीं बाइट्स के विरुद्ध करें जैसे वे आए थे: पार्स करके दोबारा सीरियलाइज़ करने से कुंजियों का क्रम बदल जाता है और हस्ताक्षर टूट जाता है। 300-सेकंड की रीप्ले विंडो लागू करना पाने वाले का काम है, और SDK का सत्यापक डिफ़ॉल्ट रूप से यही मानता है।
- जो https न हो या सार्वजनिक रूप से रूट न किया जा सकता हो (loopback, RFC1918, link-local, CGNAT और उनके IPv6 समकक्ष) उसका रजिस्ट्रेशन ठुकरा दिया जाता है, और रीडायरेक्ट का पीछा नहीं किया जाता, इसलिए 3xx को कहीं और खदेड़ने के बजाय विफल डिलीवरी के रूप में दर्ज किया जाता है। पाने वाले को 5 सेकंड मिलते हैं, एंडपॉइंट समानांतर में डिलीवर होते हैं इसलिए उनमें से दस में भी 50 सेकंड नहीं, 5 सेकंड ही लगते हैं, और हर प्रयास, एक-एक पेज करके, उस एंडपॉइंट के पेज पर रिस्पॉन्स कोड और लगे समय के साथ सूचीबद्ध रहते हैं।
- डिलीवरी की अधिकतम 8 बार कोशिश की जाती है। पहली इवेंट होते ही जाती है; ऐसी विफलता जो अपने आप ठीक हो सकती है उसे 1 मिनट बाद, फिर 5, फिर 30, फिर 2 घंटे, 5 घंटे, 10 घंटे और फिर 10 घंटे बाद दोहराया जाता है, जिससे एक इवेंट लगभग साढ़े 27 घंटे में फैल जाता है। हर इंतज़ार दसवें हिस्से तक घटता-बढ़ता है, ताकि एक साथ विफल हुए हज़ार इवेंट एक ही सेकंड में न लौटें, और अगर एंडपॉइंट का Retry-After ज़्यादा देर माँगे तो 6 घंटे तक उसका पालन होता है। रीट्राई मेमोरी में नहीं, टिकाऊ काम के रूप में रखी जाती हैं, इसलिए उस विंडो के बीच किया गया कोई डिप्लॉय उन्हें खोता नहीं। केवल वही विफलताएँ दोहराई जाती हैं जिन्हें दोहराना सार्थक है: टाइमआउट, ठुकराया गया कनेक्शन, 408, 425, 429 या कोई भी 5xx। कोई भी दूसरा 4xx इसका मतलब है कि एंडपॉइंट जानबूझकर पेलोड ठुकरा रहा है, और सात बार और पूछना उसी उत्तर के लिए सात गुना भार होता। इवेंट id और उसका createdAt एक बार तय होते हैं और हर प्रयास उन्हें ले जाता है, id को X-OpenEmail-Delivery में भी, इसलिए जो पाने वाला एक ही id दो बार देखे वह दूसरी पर कार्रवाई करने के बजाय उसे गिरा सकता है। एंडपॉइंट ठीक हो जाने पर विफल हुई डिलीवरी को ऐप के डिलीवरी लॉग से या API से रीप्ले किया जा सकता है, एक बार में एक इवेंट, और रीप्ले में वही id जाती है। रीप्ले भेजे जाते समय उस इवेंट के अपने-आप होने वाले retry रोक देता है, और अगर उनमें से कोई पहले से भेजा जा रहा हो तो मना कर देता है, ताकि पाने वाले को एक साथ दो कॉपी कभी न मिलें। लगातार 100 इवेंट के हर प्रयास विफल होने पर एंडपॉइंट अक्षम कर दिया जाता है, वर्कस्पेस को ईमेल किया जाता है, और कारण एंडपॉइंट पर ही पढ़ा जा सकता है। जो एंडपॉइंट 410 Gone लौटाता है वह तुरंत अक्षम कर दिया जाता है।
- जो एंडपॉइंट लगातार 100 बार विफल होता है उसे हमेशा के लिए डायल करते रहने के बजाय बंद कर दिया जाता है, और webhooks एक्सेस रखने वाले हर व्यक्ति को यह बताने के लिए ईमेल किया जाता है: कौन-सा एंडपॉइंट, आखिरी प्रयास ने क्या बताया, और यह कि विफलता के दौरान कुछ भी कतार में नहीं रखा गया। गिनती लगातार वाली है और कोई भी सफल प्रयास उसे शून्य कर देता है, इसलिए पिछले मार्च की एक खराब दोपहर आज अक्षम एंडपॉइंट तक नहीं जोड़ी जा सकती। उसे वापस चालू करने पर गिनती भी साफ़ हो जाती है। कंसोल एक ही टॉगल दिखाने के बजाय दोनों स्थितियों में फ़र्क करता है: जो एंडपॉइंट आपने बंद किया वह उससे अलग दिखता है जिसे हमने बंद किया।
- एंडपॉइंट प्रबंधित करना एक ही काम है जिसके दो दरवाज़े हैं। API पर यह POST /webhooks, patch, delete, rotate-secret, test, डिलीवरी लॉग और रीप्ले है, और SDK में हर एक के लिए एक मेथड है; ऐप में यह Settings → Webhooks है, जो दूसरी नहीं, उसी रजिस्ट्री पर चलता है। पढ़ना webhooks:read पर निर्भर है, इसलिए कोई भी इंटीग्रेशन बनाने वाला मालिक हुए बिना एंडपॉइंट और उनका डिलीवरी इतिहास देख सकता है (कौन-सा चला, पाने वाले ने क्या जवाब दिया, कितना समय लगा)। रजिस्टर करने, संपादित करने, परखने, घुमाने, रीप्ले करने और हटाने के लिए दोनों सतहों पर webhooks:write और मेलबॉक्स का स्वामित्व, दोनों चाहिए, और दूसरा हिस्सा जानबूझकर है: जब तक एंडपॉइंट की अपनी अनुमति-सूचियाँ उसे सीमित न करें, उसे वर्कस्पेस के हर पते की ख़बर विषय और प्राप्तकर्ताओं सहित मिलती है, और अनुमति न होने का मतलब है “यह सब भेजा जा सकता है”। जो भूमिका इंटीग्रेशन बनाती है और मेल नहीं पढ़ती, वह इसे इसके बजाय वर्कस्पेस कुंजी से चलाती है। किसी डिलीवरी को खोलकर भेजा गया body और पूरा जवाब पढ़ने के लिए भी मालिक होना ज़रूरी है, क्योंकि उस body में वही subject और प्राप्तकर्ता होते हैं।
- लॉग हर जगह एक ही तरह पढ़े जाते हैं। GET /webhooks/deliveries एक साथ सभी एंडपॉइंट का डिलीवरी लॉग पढ़ता है और GET /webhooks/{id}/deliveries एक एंडपॉइंट का, दोनों स्थिति, यानी «सिर्फ़ विफल» स्विच, और समय-सीमा से सीमित, और GET /webhooks/activity और GET /webhooks/{id}/activity पढ़ते हैं कि किसने क्या बनाया, बदला, बंद या चालू किया, रोटेट किया, टेस्ट किया, फिर से भेजा या हटाया, @username के रूप में या उस API कुंजी के रूप में जिसने यह किया। SDK में हर एक के लिए एक मेथड है, और MCP सर्वर में listWebhookDeliveries, getWebhookDelivery, listWebhookActivity और replayWebhookDelivery हैं, जो भेजने से पहले हमेशा पूछता है। किसी डिलीवरी की बॉडी पढ़ना हर सतह पर सिर्फ़ मालिक के पास रहता है, और किसी डोमेन के एक पते तक सीमित कुंजी उस एंडपॉइंट की डिलीवरी नहीं पढ़ सकती जो पूरे डोमेन को कवर करता है।