ecederstrand / exchangelib

Python client for Microsoft Exchange Web Services (EWS)
BSD 2-Clause "Simplified" License
1.17k stars 249 forks source link

Accessing shared calendars does no longer work on 5.4.2 but it does work on 5.2.0 #1325

Closed reziandoni closed 1 month ago

reziandoni commented 3 months ago

The sample code below from the documentation does not work any longer.

shared_calendar = SingleFolderQuerySet(
    account=johns_account,
    folder=DistinguishedFolderId(
        id=Calendar.DISTINGUISHED_FOLDER_ID,
        mailbox=Mailbox(email_address="mary@example.com"),
    ),
).resolve()
ValueError: Unsupported folder class: DistinguishedFolderId(id='calendar', mailbox=Mailbox(name=None, email_address='aaa@ccc.com', routing_type='SMTP', mailbox_type='Mailbox', item_id=None))
larryprice commented 3 months ago

We are also running into this issue after upgrading. Not much additional to add to the above, but our call looks like:

shared_calendar = folders.SingleFolderQuerySet(
    account=shared_mailbox_account, # <exchangelib.account.Account object>
    folder=DistinguishedFolderId(
        id='calendar',
        changekey=None,
        mailbox=Mailbox(
            name=None,
            email_address='test@example.com',
            routing_type='SMTP',
            mailbox_type='Mailbox',
            item_id=None
        )
    ),
).resolve()

which leads to the error:

Unsupported folder class: DistinguishedFolderId(id='calendar', mailbox=Mailbox(name=None, email_address='test@example.com', routing_type='SMTP', mailbox_type='Mailbox', item_id=None))
ecederstrand commented 3 months ago

Thanks for the report!

The arguments for SingleFolderQuerySet were restricted a bit, so you now need to supply a full Folder object:

from exchangelib.folders import Calendar, Folder, SingleFolderQuerySet
from exchangelib.properties import DistinguishedFolderId, Mailbox

shared_calendar = SingleFolderQuerySet(
    account=johns_account,
    folder=Folder(
        root=johns_account.root,
        _distinguished_id=DistinguishedFolderId(
            id=Calendar.DISTINGUISHED_FOLDER_ID,
            mailbox=Mailbox(email_address="mary@example.com"),
        ),
    ),
).resolve()

Docs have been updated.

reziandoni commented 3 months ago

After the change I do not get an error any more. It sends the email and calendar item to people in required_attendees, but does not save a copy on the shared_calendar. So it is still an issue. Seems like shared_calendar points to John's calendar.

ecederstrand commented 2 months ago

There's nothing in the code you posted that sends email, so I'm not sure what you're talking about.

If you want to create items in the shared calendar, then AFAIK you need to connect to the account of the shared calendar and create items from there. The above code is only about reading items in a shared calendar.

reziandoni commented 2 months ago

Below is my code:

  1. Mark get's an email for the calendar item
  2. the item does not end in teamcal's account which is the teams shared calendar.
  3. This works if shared_calendar is created with the previous example code on version 5.2.0

johns_account = Account('john@abc.com', autodiscover=True,
            credentials=credentials ,access_type=DELEGATE)

shared_calendar = SingleFolderQuerySet(
    account=johns_account,
    folder=Folder(
        root=johns_account.root,
        _distinguished_id=DistinguishedFolderId(
            id=Calendar.DISTINGUISHED_FOLDER_ID,
            mailbox=Mailbox(email_address="teamcal@abc.com"),
        ),
    ),
).resolve()

item = CalendarItem(
        account=johns_account,
        folder=shared_calendar,
        required_attendees=["mark@abc.com"],
        legacy_free_busy_status = 'Free',
        reminder_is_set = False,
        is_response_requested = False,
        allow_new_time_proposal = False,
)
item.save(send_meeting_invitations=SEND_TO_ALL_AND_SAVE_COPY)
ecederstrand commented 2 months ago

Which account does the account in account=a point to? It's not defined anywhere, AFAICS.

reziandoni commented 2 months ago

John's account - updated my code.

evelinagkougklia commented 2 months ago

I third this - in my scenario, account1 has read permissions to account2's inbox. In version 5.2.0, this code would print the subject of the latest email in account2's inbox. Post-5.2.0 (and even with the new code as described in https://github.com/ecederstrand/exchangelib/issues/1325#issuecomment-2255771795) account1's latest email subject is printed instead.

If there is a different way to read from a folder of another account's mailbox (given the proper permissions are in place), let me know.

from exchangelib import Account, Configuration, OAuth2Credentials, Identity, OAUTH2, FaultTolerance
from exchangelib.folders import Inbox, SingleFolderQuerySet
from exchangelib.properties import DistinguishedFolderId, Mailbox

credentials = OAuth2Credentials(
             client_id="xxx",
             client_secret="xxx",
             tenant_id="xxx",
             identity=Identity(primary_smtp_address="account1@abc.com")
         )
config = Configuration(server="outlook.office365.com", credentials=credentials, auth_type=OAUTH2,
                                retry_policy=FaultTolerance(max_wait=3600))
account = Account("account1@abc.com", config=config, autodiscover=False)

shared_inbox = SingleFolderQuerySet(
    account=account,
    folder=DistinguishedFolderId(
        id=Inbox.DISTINGUISHED_FOLDER_ID,
        mailbox=Mailbox(email_address="account2@abc.com"),
    ),
).resolve()

print(shared_inbox.all()[0].subject)
ecederstrand commented 2 months ago

Just to be clear: Which version of exchangelib is this? Does it also not work on 5.4.2?

evelinagkougklia commented 2 months ago

Version 5.2.0 -> displays account2's latest email subject (which is what I want) Version 5.4.2 -> displays account1's latest email subject, ignoring the Maibox parameter

For version 5.4.2 to work I define shared_inbox as:

shared_inbox = SingleFolderQuerySet(
    account=account,
    folder=Folder(root=account.root, _distinguished_id=DistinguishedFolderId(
        id=Inbox.DISTINGUISHED_FOLDER_ID,
        mailbox=Mailbox(email_address="account2@abc.com"),
    )),
).resolve()
ecederstrand commented 2 months ago

Unfortunately, I don't have a test account where I can test shared mailboxes. Your best bet is to enable debug logging and compare the requests in a working and non-working version of exchangelib to see what the two versions do differently.

ecederstrand commented 1 month ago

@evelinagkougklia I found an account where I can tests this, and committed a fix that should work for you as well.