mirror of
				https://github.com/paperless-ngx/paperless-ngx.git
				synced 2025-11-03 03:16:10 -06:00 
			
		
		
		
	Enhancement: check for mail destination directory, log post-consume errors (#7808)
--------- Co-authored-by: shamoon <4887959+shamoon@users.noreply.github.com>
This commit is contained in:
		
				
					committed by
					
						
						GitHub
					
				
			
			
				
	
			
			
			
						parent
						
							f8d79b012f
						
					
				
				
					commit
					b3487f1843
				
			@@ -28,6 +28,7 @@ from imap_tools import MailboxFolderSelectError
 | 
			
		||||
from imap_tools import MailBoxUnencrypted
 | 
			
		||||
from imap_tools import MailMessage
 | 
			
		||||
from imap_tools import MailMessageFlags
 | 
			
		||||
from imap_tools import errors
 | 
			
		||||
from imap_tools.mailbox import MailBoxTls
 | 
			
		||||
from imap_tools.query import LogicOperator
 | 
			
		||||
 | 
			
		||||
@@ -266,7 +267,14 @@ def apply_mail_action(
 | 
			
		||||
            M.folder.set(rule.folder)
 | 
			
		||||
 | 
			
		||||
            action = get_rule_action(rule, supports_gmail_labels)
 | 
			
		||||
            action.post_consume(M, message_uid, rule.action_parameter)
 | 
			
		||||
            try:
 | 
			
		||||
                action.post_consume(M, message_uid, rule.action_parameter)
 | 
			
		||||
            except errors.ImapToolsError:
 | 
			
		||||
                logger = logging.getLogger("paperless_mail")
 | 
			
		||||
                logger.exception(
 | 
			
		||||
                    "Error while processing mail action during post_consume",
 | 
			
		||||
                )
 | 
			
		||||
                raise
 | 
			
		||||
 | 
			
		||||
        ProcessedMail.objects.create(
 | 
			
		||||
            owner=rule.owner,
 | 
			
		||||
@@ -570,13 +578,17 @@ class MailAccountHandler(LoggingMixin):
 | 
			
		||||
        rule: MailRule,
 | 
			
		||||
        supports_gmail_labels: bool,
 | 
			
		||||
    ):
 | 
			
		||||
        self.log.debug(f"Rule {rule}: Selecting folder {rule.folder}")
 | 
			
		||||
 | 
			
		||||
        folders = [rule.folder]
 | 
			
		||||
        # In case of MOVE, make sure also the destination exists
 | 
			
		||||
        if rule.action == MailRule.MailAction.MOVE:
 | 
			
		||||
            folders.insert(0, rule.action_parameter)
 | 
			
		||||
        try:
 | 
			
		||||
            M.folder.set(rule.folder)
 | 
			
		||||
            for folder in folders:
 | 
			
		||||
                self.log.debug(f"Rule {rule}: Selecting folder {folder}")
 | 
			
		||||
                M.folder.set(folder)
 | 
			
		||||
        except MailboxFolderSelectError as err:
 | 
			
		||||
            self.log.error(
 | 
			
		||||
                f"Unable to access folder {rule.folder}, attempting folder listing",
 | 
			
		||||
                f"Unable to access folder {folder}, attempting folder listing",
 | 
			
		||||
            )
 | 
			
		||||
            try:
 | 
			
		||||
                for folder_info in M.folder.list():
 | 
			
		||||
@@ -588,7 +600,7 @@ class MailAccountHandler(LoggingMixin):
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
            raise MailError(
 | 
			
		||||
                f"Rule {rule}: Folder {rule.folder} "
 | 
			
		||||
                f"Rule {rule}: Folder {folder} "
 | 
			
		||||
                f"does not exist in account {rule.account}",
 | 
			
		||||
            ) from err
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -10,6 +10,7 @@ import pytest
 | 
			
		||||
from django.core.management import call_command
 | 
			
		||||
from django.db import DatabaseError
 | 
			
		||||
from django.test import TestCase
 | 
			
		||||
from django.utils import timezone
 | 
			
		||||
from imap_tools import NOT
 | 
			
		||||
from imap_tools import EmailAddress
 | 
			
		||||
from imap_tools import FolderInfo
 | 
			
		||||
@@ -17,6 +18,7 @@ from imap_tools import MailboxFolderSelectError
 | 
			
		||||
from imap_tools import MailboxLoginError
 | 
			
		||||
from imap_tools import MailMessage
 | 
			
		||||
from imap_tools import MailMessageFlags
 | 
			
		||||
from imap_tools import errors
 | 
			
		||||
 | 
			
		||||
from documents.models import Correspondent
 | 
			
		||||
from documents.tests.utils import DirectoriesMixin
 | 
			
		||||
@@ -28,6 +30,7 @@ from paperless_mail.mail import TagMailAction
 | 
			
		||||
from paperless_mail.mail import apply_mail_action
 | 
			
		||||
from paperless_mail.models import MailAccount
 | 
			
		||||
from paperless_mail.models import MailRule
 | 
			
		||||
from paperless_mail.models import ProcessedMail
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@dataclasses.dataclass
 | 
			
		||||
@@ -1424,6 +1427,95 @@ class TestMail(
 | 
			
		||||
        )  # still 2
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestPostConsumeAction(TestCase):
 | 
			
		||||
    def setUp(self):
 | 
			
		||||
        self.account = MailAccount.objects.create(
 | 
			
		||||
            name="test",
 | 
			
		||||
            imap_server="imap.test.com",
 | 
			
		||||
            imap_port=993,
 | 
			
		||||
            imap_security=MailAccount.ImapSecurity.SSL,
 | 
			
		||||
            username="testuser",
 | 
			
		||||
            password="password",
 | 
			
		||||
        )
 | 
			
		||||
        self.rule = MailRule.objects.create(
 | 
			
		||||
            name="testrule",
 | 
			
		||||
            account=self.account,
 | 
			
		||||
            action=MailRule.MailAction.MARK_READ,
 | 
			
		||||
            action_parameter="",
 | 
			
		||||
            folder="INBOX",
 | 
			
		||||
        )
 | 
			
		||||
        self.message_uid = "12345"
 | 
			
		||||
        self.message_subject = "Test Subject"
 | 
			
		||||
        self.message_date = timezone.make_aware(timezone.datetime(2023, 1, 1, 12, 0, 0))
 | 
			
		||||
 | 
			
		||||
    @mock.patch("paperless_mail.mail.get_mailbox")
 | 
			
		||||
    @mock.patch("paperless_mail.mail.mailbox_login")
 | 
			
		||||
    @mock.patch("paperless_mail.mail.get_rule_action")
 | 
			
		||||
    def test_post_consume_success(
 | 
			
		||||
        self,
 | 
			
		||||
        mock_get_rule_action,
 | 
			
		||||
        mock_mailbox_login,
 | 
			
		||||
        mock_get_mailbox,
 | 
			
		||||
    ):
 | 
			
		||||
        mock_mailbox = mock.MagicMock()
 | 
			
		||||
        mock_get_mailbox.return_value.__enter__.return_value = mock_mailbox
 | 
			
		||||
        mock_action = mock.MagicMock()
 | 
			
		||||
        mock_get_rule_action.return_value = mock_action
 | 
			
		||||
 | 
			
		||||
        apply_mail_action(
 | 
			
		||||
            result=[],
 | 
			
		||||
            rule_id=self.rule.pk,
 | 
			
		||||
            message_uid=self.message_uid,
 | 
			
		||||
            message_subject=self.message_subject,
 | 
			
		||||
            message_date=self.message_date,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        mock_mailbox_login.assert_called_once_with(mock_mailbox, self.account)
 | 
			
		||||
        mock_mailbox.folder.set.assert_called_once_with(self.rule.folder)
 | 
			
		||||
        mock_action.post_consume.assert_called_once_with(
 | 
			
		||||
            mock_mailbox,
 | 
			
		||||
            self.message_uid,
 | 
			
		||||
            self.rule.action_parameter,
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        processed_mail = ProcessedMail.objects.get(uid=self.message_uid)
 | 
			
		||||
        self.assertEqual(processed_mail.status, "SUCCESS")
 | 
			
		||||
 | 
			
		||||
    @mock.patch("paperless_mail.mail.get_mailbox")
 | 
			
		||||
    @mock.patch("paperless_mail.mail.mailbox_login")
 | 
			
		||||
    @mock.patch("paperless_mail.mail.get_rule_action")
 | 
			
		||||
    def test_post_consume_failure(
 | 
			
		||||
        self,
 | 
			
		||||
        mock_get_rule_action,
 | 
			
		||||
        mock_mailbox_login,
 | 
			
		||||
        mock_get_mailbox,
 | 
			
		||||
    ):
 | 
			
		||||
        mock_mailbox = mock.MagicMock()
 | 
			
		||||
        mock_get_mailbox.return_value.__enter__.return_value = mock_mailbox
 | 
			
		||||
        mock_action = mock.MagicMock()
 | 
			
		||||
        mock_get_rule_action.return_value = mock_action
 | 
			
		||||
        mock_action.post_consume.side_effect = errors.ImapToolsError("Test Exception")
 | 
			
		||||
 | 
			
		||||
        with (
 | 
			
		||||
            self.assertRaises(errors.ImapToolsError),
 | 
			
		||||
            self.assertLogs("paperless.mail", level="ERROR") as cm,
 | 
			
		||||
        ):
 | 
			
		||||
            apply_mail_action(
 | 
			
		||||
                result=[],
 | 
			
		||||
                rule_id=self.rule.pk,
 | 
			
		||||
                message_uid=self.message_uid,
 | 
			
		||||
                message_subject=self.message_subject,
 | 
			
		||||
                message_date=self.message_date,
 | 
			
		||||
            )
 | 
			
		||||
            error_str = cm.output[0]
 | 
			
		||||
            expected_str = "Error while processing mail action during post_consume"
 | 
			
		||||
            self.assertIn(expected_str, error_str)
 | 
			
		||||
 | 
			
		||||
        processed_mail = ProcessedMail.objects.get(uid=self.message_uid)
 | 
			
		||||
        self.assertEqual(processed_mail.status, "FAILED")
 | 
			
		||||
        self.assertIn("Test Exception", processed_mail.error)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class TestManagementCommand(TestCase):
 | 
			
		||||
    @mock.patch(
 | 
			
		||||
        "paperless_mail.management.commands.mail_fetcher.tasks.process_mail_accounts",
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user