diff --git a/docs/usage_overview.rst b/docs/usage_overview.rst index e6bb8f31e..ea1080177 100644 --- a/docs/usage_overview.rst +++ b/docs/usage_overview.rst @@ -182,9 +182,10 @@ These are as follows: When defining a mail rule with a folder, you may need to try different characters to define how the sub-folders are separated. Common values include ".", "/" or "|", but - this varies by the mail server. Unfortunately, this isn't a value we can determine - automatically. Either check the documentation for your mail server, or check for - errors in the logs and try different folder separator values. + this varies by the mail server. Check the documentation for your mail server. In the + event of an error fetching mail from a certain folder, check the Paperless logs. When + a folder is not located, Paperless will attempt to list all folders found in the account + to the Paperless logs. .. note:: diff --git a/src/paperless_mail/mail.py b/src/paperless_mail/mail.py index 5df29e2b0..8a9c1106c 100644 --- a/src/paperless_mail/mail.py +++ b/src/paperless_mail/mail.py @@ -190,6 +190,21 @@ class MailAccountHandler(LoggingMixin): try: M.folder.set(rule.folder) except MailboxFolderSelectError: + + self.log( + "error", + f"Unable to access folder {rule.folder}, attempting folder listing", + ) + try: + for folder_info in M.folder.list(): + self.log("info", f"Located folder: {folder_info.name}") + except Exception as e: + self.log( + "error", + "Exception during folder listing, unable to provide list folders: " + + str(e), + ) + raise MailError( f"Rule {rule}: Folder {rule.folder} " f"does not exist in account {rule.account}", diff --git a/src/paperless_mail/tests/test_mail.py b/src/paperless_mail/tests/test_mail.py index 9335bcd75..a638fc894 100644 --- a/src/paperless_mail/tests/test_mail.py +++ b/src/paperless_mail/tests/test_mail.py @@ -15,6 +15,7 @@ from django.test import TestCase from documents.models import Correspondent from documents.tests.utils import DirectoriesMixin from imap_tools import EmailAddress +from imap_tools import FolderInfo from imap_tools import MailboxFolderSelectError from imap_tools import MailMessage from imap_tools import MailMessageFlags @@ -53,13 +54,12 @@ class BogusMailBox(ContextManager): def __init__(self): self.messages: List[MailMessage] = [] self.messages_spam: List[MailMessage] = [] + self.folder = BogusFolderManager() def login(self, username, password): if not (username == "admin" and password == "secret"): raise Exception() - folder = BogusFolderManager() - def fetch(self, criteria, mark_seen, charset=""): msg = self.messages @@ -621,6 +621,72 @@ class TestMail(DirectoriesMixin, TestCase): self.assertEqual(len(self.bogus_mailbox.messages), 2) self.assertEqual(len(self.bogus_mailbox.messages_spam), 1) + def test_error_folder_set(self): + """ + GIVEN: + - Mail rule with non-existent folder + THEN: + - Should call list to output all folders in the account + - Should not process any messages + """ + account = MailAccount.objects.create( + name="test2", + imap_server="", + username="admin", + password="secret", + ) + _ = MailRule.objects.create( + name="testrule", + account=account, + action=MailRule.AttachmentAction.MOVE, + action_parameter="spam", + filter_subject="Claim", + order=1, + folder="uuuhhhh", # Invalid folder name + ) + + self.bogus_mailbox.folder.list = mock.Mock( + return_value=[FolderInfo("SomeFoldername", "|", ())], + ) + + self.mail_account_handler.handle_mail_account(account) + + self.bogus_mailbox.folder.list.assert_called_once() + self.assertEqual(self.async_task.call_count, 0) + + def test_error_folder_set_error_listing(self): + """ + GIVEN: + - Mail rule with non-existent folder + - Mail account folder listing raises exception + THEN: + - Should not process any messages + """ + account = MailAccount.objects.create( + name="test2", + imap_server="", + username="admin", + password="secret", + ) + _ = MailRule.objects.create( + name="testrule", + account=account, + action=MailRule.AttachmentAction.MOVE, + action_parameter="spam", + filter_subject="Claim", + order=1, + folder="uuuhhhh", # Invalid folder name + ) + + self.bogus_mailbox.folder.list = mock.Mock( + side_effect=MailboxFolderSelectError(None, "uhm"), + ) + + self.mail_account_handler.handle_mail_account(account) + + self.bogus_mailbox.folder.list.assert_called_once() + self.assertEqual(self.async_task.call_count, 0) + @mock.patch("paperless_mail.mail.MailAccountHandler.get_correspondent") def test_error_skip_mail(self, m): def get_correspondent_fake(message, rule):