-
+
+
+
{{account.imap_server}}
{{account.username}}
diff --git a/src-ui/src/app/components/manage/mail/mail.component.ts b/src-ui/src/app/components/manage/mail/mail.component.ts
index 381db6e1d..ca93b7a16 100644
--- a/src-ui/src/app/components/manage/mail/mail.component.ts
+++ b/src-ui/src/app/components/manage/mail/mail.component.ts
@@ -2,7 +2,7 @@ import { Component, OnInit, OnDestroy } from '@angular/core'
import { NgbModal } from '@ng-bootstrap/ng-bootstrap'
import { Subject, first, takeUntil } from 'rxjs'
import { ObjectWithPermissions } from 'src/app/data/object-with-permissions'
-import { MailAccount } from 'src/app/data/mail-account'
+import { MailAccount, MailAccountType } from 'src/app/data/mail-account'
import { MailRule } from 'src/app/data/mail-rule'
import {
PermissionsService,
@@ -31,6 +31,8 @@ export class MailComponent
extends ComponentWithPermissions
implements OnInit, OnDestroy
{
+ public MailAccountType = MailAccountType
+
mailAccounts: MailAccount[] = []
mailRules: MailRule[] = []
diff --git a/src-ui/src/app/data/mail-account.ts b/src-ui/src/app/data/mail-account.ts
index 5ab8ba3b5..b56917044 100644
--- a/src-ui/src/app/data/mail-account.ts
+++ b/src-ui/src/app/data/mail-account.ts
@@ -6,6 +6,12 @@ export enum IMAPSecurity {
STARTTLS = 3,
}
+export enum MailAccountType {
+ IMAP = 1,
+ Gmail = 2,
+ Outlook = 3,
+}
+
export interface MailAccount extends ObjectWithPermissions {
name: string
@@ -22,4 +28,10 @@ export interface MailAccount extends ObjectWithPermissions {
character_set?: string
is_token: boolean
+
+ account_type: MailAccountType
+
+ refresh_token?: string
+
+ expiration?: string // Date
}
diff --git a/src-ui/src/app/data/ui-settings.ts b/src-ui/src/app/data/ui-settings.ts
index 18f9ff130..d1e6bdcec 100644
--- a/src-ui/src/app/data/ui-settings.ts
+++ b/src-ui/src/app/data/ui-settings.ts
@@ -247,11 +247,11 @@ export const SETTINGS: UiSetting[] = [
{
key: SETTINGS_KEYS.GMAIL_OAUTH_URL,
type: 'string',
- default: '',
+ default: null,
},
{
key: SETTINGS_KEYS.OUTLOOK_OAUTH_URL,
type: 'string',
- default: '',
+ default: null,
},
]
diff --git a/src/documents/tests/test_migration_workflows.py b/src/documents/tests/test_migration_workflows.py
index 34e2afb5b..9a911d2e5 100644
--- a/src/documents/tests/test_migration_workflows.py
+++ b/src/documents/tests/test_migration_workflows.py
@@ -8,7 +8,7 @@ class TestMigrateWorkflow(TestMigrations):
dependencies = (
(
"paperless_mail",
- "0027_mailaccount_expiration_mailaccount_refresh_token",
+ "0027_mailaccount_expiration_mailaccount_account_type_and_more",
),
)
diff --git a/src/paperless_mail/mail.py b/src/paperless_mail/mail.py
index f2d428407..30498943d 100644
--- a/src/paperless_mail/mail.py
+++ b/src/paperless_mail/mail.py
@@ -431,7 +431,7 @@ def refresh_oauth_token(self, account: MailAccount) -> bool:
self.log.error(f"Account {account}: No refresh token available.")
return False
- if "gmail" in account.imap_server:
+ if account.account_type == MailAccount.MailAccountType.GMAIL:
url = "https://accounts.google.com/o/oauth2/token"
data = {
"client_id": settings.GMAIL_OAUTH_CLIENT_ID,
@@ -439,7 +439,7 @@ def refresh_oauth_token(self, account: MailAccount) -> bool:
"refresh_token": account.refresh_token,
"grant_type": "refresh_token",
}
- elif "outlook" in account.imap_server:
+ elif account.account_type == MailAccount.MailAccountType.OUTLOOK:
url = "https://login.microsoftonline.com/common/oauth2/v2.0/token"
data = {
"client_id": settings.OUTLOOK_OAUTH_CLIENT_ID,
diff --git a/src/paperless_mail/migrations/0027_mailaccount_expiration_mailaccount_refresh_token.py b/src/paperless_mail/migrations/0027_mailaccount_expiration_mailaccount_account_type_and_more.py
similarity index 72%
rename from src/paperless_mail/migrations/0027_mailaccount_expiration_mailaccount_refresh_token.py
rename to src/paperless_mail/migrations/0027_mailaccount_expiration_mailaccount_account_type_and_more.py
index 95e202fd1..8dd7fe618 100644
--- a/src/paperless_mail/migrations/0027_mailaccount_expiration_mailaccount_refresh_token.py
+++ b/src/paperless_mail/migrations/0027_mailaccount_expiration_mailaccount_account_type_and_more.py
@@ -1,4 +1,4 @@
-# Generated by Django 5.1.1 on 2024-10-05 07:42
+# Generated by Django 5.1.1 on 2024-10-05 17:12
from django.db import migrations
from django.db import models
@@ -20,6 +20,15 @@ class Migration(migrations.Migration):
verbose_name="expiration",
),
),
+ migrations.AddField(
+ model_name="mailaccount",
+ name="account_type",
+ field=models.PositiveIntegerField(
+ choices=[(1, "IMAP"), (2, "Gmail"), (3, "Outlook")],
+ default=1,
+ verbose_name="account type",
+ ),
+ ),
migrations.AddField(
model_name="mailaccount",
name="refresh_token",
diff --git a/src/paperless_mail/models.py b/src/paperless_mail/models.py
index 231b01659..0ffce38bf 100644
--- a/src/paperless_mail/models.py
+++ b/src/paperless_mail/models.py
@@ -15,6 +15,11 @@ class MailAccount(document_models.ModelWithOwner):
SSL = 2, _("Use SSL")
STARTTLS = 3, _("Use STARTTLS")
+ class MailAccountType(models.IntegerChoices):
+ IMAP = 1, _("IMAP")
+ GMAIL = 2, _("Gmail")
+ OUTLOOK = 3, _("Outlook")
+
name = models.CharField(_("name"), max_length=256, unique=True)
imap_server = models.CharField(_("IMAP server"), max_length=256)
@@ -51,6 +56,12 @@ class MailAccount(document_models.ModelWithOwner):
),
)
+ account_type = models.PositiveIntegerField(
+ _("account type"),
+ choices=MailAccountType.choices,
+ default=MailAccountType.IMAP,
+ )
+
refresh_token = models.CharField(
_("refresh token"),
max_length=2048,
diff --git a/src/paperless_mail/serialisers.py b/src/paperless_mail/serialisers.py
index 9237b47de..40dac8cc7 100644
--- a/src/paperless_mail/serialisers.py
+++ b/src/paperless_mail/serialisers.py
@@ -39,6 +39,9 @@ class MailAccountSerializer(OwnedObjectSerializer):
"user_can_change",
"permissions",
"set_permissions",
+ "account_type",
+ "refresh_token",
+ "expiration",
]
def update(self, instance, validated_data):
diff --git a/src/paperless_mail/views.py b/src/paperless_mail/views.py
index 2a84e04ea..2c3d9dd77 100644
--- a/src/paperless_mail/views.py
+++ b/src/paperless_mail/views.py
@@ -63,6 +63,7 @@ class MailAccountTestView(GenericAPIView):
):
existing_account = MailAccount.objects.get(pk=request.data["id"])
serializer.validated_data["password"] = existing_account.password
+ serializer.validated_data["account_type"] = existing_account.account_type
serializer.validated_data["refresh_token"] = existing_account.refresh_token
serializer.validated_data["expiration"] = existing_account.expiration
@@ -109,12 +110,14 @@ class OauthCallbackView(GenericAPIView):
if scope is not None and "google" in scope:
# Google
# Gmail setup guide: https://postmansmtp.com/how-to-configure-post-smtp-with-gmailgsuite-using-oauth/
+ account_type = MailAccount.AccountType.GMAIL
imap_server = "imap.gmail.com"
defaults = {
"name": f"Gmail OAuth {datetime.now()}",
"username": "",
"imap_security": MailAccount.ImapSecurity.SSL,
"imap_port": 993,
+ "account_type": account_type,
}
token_request_uri = "https://accounts.google.com/o/oauth2/token"
@@ -124,12 +127,14 @@ class OauthCallbackView(GenericAPIView):
elif scope is None:
# Outlook
# Outlok setup guide: https://medium.com/@manojkumardhakad/python-read-and-send-outlook-mail-using-oauth2-token-and-graph-api-53de606ecfa1
+ account_type = MailAccount.AccountType.OUTLOOK
imap_server = "outlook.office365.com"
defaults = {
"name": f"Outlook OAuth {datetime.now()}",
"username": "",
"imap_security": MailAccount.ImapSecurity.SSL,
"imap_port": 993,
+ "account_type": account_type,
}
token_request_uri = (