2025, Oct 20 12:31
Office 365 माइग्रेशन के बाद exchangelib में 'wrong credentials' त्रुटि का समाधान: OAuth
Office 365 पर माइग्रेशन के बाद exchangelib में 'wrong credentials'? कारण: Basic auth बंद. Outlook/Python इंटीग्रेशन के लिए OAuth सेटअप और कोड बदलाव यहाँ जानें.
जब कोई मेलबॉक्स इंटीग्रेशन सालों तक बिना रुकावट चलता है और अचानक “wrong credentials” लौटाने लगता है, तो वजह आमतौर पर टाइपो नहीं होती। ऑन-प्रिमाइसेस शैली वाले URL से Outlook on Office 365 पर हालिया बदलाव ठीक वैसा ही उदाहरण है: आपके नीचे का ऑथेंटिकेशन मॉडल बदल गया है।
प्रसंग: क्या बदला और कोड क्यों फेल हुआ
पहले एक्सेस इस तरह के URL से होता था: https://webmail.domain.it/owa/shared_mailbox@domain.it. क्लाउड में माइग्रेशन के बाद एंट्री पॉइंट https://outlook.office365.com/mail हो गया। Python इंटीग्रेशन exchangelib पर आधारित था और Credentials के जरिए यूज़रनेम/पासवर्ड का उपयोग करता था। इसमें प्रॉक्सी को फोर्स करने के लिए एक कस्टम HTTP एडेप्टर था, autodiscover सक्षम था और shared mailbox के लिए delegate access दी गई थी। माइग्रेशन से पहले यही कोड एक वैध Account ऑब्जेक्ट लौटाता था। माइग्रेशन के बाद, वही क्रेडेंशियल्स अब “wrong credentials” त्रुटि दे रहे हैं।
Autodiscover डिसेबल करने पर तात्कालिक क्रेडेंशियल विफलता से तो बचा गया, लेकिन इसके बदले सर्वर का back-off संदेश मिलने लगा।
WARNING:exchangelib.util:Server requested back off until 2025-07-31 08:42:34.617995. Sleeping 9.998383 seconds
यूज़रनेम का फॉर्मैट बदलने और environment variables या किसी अलग एडेप्टर के जरिए प्रॉक्सी को फोर्स करने की कोशिशों से भी नतीजा नहीं बदला।
वह मूल कोड जो माइग्रेशन के बाद फेल होने लगा
class RelayHTTPAdapter(requests.adapters.HTTPAdapter):
    def send(self, req, stream=False, timeout=None, verify=True, cert=None, proxies=None):
        proxies = {
            'http': 'proxy',
            'https': 'proxy',
        }
        return super().send(req, stream=stream, timeout=timeout, verify=verify, cert=cert, proxies=proxies)
def acquire_mailbox():
    try:
        usr = "UT-*****-DEV"
        pwd = "Password"
        BaseProtocol.HTTP_ADAPTER_CLS = RelayHTTPAdapter
        cfg = Configuration(
            server='outlook.office365.com',
            retry_policy=FaultTolerance(max_wait=900),
            credentials=Credentials(usr, pwd)
        )
        return Account(
            'shared_mailbox@domain.it',
            config=cfg,
            autodiscover=True,
            access_type=DELEGATE
        )
    except Exception as exc:
        print(f"Account fetch failed: {exc}...")
        return None
मूल कारण
office365.com पर अब Basic (username/password) authentication सपोर्टेड नहीं है। इसलिए Credentials(user, password) वाला फ्लो जो पहले पास हो जाता था, अब अस्वीकृत हो रहा है, भले ही मान सही हों। Autodiscover को टॉगल करने पर दिखा back-off चेतावनी मात्र एक साइड इफेक्ट है, समाधान नहीं।
समाधान
इंटीग्रेशन को OAuth पर स्विच करें। आवश्यक सेटअप और कोड परिवर्तन यहाँ दिए हैं: https://ecederstrand.github.io/exchangelib/#impersonation-oauth-on-office-365
ऊपरी स्तर पर, Python पक्ष में बदलाव यह है कि Configuration को अब Credentials(user, password) के साथ न बनाएं, बल्कि आधिकारिक गाइड के अनुसार OAuth-आधारित credentials ऑब्जेक्ट दें। बाकी प्रवाह—प्रॉक्सी एडेप्टर, सर्वर, रीट्राई पॉलिसी, autodiscover और delegate access—संरचनात्मक रूप से वैसे ही रह सकते हैं।
OAuth-आधारित credentials इंजेक्ट करके समायोजित उदाहरण
class RelayHTTPAdapter(requests.adapters.HTTPAdapter):
    def send(self, req, stream=False, timeout=None, verify=True, cert=None, proxies=None):
        proxies = {
            'http': 'proxy',
            'https': 'proxy',
        }
        return super().send(req, stream=stream, timeout=timeout, verify=verify, cert=cert, proxies=proxies)
def acquire_mailbox_oauth(oauth_creds):
    try:
        BaseProtocol.HTTP_ADAPTER_CLS = RelayHTTPAdapter
        cfg = Configuration(
            server='outlook.office365.com',
            retry_policy=FaultTolerance(max_wait=900),
            credentials=oauth_creds
        )
        return Account(
            'shared_mailbox@domain.it',
            config=cfg,
            autodiscover=True,
            access_type=DELEGATE
        )
    except Exception as exc:
        print(f"Account fetch failed: {exc}...")
        return None
oauth_creds ऑब्जेक्ट को ऊपर लिंक की गई exchangelib डॉक्यूमेंटेशन के अनुसार बनाना होगा।
यह क्यों महत्वपूर्ण है
Authentication का deprecation इंटीग्रेशन को सूक्ष्म तरीकों से तोड़ देता है। सेवा बाहर से वही दिख सकती है—वही hostname, वही mailbox—लेकिन auth पाइपलाइन में बदलाव पुराने स्क्रिप्ट्स को अनुपयोगी बना देता है। माइग्रेशन के बाद “wrong credentials” को टाइपिंग गलती के बजाय नीति बदलाव के संकेत के रूप में पहचानना, प्रॉक्सी, autodiscover और endpoint URLs पर होने वाली घंटों की ट्रबलशूटिंग बचा सकता है।
मुख्य बातें
यदि आपका exchangelib इंटीग्रेशन Outlook on Office 365 पर जाने के बाद काम करना बंद कर गया है और आप अब भी यूज़रनेम और पासवर्ड पास कर रहे हैं, तो समस्या वहीं है। आधिकारिक exchangelib निर्देशों का पालन करते हुए Basic auth की जगह OAuth अपनाएँ। अपना प्रॉक्सी हैंडलिंग और कॉन्फ़िगरेशन जस का तस रखें; केवल credentials तंत्र बदलें। इससे इंटीग्रेशन मौजूदा authentication मॉडल के अनुरूप हो जाएगा और deprecated फ्लो पर निर्भर हुए बिना shared mailbox तक पहुँच बहाल होगी।
यह लेख StackOverflow पर प्रश्न (लेखक: zacthebigkub) और Erik Cederstrand के उत्तर पर आधारित है।