ikvk / imap_tools

Work with email by IMAP
Apache License 2.0
705 stars 80 forks source link

Imposiblle to show all folders or set path for missing folders manually #87

Closed js-compilatrum closed 3 years ago

js-compilatrum commented 3 years ago

I stuck with very simple code, something like that:

with MailBox('imap.mail.com').login('test@mail.com', 'password') as mailbox:
    # LIST
    for folder_info in mailbox.folder.list('INBOX'):
        print(folder_info) 

On Windows in one folder I have UnicodeError, but it is not main problem. I haqve on account nested folders structures like:

Work / Company / Documents / Reports

I can't see using Python show all available folder. I see all of them in Thunderbird, eM email client without problems. Login using webmail from mail provider - all them exists and are not empty. When I tried:

mailbox.folder.set('_Work/ Company/Documents/Reports_')

I got error that folder not exists. When I manually set unread inside folder which is not shown and try read unread messages - messages with that folder are missed. It's looks like some folders are outside INBOX and I can't grap data from them.

I am not sure, but it maybe connected with IPF.Note and IPF.Imap (I guessing), but I have not idea how set this inside imap-tools

ikvk commented 3 years ago

Hello.

  1. Show output of your code example
  2. "some folders are outside INBOX" - I have met with it, always it was not a problem
  3. Show me trace of UnicodeError
js-compilatrum commented 3 years ago
  1. Show output of your code example INBOX/folder INBOX/folder2

and no MISSING_FOLDER

  1. "some folders are outside INBOX" - I have met with it, always it was not a problem
    mailbox.folder.set('MISSING_FOLDER')
  File "C:\project\lib\site-packages\imap_tools\folder.py", line 38, in set
    check_command_status(result, MailboxFolderSelectError)
  File "D:\skrypty\py\sendmailer\lib\site-packages\imap_tools\utils.py", line 54, in check_command_status
    raise exception(command_result=command_result, expected=expected)
imap_tools.errors.MailboxFolderSelectError: Response status "OK" expected, but "NO" received. Data: [b'Folder does not exist.']

before you post reply I manually add all folders to INBOX and this resolve issue. I will try reproduce it on another account. Windows 10, Python 3.9.1.

  1. Show me trace of UnicodeError

Problem was with saving using Pathlib. Using open and encoding="utf-8" resolve issue.

ikvk commented 3 years ago

I think you trying to do:

    mailbox.folder.list('INBOX')

Try this instead:

    for folder in mailbox.folder.list(''):  # or .list()
        print(folder)
js-compilatrum commented 3 years ago

It's works. I can see all folders. I only at the end have only problem with grap unread form all folders. I have to use your aproach to scan folder and then pass it to set:

def group_unread(mailbox: MailBox, use_folder: str = 'INBOX') -> Generator:
    fast_and_high_memory_consumption = False
    mailbox.folder.set(use_folder)
    return mailbox.fetch(AND(seen=False), bulk=fast_and_high_memory_consumption)

available_folders = [folder['name'] for folder in mailbox.folder.list('')]
for current_folder in available_folders:
    unread_emails = group_unread(mailbox, use_folder=current_folder)

Is better way for it? If I don't do this way few folders are missing, but when I use this way - all works fine.

ikvk commented 3 years ago
# STATUS
folder_status = mailbox.folder.status('some_folder')
print(folder_status)  # {'MESSAGES': 41, 'RECENT': 0, 'UIDNEXT': 11996, 'UIDVALIDITY': 1, 'UNSEEN': 5}

# or .status(MailBoxFolderStatusOptions.UNSEEN)
ikvk commented 3 years ago

For clarity: you can check UNSEEN msg count in each folder before grap from it.

js-compilatrum commented 3 years ago

I have tested. When I check result from my script I see few times internal IMAP server error. Using folder.status() or .status(MailBoxFolderStatusOptions.UNSEEN) as you suggest don't make extra overload to server?

ikvk commented 3 years ago

I have checked - no overload problem for me. You decide how to load the server

js-compilatrum commented 3 years ago

I testing on email client how email was processed. Some part is split on group and read only processed. I do it: mailbox.seen(email.uid, False) # Mark as UNREAD!

Is it correct way? I have some email not mark or marked if it should be unread. I don't know that its delay on email client or wrong command with mailbox.

ikvk commented 3 years ago
  1. mailbox.seen(email.uid, False) is correct but if you have many uids for mark as seen, it will be more effective to pass all uids at time: mailbox.seen(uid_list, False)
  2. Action methods can works with mailbox.fetch() generator directly mailbox.seen(mailbox.fetch(...), False)
  3. When works with seen flags, read about mailbox.fetch mark_seen arg.
js-compilatrum commented 3 years ago

All works fine. Thank you for your help.