]> git.ipfire.org Git - thirdparty/paperless-ngx.git/commitdiff
Enhancement: process mail button (#8466)
authorshamoon <4887959+shamoon@users.noreply.github.com>
Wed, 11 Dec 2024 19:03:53 +0000 (11:03 -0800)
committerGitHub <noreply@github.com>
Wed, 11 Dec 2024 19:03:53 +0000 (11:03 -0800)
src-ui/messages.xlf
src-ui/src/app/components/manage/mail/mail.component.html
src-ui/src/app/components/manage/mail/mail.component.spec.ts
src-ui/src/app/components/manage/mail/mail.component.ts
src-ui/src/app/services/rest/mail-account.service.spec.ts
src-ui/src/app/services/rest/mail-account.service.ts
src/paperless_mail/tasks.py
src/paperless_mail/tests/test_mail.py
src/paperless_mail/views.py

index 9dc2df42dc325b2a530d735e4bd4256546647fb6..2854df87c90ec14ad5cea9ff12e2395c6b054721 100644 (file)
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
-          <context context-type="linenumber">114</context>
+          <context context-type="linenumber">122</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
-          <context context-type="linenumber">178</context>
+          <context context-type="linenumber">186</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
-          <context context-type="linenumber">76</context>
+          <context context-type="linenumber">78</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
-          <context context-type="linenumber">140</context>
+          <context context-type="linenumber">148</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
-          <context context-type="linenumber">152</context>
+          <context context-type="linenumber">160</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
-          <context context-type="linenumber">103</context>
+          <context context-type="linenumber">111</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
-          <context context-type="linenumber">107</context>
+          <context context-type="linenumber">115</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
-          <context context-type="linenumber">79</context>
+          <context context-type="linenumber">81</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
-          <context context-type="linenumber">141</context>
+          <context context-type="linenumber">149</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
-          <context context-type="linenumber">155</context>
+          <context context-type="linenumber">163</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.ts</context>
-          <context context-type="linenumber">259</context>
+          <context context-type="linenumber">270</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.ts</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
-          <context context-type="linenumber">73</context>
+          <context context-type="linenumber">75</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
-          <context context-type="linenumber">139</context>
+          <context context-type="linenumber">147</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
-          <context context-type="linenumber">149</context>
+          <context context-type="linenumber">157</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.html</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.ts</context>
-          <context context-type="linenumber">261</context>
+          <context context-type="linenumber">272</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.ts</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
-          <context context-type="linenumber">105</context>
+          <context context-type="linenumber">113</context>
         </context-group>
       </trans-unit>
       <trans-unit id="220550782947016929" datatype="html">
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
-          <context context-type="linenumber">128</context>
+          <context context-type="linenumber">136</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/workflows/workflows.component.html</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
-          <context context-type="linenumber">142</context>
+          <context context-type="linenumber">150</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
-          <context context-type="linenumber">160</context>
+          <context context-type="linenumber">168</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/workflows/workflows.component.html</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
-          <context context-type="linenumber">106</context>
+          <context context-type="linenumber">114</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/workflows/workflows.component.html</context>
           <context context-type="linenumber">31</context>
         </context-group>
       </trans-unit>
+      <trans-unit id="5998664372396608071" datatype="html">
+        <source>Process Mail</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
+          <context context-type="linenumber">68</context>
+        </context-group>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
+          <context context-type="linenumber">86</context>
+        </context-group>
+      </trans-unit>
       <trans-unit id="6235247415162820954" datatype="html">
         <source>No mail accounts defined.</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
-          <context context-type="linenumber">87</context>
+          <context context-type="linenumber">95</context>
         </context-group>
       </trans-unit>
       <trans-unit id="5364020217520256833" datatype="html">
         <source>Mail rules</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
-          <context context-type="linenumber">95</context>
+          <context context-type="linenumber">103</context>
         </context-group>
       </trans-unit>
       <trans-unit id="1372022816709469401" datatype="html">
         <source>Add Rule</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
-          <context context-type="linenumber">97</context>
+          <context context-type="linenumber">105</context>
         </context-group>
       </trans-unit>
       <trans-unit id="2535466903620876415" datatype="html">
         <source>Sort Order</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
-          <context context-type="linenumber">104</context>
+          <context context-type="linenumber">112</context>
         </context-group>
       </trans-unit>
       <trans-unit id="5769292297914455214" datatype="html">
         <source>Disabled</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
-          <context context-type="linenumber">128</context>
+          <context context-type="linenumber">136</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/workflows/workflows.component.html</context>
         <source>No mail rules defined.</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.html</context>
-          <context context-type="linenumber">169</context>
+          <context context-type="linenumber">177</context>
         </context-group>
       </trans-unit>
       <trans-unit id="3178554336792037159" datatype="html">
           <context context-type="linenumber">197</context>
         </context-group>
       </trans-unit>
+      <trans-unit id="6017339134595080118" datatype="html">
+        <source>Processing mail account</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/mail/mail.component.ts</context>
+          <context context-type="linenumber">208</context>
+        </context-group>
+      </trans-unit>
+      <trans-unit id="7662032577672828575" datatype="html">
+        <source>Error processing mail account</source>
+        <context-group purpose="location">
+          <context context-type="sourcefile">src/app/components/manage/mail/mail.component.ts</context>
+          <context context-type="linenumber">211</context>
+        </context-group>
+      </trans-unit>
       <trans-unit id="123368655395433699" datatype="html">
         <source>Saved rule &quot;<x id="PH" equiv-text="newMailRule.name"/>&quot;.</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.ts</context>
-          <context context-type="linenumber">216</context>
+          <context context-type="linenumber">227</context>
         </context-group>
       </trans-unit>
       <trans-unit id="8951124554918814321" datatype="html">
         <source>Error saving rule.</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.ts</context>
-          <context context-type="linenumber">227</context>
+          <context context-type="linenumber">238</context>
         </context-group>
       </trans-unit>
       <trans-unit id="3574401690710711341" datatype="html">
         <source>Rule &quot;<x id="PH" equiv-text="rule.name"/>&quot; enabled.</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.ts</context>
-          <context context-type="linenumber">243</context>
+          <context context-type="linenumber">254</context>
         </context-group>
       </trans-unit>
       <trans-unit id="7171685227222299542" datatype="html">
         <source>Rule &quot;<x id="PH" equiv-text="rule.name"/>&quot; disabled.</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.ts</context>
-          <context context-type="linenumber">244</context>
+          <context context-type="linenumber">255</context>
         </context-group>
       </trans-unit>
       <trans-unit id="684458488797860482" datatype="html">
         <source>Error toggling rule.</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.ts</context>
-          <context context-type="linenumber">248</context>
+          <context context-type="linenumber">259</context>
         </context-group>
       </trans-unit>
       <trans-unit id="3896080636020672118" datatype="html">
         <source>Confirm delete mail rule</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.ts</context>
-          <context context-type="linenumber">257</context>
+          <context context-type="linenumber">268</context>
         </context-group>
       </trans-unit>
       <trans-unit id="2250372580580310337" datatype="html">
         <source>This operation will permanently delete this mail rule.</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.ts</context>
-          <context context-type="linenumber">258</context>
+          <context context-type="linenumber">269</context>
         </context-group>
       </trans-unit>
       <trans-unit id="9077981247971516916" datatype="html">
         <source>Deleted mail rule</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.ts</context>
-          <context context-type="linenumber">267</context>
+          <context context-type="linenumber">278</context>
         </context-group>
       </trans-unit>
       <trans-unit id="2033194641751367552" datatype="html">
         <source>Error deleting mail rule.</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.ts</context>
-          <context context-type="linenumber">276</context>
+          <context context-type="linenumber">287</context>
         </context-group>
       </trans-unit>
       <trans-unit id="3061362835271417984" datatype="html">
         <source>Permissions updated</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.ts</context>
-          <context context-type="linenumber">298</context>
+          <context context-type="linenumber">309</context>
         </context-group>
       </trans-unit>
       <trans-unit id="4639647950943944112" datatype="html">
         <source>Error updating permissions</source>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/mail/mail.component.ts</context>
-          <context context-type="linenumber">303</context>
+          <context context-type="linenumber">314</context>
         </context-group>
         <context-group purpose="location">
           <context context-type="sourcefile">src/app/components/manage/management-list/management-list.component.ts</context>
index 9b6fe04235538cb4cd873b3815a34a75fd8d4dca..fc786840c46696f881d3d2e5c5c9e1ac11bd36f5 100644 (file)
                   <button (click)="editMailAccount(account)" *pngxIfPermissions="{ action: PermissionAction.Change, type: PermissionType.MailAccount }" ngbDropdownItem i18n>Edit</button>
                   <button (click)="editPermissions(account)" *pngxIfOwner="account" ngbDropdownItem i18n>Permissions</button>
                   <button (click)="deleteMailAccount(account)" *pngxIfPermissions="{ action: PermissionAction.Delete, type: PermissionType.MailAccount }" ngbDropdownItem i18n>Delete</button>
+                  <button (click)="processAccount(account)" *pngxIfPermissions="{ action: PermissionAction.Change, type: PermissionType.MailAccount }" ngbDropdownItem i18n>Process Mail</button>
                 </div>
               </div>
             </div>
-            <div class="btn-group d-none d-sm-block">
-              <button *pngxIfPermissions="{ action: PermissionAction.Change, type: PermissionType.MailAccount }" [disabled]="!userCanEdit(account)" class="btn btn-sm btn-outline-secondary" type="button" (click)="editMailAccount(account)">
-                <i-bs width="1em" height="1em" name="pencil"></i-bs>&nbsp;<ng-container i18n>Edit</ng-container>
-              </button>
-              <button *pngxIfOwner="account" class="btn btn-sm btn-outline-secondary" type="button" (click)="editPermissions(account)">
-                <i-bs width="1em" height="1em" name="person-lock"></i-bs>&nbsp;<ng-container i18n>Permissions</ng-container>
-              </button>
-              <button *pngxIfPermissions="{ action: PermissionAction.Delete, type: PermissionType.MailAccount }" [disabled]="!userIsOwner(account)" class="btn btn-sm btn-outline-danger" type="button" (click)="deleteMailAccount(account)">
-                <i-bs width="1em" height="1em" name="trash"></i-bs>&nbsp;<ng-container i18n>Delete</ng-container>
-              </button>
+            <div class="btn-toolbar d-none d-sm-flex gap-2" role="toolbar">
+              <div class="btn-group">
+                <button *pngxIfPermissions="{ action: PermissionAction.Change, type: PermissionType.MailAccount }" [disabled]="!userCanEdit(account)" class="btn btn-sm btn-outline-secondary" type="button" (click)="editMailAccount(account)">
+                  <i-bs width="1em" height="1em" name="pencil"></i-bs>&nbsp;<ng-container i18n>Edit</ng-container>
+                </button>
+                <button *pngxIfOwner="account" class="btn btn-sm btn-outline-secondary" type="button" (click)="editPermissions(account)">
+                  <i-bs width="1em" height="1em" name="person-lock"></i-bs>&nbsp;<ng-container i18n>Permissions</ng-container>
+                </button>
+                <button *pngxIfPermissions="{ action: PermissionAction.Delete, type: PermissionType.MailAccount }" [disabled]="!userIsOwner(account)" class="btn btn-sm btn-outline-danger" type="button" (click)="deleteMailAccount(account)">
+                  <i-bs width="1em" height="1em" name="trash"></i-bs>&nbsp;<ng-container i18n>Delete</ng-container>
+                </button>
+              </div>
+              <div class="btn-group">
+                <button *pngxIfPermissions="{ action: PermissionAction.Change, type: PermissionType.MailAccount }" class="btn btn-sm btn-outline-secondary" type="button" (click)="processAccount(account)">
+                  <i-bs width="1em" height="1em" name="arrow-clockwise"></i-bs>&nbsp;<ng-container i18n>Process Mail</ng-container>
+                </button>
+              </div>
             </div>
           </div>
         </div>
index d3194459fdf3a67b07fe71b169a65c499a549034..5f9a3c73a844c1b742c6628828e3e23c18014f55 100644 (file)
@@ -219,6 +219,23 @@ describe('MailComponent', () => {
     expect(toastInfoSpy).toHaveBeenCalledWith('Deleted mail account')
   })
 
+  it('should support process mail account, show error if needed', () => {
+    completeSetup()
+    const processSpy = jest.spyOn(mailAccountService, 'processAccount')
+    const toastErrorSpy = jest.spyOn(toastService, 'showError')
+    const toastInfoSpy = jest.spyOn(toastService, 'showInfo')
+    component.processAccount(mailAccounts[0] as MailAccount)
+    expect(processSpy).toHaveBeenCalled()
+    processSpy.mockReturnValueOnce(
+      throwError(() => new Error('error processing mail account'))
+    )
+    component.processAccount(mailAccounts[0] as MailAccount)
+    expect(toastErrorSpy).toHaveBeenCalled()
+    processSpy.mockReturnValueOnce(of(true))
+    component.processAccount(mailAccounts[0] as MailAccount)
+    expect(toastInfoSpy).toHaveBeenCalledWith('Processing mail account')
+  })
+
   it('should support edit / create mail rule, show error if needed', () => {
     completeSetup()
     let modal: NgbModalRef
index dce23b4b6b417c26f27547f717a8a0261ecf457e..c15ef28afff48730452ca00e561089a07ad1aa8a 100644 (file)
@@ -202,6 +202,17 @@ export class MailComponent
     })
   }
 
+  processAccount(account: MailAccount) {
+    this.mailAccountService.processAccount(account).subscribe({
+      next: () => {
+        this.toastService.showInfo($localize`Processing mail account`)
+      },
+      error: (e) => {
+        this.toastService.showError($localize`Error processing mail account`, e)
+      },
+    })
+  }
+
   editMailRule(rule: MailRule = null, forceCreate = false) {
     const modal = this.modalService.open(MailRuleEditDialogComponent, {
       backdrop: 'static',
index c9d1da7d11140d6132648ce2e1c39df6806de5ea..ef69b979ebe5fbfbc20517c37e6c7703f95f2908 100644 (file)
@@ -68,6 +68,14 @@ describe(`Additional service tests for MailAccountService`, () => {
     expect(service.allAccounts).toEqual(mail_accounts)
   })
 
+  it('should support processAccount', () => {
+    subscription = service.processAccount(mail_accounts[0]).subscribe()
+    const req = httpTestingController.expectOne(
+      `${environment.apiBaseUrl}${endpoint}/${mail_accounts[0].id}/process/`
+    )
+    expect(req.request.method).toEqual('POST')
+  })
+
   beforeEach(() => {
     // Dont need to setup again
 
index c5c2c79e014447e7b7eb944ea201dd5f882aaead..e946b139980b775ffd9f34851b02ca69ab2d3849 100644 (file)
@@ -47,4 +47,8 @@ export class MailAccountService extends AbstractPaperlessService<MailAccount> {
     delete account['set_permissions']
     return this.http.post(this.getResourceUrl() + 'test/', account)
   }
+
+  processAccount(account: MailAccount) {
+    return this.http.post(this.getResourceUrl(account.id, 'process'), {})
+  }
 }
index 67bd620cf53bb09cb8ed7ff00cc6c6914ec94f83..df1f30d9145f42b3a3b5320257f66ab4dd29d32f 100644 (file)
@@ -11,9 +11,14 @@ logger = logging.getLogger("paperless.mail.tasks")
 
 
 @shared_task
-def process_mail_accounts():
+def process_mail_accounts(account_ids: list[int] | None = None) -> str:
     total_new_documents = 0
-    for account in MailAccount.objects.all():
+    accounts = (
+        MailAccount.objects.filter(pk__in=account_ids)
+        if account_ids
+        else MailAccount.objects.all()
+    )
+    for account in accounts:
         if not MailRule.objects.filter(account=account, enabled=True).exists():
             logger.info(f"No rules enabled for account {account}. Skipping.")
             continue
index acd5ac0f739777c611856e37d2b67918ae4cb2bc..0e58fc6f70f16c46062aa4811d22fcb346264b59 100644 (file)
@@ -1596,6 +1596,40 @@ class TestTasks(TestCase):
         tasks.process_mail_accounts()
         self.assertEqual(m.call_count, 0)
 
+    @mock.patch("paperless_mail.tasks.MailAccountHandler.handle_mail_account")
+    def test_process_with_account_ids(self, m):
+        m.side_effect = lambda account: 6
+
+        account_a = MailAccount.objects.create(
+            name="A",
+            imap_server="A",
+            username="A",
+            password="A",
+        )
+        account_b = MailAccount.objects.create(
+            name="B",
+            imap_server="A",
+            username="A",
+            password="A",
+        )
+        MailRule.objects.create(
+            name="A",
+            account=account_a,
+        )
+        MailRule.objects.create(
+            name="B",
+            account=account_b,
+        )
+
+        result = tasks.process_mail_accounts(account_ids=[account_a.id])
+
+        self.assertEqual(m.call_count, 1)
+        self.assertIn("Added 6", result)
+
+        m.side_effect = lambda account: 0
+        result = tasks.process_mail_accounts(account_ids=[account_b.id])
+        self.assertIn("No new", result)
+
 
 class TestMailAccountTestView(APITestCase):
     def setUp(self):
@@ -1720,3 +1754,30 @@ class TestMailAccountTestView(APITestCase):
             error_str = cm.output[0]
             expected_str = "Unable to refresh oauth token"
             self.assertIn(expected_str, error_str)
+
+
+class TestMailAccountProcess(APITestCase):
+    def setUp(self):
+        self.mailMocker = MailMocker()
+        self.mailMocker.setUp()
+        self.user = User.objects.create_superuser(
+            username="testuser",
+            password="testpassword",
+        )
+        self.client.force_authenticate(user=self.user)
+        self.account = MailAccount.objects.create(
+            imap_server="imap.example.com",
+            imap_port=993,
+            imap_security=MailAccount.ImapSecurity.SSL,
+            username="admin",
+            password="secret",
+            account_type=MailAccount.MailAccountType.IMAP,
+            owner=self.user,
+        )
+        self.url = f"/api/mail_accounts/{self.account.pk}/process/"
+
+    @mock.patch("paperless_mail.tasks.process_mail_accounts.delay")
+    def test_mail_account_process_view(self, m):
+        response = self.client.post(self.url)
+        self.assertEqual(response.status_code, status.HTTP_200_OK)
+        m.assert_called_once()
index 724d8e91e691d056037103155b5ca37d46de6a0a..170d5c6c1d43ece016294a68ae3e3ac6fcb5c286 100644 (file)
@@ -24,6 +24,7 @@ from paperless_mail.models import MailRule
 from paperless_mail.oauth import PaperlessMailOAuth2Manager
 from paperless_mail.serialisers import MailAccountSerializer
 from paperless_mail.serialisers import MailRuleSerializer
+from paperless_mail.tasks import process_mail_accounts
 
 
 class MailAccountViewSet(ModelViewSet, PassUserMixin):
@@ -87,6 +88,13 @@ class MailAccountViewSet(ModelViewSet, PassUserMixin):
                 )
                 return HttpResponseBadRequest("Unable to connect to server")
 
+    @action(methods=["post"], detail=True)
+    def process(self, request, pk=None):
+        account = self.get_object()
+        process_mail_accounts.delay([account.pk])
+
+        return Response({"result": "OK"})
+
 
 class MailRuleViewSet(ModelViewSet, PassUserMixin):
     model = MailRule