{"id":3481,"library":"exchangelib","title":"Exchangelib","description":"Exchangelib is a Python client for Microsoft Exchange Web Services (EWS), providing programmatic access to Exchange mailboxes, calendars, contacts, and tasks. It supports autodiscovery, various authentication methods (NTLM, OAuth), and aims to be a comprehensive, easy-to-use interface for EWS. The current version is 5.6.0, with a release cadence that responds to bug fixes, feature requests, and EWS changes.","status":"active","version":"5.6.0","language":"python","source_language":"en","source_url":"https://github.com/ecederstrand/exchangelib.git","tags":["exchange","ews","microsoft","email","calendar","outlook"],"install":[{"cmd":"pip install exchangelib","lang":"bash","label":"Install stable version"}],"dependencies":[{"reason":"HTTP client for making EWS requests.","package":"requests"},{"reason":"Required for NTLM authentication with Exchange servers.","package":"requests-ntlm"},{"reason":"Efficient XML parsing and serialization for EWS SOAP messages.","package":"lxml"},{"reason":"Used for DNS lookups during autodiscovery of EWS endpoints.","package":"dnspython"},{"reason":"Timezone handling, especially for converting between local and EWS timezones.","package":"pytz"},{"reason":"Determines the local timezone for accurate timestamp conversions.","package":"tzlocal"},{"reason":"Enhanced security for XML parsing to prevent known vulnerabilities.","package":"defusedxml"}],"imports":[{"symbol":"Account","correct":"from exchangelib import Account"},{"symbol":"Credentials","correct":"from exchangelib import Credentials"},{"symbol":"Configuration","correct":"from exchangelib import Configuration"},{"symbol":"DELEGATE","correct":"from exchangelib import DELEGATE"},{"symbol":"EWSTimeZone","correct":"from exchangelib import EWSTimeZone"},{"symbol":"IMPERSONATION","correct":"from exchangelib import IMPERSONATION"},{"symbol":"Message","correct":"from exchangelib import Message"},{"symbol":"Mailbox","correct":"from exchangelib import Mailbox"},{"symbol":"Folder","correct":"from exchangelib import Folder"}],"quickstart":{"code":"import os\nfrom exchangelib import Account, Credentials, Configuration, DELEGATE\n\n# Get credentials from environment variables for security\nemail = os.environ.get('EXCHANGE_EMAIL', 'your_email@example.com')\npassword = os.environ.get('EXCHANGE_PASSWORD', 'your_password')\n\nif not email or not password or email == 'your_email@example.com':\n    print(\"Please set EXCHANGE_EMAIL and EXCHANGE_PASSWORD environment variables.\")\n    print(\"Or replace placeholders directly in the script (not recommended for production).\")\n    exit(1)\n\ncredentials = Credentials(email, password)\n\ntry:\n    # Autodiscover the EWS URL and connect\n    account = Account(\n        primary_smtp_address=email,\n        credentials=credentials,\n        autodiscover=True,\n        access_type=DELEGATE # Or IMPERSONATION, ARCHIVE, etc.\n    )\n    print(f\"Successfully connected to Exchange for {account.primary_smtp_address}\")\n    print(f\"EWS URL: {account.protocol.ews_url}\")\n\n    # Example: List subjects of 5 most recent unread items in Inbox\n    inbox = account.inbox\n    print(f\"\\nListing up to 5 unread items in Inbox for {email}:\")\n    for item in inbox.filter(is_read=False).order_by('-datetime_received')[:5]:\n        print(f\"- Subject: {item.subject}, From: {item.sender.email_address}, Received: {item.datetime_received}\")\n\nexcept Exception as e:\n    print(f\"Could not connect or perform operation: {e}\")\n    print(\"Common issues: Incorrect credentials, firewall blocking EWS, autodiscovery failure.\")\n    print(\"If autodiscovery fails, try setting `autodiscover=False` and `ews_url` manually in Configuration.\")","lang":"python","description":"This quickstart demonstrates how to connect to an Exchange mailbox using email/password credentials and autodiscovery. It then fetches and prints the subjects of the 5 most recent unread items in the inbox. It uses environment variables for security to avoid hardcoding sensitive information."},"warnings":[{"fix":"Migrate authentication logic to use `exchangelib.Credentials` directly. For custom protocols, ensure `auth_type` and other parameters are correctly passed to `Protocol`.","message":"Version 5.0.0 removed `BasicAuth` as a standalone class. Authentication details are now handled directly by the `Credentials` class or implicitly by the `Protocol` class. Custom protocol definitions must be updated.","severity":"breaking","affected_versions":">=5.0.0"},{"fix":"Update any code that references `protocol.ews_url` (for autodiscover URL) to `protocol.autodiscover_url` and `protocol.service_endpoint` (for service endpoint URL) to `protocol.ews_url`.","message":"In version 5.0.0, the `protocol.ews_url` attribute was renamed to `protocol.autodiscover_url` for clarity. The attribute that points to the actual EWS service endpoint is now `protocol.ews_url` (previously `protocol.service_endpoint`). This affects direct manipulation or inspection of `Protocol` objects.","severity":"breaking","affected_versions":">=5.0.0"},{"fix":"Always use `exchangelib.EWSTimeZone` when creating or modifying datetime objects that interact with Exchange. Ensure your local system's timezone is correctly configured if relying on `tzlocal`.","message":"Time zone handling can be complex with EWS, especially when dealing with recurring events or ensuring consistent timestamps across systems. EWS often expects UTC or specific EWS timezones.","severity":"gotcha","affected_versions":"All"},{"fix":"Use iterators or specify a maximum number of items when querying large folders (e.g., `folder.all().order_by('-datetime_received')[:100]`). For complex queries, use `folder.filter().iterator()`.","message":"Fetching all items from large folders (`folder.all()`) can be very slow and consume excessive memory. EWS APIs are often paginated.","severity":"gotcha","affected_versions":"All"},{"fix":"If autodiscovery fails, explicitly provide the `ews_url` when creating a `Configuration` object, then pass that configuration to the `Account`. Example: `config = Configuration(server='outlook.office365.com', credentials=credentials, ews_url='https://outlook.office365.com/EWS/Exchange.asmx')`.","message":"Autodiscovery might fail in complex network environments or specific Exchange configurations. This prevents `Account` from establishing a connection.","severity":"gotcha","affected_versions":"All"}],"env_vars":null,"search_vec":"'5.6.0':48 'access':15 'aim':32 'authent':27 'autodiscoveri':25 'bug':56 'cadenc':52 'calendar':19,67 'chang':62 'client':6 'comprehens':36 'contact':20 'current':45 'easi':38 'easy-to-us':37 'email':66 'ew':12,43,61,64 'exchang':9,17,63 'exchangelib':1,2 'featur':58 'fix':57 'interfac':41 'mailbox':18 'method':28 'microsoft':8,65 'ntlm':29 'oauth':30 'outlook':68 'programmat':14 'provid':13 'python':5 'releas':51 'request':59 'respond':54 'servic':11 'support':24 'task':22 'use':40 'various':26 'version':46 'web':10","created_at":"2026-04-11T17:31:28.156525+00:00","updated_at":"2026-04-16T14:52:58.036520+00:00","problems":[{"fix":"Manually specify the EWS server URL and disable autodiscover. You can often find the EWS URL in Outlook's connection settings or through your IT administrator.\n```python\nfrom exchangelib import Credentials, Account, Configuration\n\ncreds = Credentials(username='your_username@your_domain.com', password='your_password')\nconfig = Configuration(server='your.exchange.server.com', credentials=creds) # e.g., 'outlook.office365.com' or a specific EWS URL\naccount = Account(primary_smtp_address='your_username@your_domain.com', config=config, autodiscover=False)\n```","cause":"This error occurs when `exchangelib` cannot automatically determine the correct Exchange Web Services (EWS) endpoint for the given email address, often due to complex network configurations, non-standard EWS setups, or stricter server-side autodiscover policies.","error":"exchangelib.errors.AutoDiscoverFailed: All steps in the autodiscover protocol failed"},{"fix":"First, double-check your username and password, including the format (e.g., `DOMAIN\\username` vs. `user@domain.com`). If using Office 365, consider switching to OAuth2 authentication as Basic Auth is largely deprecated.\n```python\nfrom exchangelib import Credentials, Account, OAUTH2, OAuth2Credentials\n\n# For NTLM/Basic Auth (if supported by your server)\n# creds = Credentials(username='DOMAIN\\username', password='your_password')\n\n# For Office 365 / OAuth2\n# Requires prior Azure AD app registration to get client_id, client_secret, and tenant_id\nocreds = OAuth2Credentials(\n    client_id='your_client_id',\n    client_secret='your_client_secret',\n    tenant_id='your_tenant_id', # or 'organizations' or 'common'\n    access_token='your_initial_access_token' # This needs to be refreshed externally\n)\n\naccount = Account(primary_smtp_address='user@example.com', credentials=ocreds, autodiscover=True, access_type=OAUTH2)\n```","cause":"This error indicates that the provided username or password is incorrect, the authentication type used by `exchangelib` (e.g., NTLM, Basic, OAuth) does not match the server's requirements, or the account lacks the necessary permissions to access EWS. For Office 365, this often means Basic Authentication has been disabled, requiring a switch to OAuth2.","error":"exchangelib.errors.UnauthorizedError: Invalid credentials for https://[domain]/EWS/Exchange.asmx"},{"fix":"To fix this, you can either explicitly trust the certificate by providing its path to `exchangelib` or, as a last resort for testing (not recommended for production), disable SSL verification.\n```python\nfrom exchangelib import DELEGATE, Account, Credentials, Configuration\nfrom exchangelib.protocol import BaseProtocol, NoVerifyHTTPAdapter\nimport ssl\n\n# Option 1: Provide path to CA bundle (recommended)\n# BaseProtocol.HTTP_ADAPTER_CLS.ssl_context = ssl.create_default_context(cafile='/path/to/your/ca_bundle.pem')\n\n# Option 2: Disable SSL verification (use with caution, for testing only)\nBaseProtocol.HTTP_ADAPTER_CLS = NoVerifyHTTPAdapter\n\ncreds = Credentials(username='user@example.com', password='your_password')\naccount = Account(primary_smtp_address='user@example.com', credentials=creds, autodiscover=True)\n```","cause":"This SSL error occurs when the Python environment cannot verify the SSL certificate presented by the Exchange server. This is common in corporate environments with custom root Certificate Authorities or self-signed certificates.","error":"requests.exceptions.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed"},{"fix":"Always use `exchangelib.EWSTimeZone` and `exchangelib.EWSDateTime` when working with dates and times that will be sent to or received from Exchange.\n```python\nfrom exchangelib import EWSDateTime, EWSTimeZone\nfrom datetime import datetime\n\n# Correct way to create a timezone-aware EWSDateTime\ntz = EWSTimeZone.localzone() # or EWSTimeZone.timezone('Europe/Copenhagen')\nnow = EWSDateTime.now(tz=tz)\n\n# If you have a standard datetime object and need to convert it:\nstandard_dt = datetime.now(tz=pytz.utc) # Example with pytz\news_tz = EWSTimeZone.from_timezone(standard_dt.tzinfo)\nnews_dt = EWSDateTime(standard_dt.year, standard_dt.month, standard_dt.day, \n                      standard_dt.hour, standard_dt.minute, standard_dt.second, \n                      tzinfo=news_tz)\n```","cause":"`exchangelib` requires its specific `EWSTimeZone` objects for timezone-aware datetimes when interacting with EWS, rather than standard Python `datetime.tzinfo` or `pytz` timezone objects. This error typically arises when mixing different timezone object types.","error":"exchangelib.errors.InvalidTypeError: 'tzinfo' <UTC> must be of type <class 'exchangelib.ewsdatetime.EWSTimeZone'>"},{"fix":"Ensure `exchangelib` is installed in your environment using pip. If using a virtual environment, activate it first. If deploying with PyInstaller, ensure PyInstaller is correctly configured to include `exchangelib` as a hidden import if necessary.\n```bash\npip install exchangelib\n\n# If using PyInstaller and encountering issues, you might need:\npyinstaller --hidden-import exchangelib your_script.py\n```","cause":"This fundamental Python error occurs when the `exchangelib` package is not installed in the Python environment where the script is being run, or if the environment path is misconfigured. It's also frequently encountered when deploying applications with tools like PyInstaller that might not correctly bundle all dependencies.","error":"ModuleNotFoundError: No module named 'exchangelib'"}],"ecosystem":"pypi","meta_description":null,"install_score":null,"quickstart_score":null,"quickstart_tag":null,"pypi_latest":"5.6.0","cli_name":"","cli_version":null,"type":"library","homepage":"https://ecederstrand.github.io/exchangelib/","github":"https://github.com/ecederstrand/exchangelib","docs":"https://ecederstrand.github.io/exchangelib/","changelog":"https://github.com/ecederstrand/exchangelib/blob/master/CHANGELOG.md","pypi":"https://pypi.org/project/exchangelib/","npm":null,"openapi_spec":null,"status_page":null,"smithery":null,"categories":["communication","aws","http-networking","auth-security","web-framework"],"base_url":null,"auth_type":null,"provenance":{"verified_status":"passing","verified_at":"2026-06-28","last_verified":"2026-08-29","next_check":"2026-07-28","install_tag":null}}