Repository: paperless-ngx/paperless-ngx

Issue:
[BUG] Mail Import broken
**Describe the bug**
Found multiple bugs when trying to consume Mails via IMAP:

When creating an EMail Rule which should work at an IMAP (Sub)Folder, the GUI sais subfolders should be seperated by "." . This is wrong - in my case - as SubFolders are seperated by "/". Listing my IMAP Folders with a little Python Script using imap_tools gives this for example:

`FolderInfo(name='INBOX/2DMS', delim='/', flags=('\\HasChildren',))`
(note the "/" as delimiter)

When entering this Folder seperated by "." as the GUI sais:

![image](https://user-images.githubusercontent.com/3826246/159741159-b920929d-58d2-48b1-a144-79106b47c8de.png)

No Mail is imported by the Job "Check all e-mail accounts" (process_mail_accounts) and this can be found in the logs:

```
16:50:41 [Q] INFO Enqueued 1
16:50:41 [Q] INFO Process-1 created a task from schedule [Check all e-mail accounts]
16:50:41 [Q] INFO Process-1:1582 processing [winter-oregon-sodium-asparagus]
[2022-03-23 16:50:41,611] [ERROR] [paperless_mail] Rule ***.GetMails: Error while processing rule: Rule ***.GetMails: Folder INBOX.2DMS does not exist in account ***
Traceback (most recent call last):
  File "/usr/src/paperless/src/paperless_mail/mail.py", line 192, in handle_mail_rule
    M.folder.set(rule.folder)
  File "/usr/local/lib/python3.9/site-packages/imap_tools/folder.py", line 44, in set
    check_command_status(result, MailboxFolderSelectError)
  File "/usr/local/lib/python3.9/site-packages/imap_tools/utils.py", line 45, 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'SELECT error getting mails in folder']

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/usr/src/paperless/src/paperless_mail/mail.py", line 177, in handle_mail_account
    total_processed_files += self.handle_mail_rule(M, rule)
  File "/usr/src/paperless/src/paperless_mail/mail.py", line 194, in handle_mail_rule
    raise MailError(
paperless_mail.mail.MailError: Rule ***.GetMails: Folder INBOX.2DMS does not exist in account ***
```
"Folder INBOX.2DMS does not exist in account" is quit correct as the Folder is "INBOX/2DMS".

Sidenote:
In the GUI the obviously failed job can be found under "Successful tasks", not under "Failed Tasks" which for me is a bug, either:
![image](https://user-images.githubusercontent.com/3826246/159742553-76836da9-e45c-46e1-9bb9-0003f675c511.png)


When correcting the Folder delimiter to "/" for matching the SubFolder Name:

![image](https://user-images.githubusercontent.com/3826246/159743047-324ffe96-b3c8-48b7-8871-801c954d6445.png)

another error is in the logs:

```
17:02:43 [Q] INFO Enqueued 1
17:02:43 [Q] INFO Process-1 created a task from schedule [Check all e-mail accounts]
17:02:43 [Q] INFO Process-1:1584 processing [monkey-blue-maine-network]
[2022-03-23 17:02:45,251] [ERROR] [paperless_mail] Rule ***.GetMails: Error while processing mail 668684: argument of type 'EmailAddress' is not iterable
Traceback (most recent call last):
  File "/usr/src/paperless/src/paperless_mail/mail.py", line 222, in handle_mail_rule
    processed_files = self.handle_message(message, rule)
  File "/usr/src/paperless/src/paperless_mail/mail.py", line 266, in handle_message
    correspondent = self.get_correspondent(message, rule)
  File "/usr/src/paperless/src/paperless_mail/mail.py", line 138, in get_correspondent
    and "name" in message.from_values
TypeError: argument of type 'EmailAddress' is not iterable
[2022-03-23 17:02:45,309] [ERROR] [paperless_mail] Rule ***.GetMails: Error while processing mail 670533: argument of type 'EmailAddress' is not iterable
Traceback (most recent call last):
  File "/usr/src/paperless/src/paperless_mail/mail.py", line 222, in handle_mail_rule
    processed_files = self.handle_message(message, rule)
  File "/usr/src/paperless/src/paperless_mail/mail.py", line 266, in handle_message
    correspondent = self.get_correspondent(message, rule)
  File "/usr/src/paperless/src/paperless_mail/mail.py", line 138, in get_correspondent
    and "name" in message.from_values
TypeError: argument of type 'EmailAddress' is not iterable
```

So the folder is found now but sth. is wrong when working on the contained mails.

And as described in the sidenote above, this job is found under "Successful tasks" too:
![image](https://user-images.githubusercontent.com/3826246/159743815-01ff90ed-98ba-443a-8258-fb03f9a52575.png)


**Relevant information**
 - Host OS of the machine running paperless: Debian
 - Browser Chrome
 - Version 1.6.0
 - Installation method: docker


Discussion:
> TypeError: argument of type 'EmailAddress' is not iterable

This error was fixed in #393

However, I do agree the documentation for email consumption and settings could use further details.  In particular, I'm not sure the folder delimiter of `.` is always valid.  As in your case, it appears a `/` is used.  This seems to vary by the server.
So Im guessing we dont have an easy way to know ahead of time when the user is setting up rules (I know he said 'imap_tools' reports the delimiter but we're not going to ping the server a priori) but perhaps changing the instructions under the field as well as reporting a more helpful error?
> > TypeError: argument of type 'EmailAddress' is not iterable
> 
> This error was fixed in #393
> 
> However, I do agree the documentation for email consumption and settings could use further details. In particular, I'm not sure the folder delimiter of `.` is always valid. As in your case, it appears a `/` is used. This seems to vary by the server.

So when will the fix be merged to main and so enters a new version (1.6.1. for example?) As this bug competely breaks mail import functionality.....
> So Im guessing we dont have an easy way to know ahead of time when the user is setting up rules (I know he said 'imap_tools' reports the delimiter but we're not going to ping the server a priori) but perhaps changing the instructions under the field as well as reporting a more helpful error?

Changing the instructions has to be done, IMHO, as the current one could be misleading.
Could it be worth thinking about some sort of Select Box / Drop Down, which let the user select the folder instead of a plain text field? This would 1. be more user friendly and 2. eliminates the need of knowing the delimiter ahead of time? Could imagine, not technically interested users even don't know which delimiter will be the correct one at all...

Concerning the error handling:
It would absolutly make sense, that the errored task should not appear under "Successful Tasks" but in "Failed Tasks" with a - more or less - speaking error message.
For tracking down, why mails aren't imported, I had to use "docker logs....", which shouldn't be the standard in case of failing jobs.
> So when will the fix be merged to main and so enters a new version (1.6.1. for example?) As this bug competely breaks mail import functionality.....

As soon as we release it. Please remember we are all volunteers, everyone who is fixing bugs has all of the other things in their life going on. We havent discussed timeline of a next release, there are a bunch of things still in progress but are hopefully approaching one soon.

Resolving patch:
diff --git a/src/paperless_mail/mail.py b/src/paperless_mail/mail.py
--- a/src/paperless_mail/mail.py
+++ b/src/paperless_mail/mail.py
@@ -61,13 +61,13 @@ def post_consume(self, M, message_uids, parameter):
 
 
 def get_rule_action(rule):
-    if rule.action == MailRule.ACTION_FLAG:
+    if rule.action == MailRule.AttachmentAction.FLAG:
         return FlagMailAction()
-    elif rule.action == MailRule.ACTION_DELETE:
+    elif rule.action == MailRule.AttachmentAction.DELETE:
         return DeleteMailAction()
-    elif rule.action == MailRule.ACTION_MOVE:
+    elif rule.action == MailRule.AttachmentAction.MOVE:
         return MoveMailAction()
-    elif rule.action == MailRule.ACTION_MARK_READ:
+    elif rule.action == MailRule.AttachmentAction.MARK_READ:
         return MarkReadMailAction()
     else:
         raise NotImplementedError("Unknown action.")  # pragma: nocover
@@ -89,11 +89,11 @@ def make_criterias(rule):
 
 
 def get_mailbox(server, port, security):
-    if security == MailAccount.IMAP_SECURITY_NONE:
+    if security == MailAccount.ImapSecurity.NONE:
         mailbox = MailBoxUnencrypted(server, port)
-    elif security == MailAccount.IMAP_SECURITY_STARTTLS:
+    elif security == MailAccount.ImapSecurity.STARTTLS:
         mailbox = MailBox(server, port, starttls=True)
-    elif security == MailAccount.IMAP_SECURITY_SSL:
+    elif security == MailAccount.ImapSecurity.SSL:
         mailbox = MailBox(server, port)
     else:
         raise NotImplementedError("Unknown IMAP security")  # pragma: nocover
@@ -112,10 +112,10 @@ def _correspondent_from_name(self, name):
             return None
 
     def get_title(self, message, att, rule):
-        if rule.assign_title_from == MailRule.TITLE_FROM_SUBJECT:
+        if rule.assign_title_from == MailRule.TitleSource.FROM_SUBJECT:
             return message.subject
 
-        elif rule.assign_title_from == MailRule.TITLE_FROM_FILENAME:
+        elif rule.assign_title_from == MailRule.TitleSource.FROM_FILENAME:
             return os.path.splitext(os.path.basename(att.filename))[0]
 
         else:
@@ -126,20 +126,20 @@ def get_title(self, message, att, rule):
     def get_correspondent(self, message: MailMessage, rule):
         c_from = rule.assign_correspondent_from
 
-        if c_from == MailRule.CORRESPONDENT_FROM_NOTHING:
+        if c_from == MailRule.CorrespondentSource.FROM_NOTHING:
             return None
 
-        elif c_from == MailRule.CORRESPONDENT_FROM_EMAIL:
+        elif c_from == MailRule.CorrespondentSource.FROM_EMAIL:
             return self._correspondent_from_name(message.from_)
 
-        elif c_from == MailRule.CORRESPONDENT_FROM_NAME:
+        elif c_from == MailRule.CorrespondentSource.FROM_NAME:
             from_values = message.from_values
             if from_values is not None and len(from_values.name) > 0:
                 return self._correspondent_from_name(from_values.name)
             else:
                 return self._correspondent_from_name(message.from_)
 
-        elif c_from == MailRule.CORRESPONDENT_FROM_CUSTOM:
+        elif c_from == MailRule.CorrespondentSource.FROM_CUSTOM:
             return rule.assign_correspondent
 
         else:
@@ -274,7 +274,8 @@ def handle_message(self, message, rule):
 
             if (
                 not att.content_disposition == "attachment"
-                and rule.attachment_type == MailRule.ATTACHMENT_TYPE_ATTACHMENTS_ONLY
+                and rule.attachment_type
+                == MailRule.AttachmentProcessing.ATTACHMENTS_ONLY
             ):
                 self.log(
                     "debug",
diff --git a/src/paperless_mail/migrations/0009_alter_mailrule_action_alter_mailrule_folder.py b/src/paperless_mail/migrations/0009_alter_mailrule_action_alter_mailrule_folder.py
new file mode 100644
--- /dev/null
+++ b/src/paperless_mail/migrations/0009_alter_mailrule_action_alter_mailrule_folder.py
@@ -0,0 +1,37 @@
+# Generated by Django 4.0.3 on 2022-03-28 17:40
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ("paperless_mail", "0008_auto_20210516_0940"),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name="mailrule",
+            name="action",
+            field=models.PositiveIntegerField(
+                choices=[
+                    (1, "Mark as read, don't process read mails"),
+                    (2, "Flag the mail, don't process flagged mails"),
+                    (3, "Move to specified folder"),
+                    (4, "Delete"),
+                ],
+                default=3,
+                verbose_name="action",
+            ),
+        ),
+        migrations.AlterField(
+            model_name="mailrule",
+            name="folder",
+            field=models.CharField(
+                default="INBOX",
+                help_text="Subfolders must be separated by a delimiter, often a dot ('.') or slash ('/'), but it varies by mail server.",
+                max_length=256,
+                verbose_name="folder",
+            ),
+        ),
+    ]
diff --git a/src/paperless_mail/models.py b/src/paperless_mail/models.py
--- a/src/paperless_mail/models.py
+++ b/src/paperless_mail/models.py
@@ -8,15 +8,10 @@ class Meta:
         verbose_name = _("mail account")
         verbose_name_plural = _("mail accounts")
 
-    IMAP_SECURITY_NONE = 1
-    IMAP_SECURITY_SSL = 2
-    IMAP_SECURITY_STARTTLS = 3
-
-    IMAP_SECURITY_OPTIONS = (
-        (IMAP_SECURITY_NONE, _("No encryption")),
-        (IMAP_SECURITY_SSL, _("Use SSL")),
-        (IMAP_SECURITY_STARTTLS, _("Use STARTTLS")),
-    )
+    class ImapSecurity(models.IntegerChoices):
+        NONE = 1, _("No encryption")
+        SSL = 2, _("Use SSL")
+        STARTTLS = 3, _("Use STARTTLS")
 
     name = models.CharField(_("name"), max_length=256, unique=True)
 
@@ -34,8 +29,8 @@ class Meta:
 
     imap_security = models.PositiveIntegerField(
         _("IMAP security"),
-        choices=IMAP_SECURITY_OPTIONS,
-        default=IMAP_SECURITY_SSL,
+        choices=ImapSecurity.choices,
+        default=ImapSecurity.SSL,
     )
 
     username = models.CharField(_("username"), max_length=256)
@@ -61,48 +56,25 @@ class Meta:
         verbose_name = _("mail rule")
         verbose_name_plural = _("mail rules")
 
-    ATTACHMENT_TYPE_ATTACHMENTS_ONLY = 1
-    ATTACHMENT_TYPE_EVERYTHING = 2
+    class AttachmentProcessing(models.IntegerChoices):
+        ATTACHMENTS_ONLY = 1, _("Only process attachments.")
+        EVERYTHING = 2, _("Process all files, including 'inline' " "attachments.")
 
-    ATTACHMENT_TYPES = (
-        (ATTACHMENT_TYPE_ATTACHMENTS_ONLY, _("Only process attachments.")),
-        (
-            ATTACHMENT_TYPE_EVERYTHING,
-            _("Process all files, including 'inline' " "attachments."),
-        ),
-    )
+    class AttachmentAction(models.IntegerChoices):
+        DELETE = 1, _("Mark as read, don't process read mails")
+        MOVE = 2, _("Flag the mail, don't process flagged mails")
+        MARK_READ = 3, _("Move to specified folder")
+        FLAG = 4, _("Delete")
 
-    ACTION_DELETE = 1
-    ACTION_MOVE = 2
-    ACTION_MARK_READ = 3
-    ACTION_FLAG = 4
+    class TitleSource(models.IntegerChoices):
+        FROM_SUBJECT = 1, _("Use subject as title")
+        FROM_FILENAME = 2, _("Use attachment filename as title")
 
-    ACTIONS = (
-        (ACTION_MARK_READ, _("Mark as read, don't process read mails")),
-        (ACTION_FLAG, _("Flag the mail, don't process flagged mails")),
-        (ACTION_MOVE, _("Move to specified folder")),
-        (ACTION_DELETE, _("Delete")),
-    )
-
-    TITLE_FROM_SUBJECT = 1
-    TITLE_FROM_FILENAME = 2
-
-    TITLE_SELECTOR = (
-        (TITLE_FROM_SUBJECT, _("Use subject as title")),
-        (TITLE_FROM_FILENAME, _("Use attachment filename as title")),
-    )
-
-    CORRESPONDENT_FROM_NOTHING = 1
-    CORRESPONDENT_FROM_EMAIL = 2
-    CORRESPONDENT_FROM_NAME = 3
-    CORRESPONDENT_FROM_CUSTOM = 4
-
-    CORRESPONDENT_SELECTOR = (
-        (CORRESPONDENT_FROM_NOTHING, _("Do not assign a correspondent")),
-        (CORRESPONDENT_FROM_EMAIL, _("Use mail address")),
-        (CORRESPONDENT_FROM_NAME, _("Use name (or mail address if not available)")),
-        (CORRESPONDENT_FROM_CUSTOM, _("Use correspondent selected below")),
-    )
+    class CorrespondentSource(models.IntegerChoices):
+        FROM_NOTHING = 1, _("Do not assign a correspondent")
+        FROM_EMAIL = 2, _("Use mail address")
+        FROM_NAME = 3, _("Use name (or mail address if not available)")
+        FROM_CUSTOM = 4, _("Use correspondent selected below")
 
     name = models.CharField(_("name"), max_length=256, unique=True)
 
@@ -119,7 +91,10 @@ class Meta:
         _("folder"),
         default="INBOX",
         max_length=256,
-        help_text=_("Subfolders must be separated by dots."),
+        help_text=_(
+            "Subfolders must be separated by a delimiter, often a dot ('.') or"
+            " slash ('/'), but it varies by mail server.",
+        ),
     )
 
     filter_from = models.CharField(
@@ -161,8 +136,8 @@ class Meta:
 
     attachment_type = models.PositiveIntegerField(
         _("attachment type"),
-        choices=ATTACHMENT_TYPES,
-        default=ATTACHMENT_TYPE_ATTACHMENTS_ONLY,
+        choices=AttachmentProcessing.choices,
+        default=AttachmentProcessing.ATTACHMENTS_ONLY,
         help_text=_(
             "Inline attachments include embedded images, so it's best "
             "to combine this option with a filename filter.",
@@ -171,8 +146,8 @@ class Meta:
 
     action = models.PositiveIntegerField(
         _("action"),
-        choices=ACTIONS,
-        default=ACTION_MARK_READ,
+        choices=AttachmentAction.choices,
+        default=AttachmentAction.MARK_READ,
     )
 
     action_parameter = models.CharField(
@@ -190,8 +165,8 @@ class Meta:
 
     assign_title_from = models.PositiveIntegerField(
         _("assign title from"),
-        choices=TITLE_SELECTOR,
-        default=TITLE_FROM_SUBJECT,
+        choices=TitleSource.choices,
+        default=TitleSource.FROM_SUBJECT,
     )
 
     assign_tag = models.ForeignKey(
@@ -212,8 +187,8 @@ class Meta:
 
     assign_correspondent_from = models.PositiveIntegerField(
         _("assign correspondent from"),
-        choices=CORRESPONDENT_SELECTOR,
-        default=CORRESPONDENT_FROM_NOTHING,
+        choices=CorrespondentSource.choices,
+        default=CorrespondentSource.FROM_NOTHING,
     )
 
     assign_correspondent = models.ForeignKey(


Test patch:
diff --git a/src/paperless_mail/tests/test_mail.py b/src/paperless_mail/tests/test_mail.py
--- a/src/paperless_mail/tests/test_mail.py
+++ b/src/paperless_mail/tests/test_mail.py
@@ -246,13 +246,13 @@ def test_get_correspondent(self):
 
         rule = MailRule(
             name="a",
-            assign_correspondent_from=MailRule.CORRESPONDENT_FROM_NOTHING,
+            assign_correspondent_from=MailRule.CorrespondentSource.FROM_NOTHING,
         )
         self.assertIsNone(handler.get_correspondent(message, rule))
 
         rule = MailRule(
             name="b",
-            assign_correspondent_from=MailRule.CORRESPONDENT_FROM_EMAIL,
+            assign_correspondent_from=MailRule.CorrespondentSource.FROM_EMAIL,
         )
         c = handler.get_correspondent(message, rule)
         self.assertIsNotNone(c)
@@ -264,7 +264,7 @@ def test_get_correspondent(self):
 
         rule = MailRule(
             name="c",
-            assign_correspondent_from=MailRule.CORRESPONDENT_FROM_NAME,
+            assign_correspondent_from=MailRule.CorrespondentSource.FROM_NAME,
         )
         c = handler.get_correspondent(message, rule)
         self.assertIsNotNone(c)
@@ -275,7 +275,7 @@ def test_get_correspondent(self):
 
         rule = MailRule(
             name="d",
-            assign_correspondent_from=MailRule.CORRESPONDENT_FROM_CUSTOM,
+            assign_correspondent_from=MailRule.CorrespondentSource.FROM_CUSTOM,
             assign_correspondent=someone_else,
         )
         c = handler.get_correspondent(message, rule)
@@ -289,9 +289,15 @@ def test_get_title(self):
 
         handler = MailAccountHandler()
 
-        rule = MailRule(name="a", assign_title_from=MailRule.TITLE_FROM_FILENAME)
+        rule = MailRule(
+            name="a",
+            assign_title_from=MailRule.TitleSource.FROM_FILENAME,
+        )
         self.assertEqual(handler.get_title(message, att, rule), "this_is_the_file")
-        rule = MailRule(name="b", assign_title_from=MailRule.TITLE_FROM_SUBJECT)
+        rule = MailRule(
+            name="b",
+            assign_title_from=MailRule.TitleSource.FROM_SUBJECT,
+        )
         self.assertEqual(handler.get_title(message, att, rule), "the message title")
 
     def test_handle_message(self):
@@ -302,7 +308,10 @@ def test_handle_message(self):
         )
 
         account = MailAccount()
-        rule = MailRule(assign_title_from=MailRule.TITLE_FROM_FILENAME, account=account)
+        rule = MailRule(
+            assign_title_from=MailRule.TitleSource.FROM_FILENAME,
+            account=account,
+        )
 
         result = self.mail_account_handler.handle_message(message, rule)
 
@@ -346,7 +355,10 @@ def test_handle_unknown_mime_type(self):
         )
 
         account = MailAccount()
-        rule = MailRule(assign_title_from=MailRule.TITLE_FROM_FILENAME, account=account)
+        rule = MailRule(
+            assign_title_from=MailRule.TitleSource.FROM_FILENAME,
+            account=account,
+        )
 
         result = self.mail_account_handler.handle_message(message, rule)
 
@@ -369,7 +381,10 @@ def test_handle_disposition(self):
         )
 
         account = MailAccount()
-        rule = MailRule(assign_title_from=MailRule.TITLE_FROM_FILENAME, account=account)
+        rule = MailRule(
+            assign_title_from=MailRule.TitleSource.FROM_FILENAME,
+            account=account,
+        )
 
         result = self.mail_account_handler.handle_message(message, rule)
 
@@ -392,9 +407,9 @@ def test_handle_inline_files(self):
 
         account = MailAccount()
         rule = MailRule(
-            assign_title_from=MailRule.TITLE_FROM_FILENAME,
+            assign_title_from=MailRule.TitleSource.FROM_FILENAME,
             account=account,
-            attachment_type=MailRule.ATTACHMENT_TYPE_EVERYTHING,
+            attachment_type=MailRule.AttachmentProcessing.EVERYTHING,
         )
 
         result = self.mail_account_handler.handle_message(message, rule)
@@ -424,7 +439,7 @@ def test_filename_filter(self):
             self.async_task.reset_mock()
             account = MailAccount()
             rule = MailRule(
-                assign_title_from=MailRule.TITLE_FROM_FILENAME,
+                assign_title_from=MailRule.TitleSource.FROM_FILENAME,
                 account=account,
                 filter_attachment_filename=pattern,
             )
@@ -449,7 +464,7 @@ def test_handle_mail_account_mark_read(self):
         _ = MailRule.objects.create(
             name="testrule",
             account=account,
-            action=MailRule.ACTION_MARK_READ,
+            action=MailRule.AttachmentAction.MARK_READ,
         )
 
         self.assertEqual(len(self.bogus_mailbox.messages), 3)
@@ -472,7 +487,7 @@ def test_handle_mail_account_delete(self):
         _ = MailRule.objects.create(
             name="testrule",
             account=account,
-            action=MailRule.ACTION_DELETE,
+            action=MailRule.AttachmentAction.DELETE,
             filter_subject="Invoice",
         )
 
@@ -493,7 +508,7 @@ def test_handle_mail_account_flag(self):
         _ = MailRule.objects.create(
             name="testrule",
             account=account,
-            action=MailRule.ACTION_FLAG,
+            action=MailRule.AttachmentAction.FLAG,
             filter_subject="Invoice",
         )
 
@@ -516,7 +531,7 @@ def test_handle_mail_account_move(self):
         _ = MailRule.objects.create(
             name="testrule",
             account=account,
-            action=MailRule.ACTION_MOVE,
+            action=MailRule.AttachmentAction.MOVE,
             action_parameter="spam",
             filter_subject="Claim",
         )
@@ -562,7 +577,7 @@ def test_error_skip_account(self):
         _ = MailRule.objects.create(
             name="testrule",
             account=account,
-            action=MailRule.ACTION_MOVE,
+            action=MailRule.AttachmentAction.MOVE,
             action_parameter="spam",
             filter_subject="Claim",
         )
@@ -583,7 +598,7 @@ def test_error_skip_rule(self):
         _ = MailRule.objects.create(
             name="testrule",
             account=account,
-            action=MailRule.ACTION_MOVE,
+            action=MailRule.AttachmentAction.MOVE,
             action_parameter="spam",
             filter_subject="Claim",
             order=1,
@@ -592,7 +607,7 @@ def test_error_skip_rule(self):
         _ = MailRule.objects.create(
             name="testrule2",
             account=account,
-            action=MailRule.ACTION_MOVE,
+            action=MailRule.AttachmentAction.MOVE,
             action_parameter="spam",
             filter_subject="Claim",
             order=2,
@@ -622,7 +637,7 @@ def get_correspondent_fake(message, rule):
         _ = MailRule.objects.create(
             name="testrule",
             account=account,
-            action=MailRule.ACTION_MOVE,
+            action=MailRule.AttachmentAction.MOVE,
             action_parameter="spam",
         )
 
@@ -647,9 +662,9 @@ def test_error_create_correspondent(self):
             name="testrule",
             filter_from="amazon@amazon.de",
             account=account,
-            action=MailRule.ACTION_MOVE,
+            action=MailRule.AttachmentAction.MOVE,
             action_parameter="spam",
-            assign_correspondent_from=MailRule.CORRESPONDENT_FROM_EMAIL,
+            assign_correspondent_from=MailRule.CorrespondentSource.FROM_EMAIL,
         )
 
         self.mail_account_handler.handle_mail_account(account)
@@ -684,7 +699,7 @@ def test_filters(self):
         rule = MailRule.objects.create(
             name="testrule3",
             account=account,
-            action=MailRule.ACTION_DELETE,
+            action=MailRule.AttachmentAction.DELETE,
             filter_subject="Claim",
         )