Skip to content

X-GM-EXT-1 Gmail Label Extension for Proton Bridge#450

Open
bolausson wants to merge 7 commits into
ProtonMail:devfrom
bolausson:dev
Open

X-GM-EXT-1 Gmail Label Extension for Proton Bridge#450
bolausson wants to merge 7 commits into
ProtonMail:devfrom
bolausson:dev

Conversation

@bolausson
Copy link
Copy Markdown

@bolausson bolausson commented Feb 22, 2026

Just to be clear - This was entirly coded with a LLM!

X-GM-EXT-1 Gmail Label Extension for Proton Bridge

Paperless-NGX uses Gmail's X-GM-LABELS IMAP extension to apply and query labels on emails after processing. Proton Bridge didn't support this, so we implemented it across Gluon and Bridge.

Gluon (IMAP server library)

  • STORE X-GM-LABELS — Parses STORE +X-GM-LABELS ("Paperless") / -X-GM-LABELS commands, routes them through a new SetGmailLabels connector interface to the Bridge backend. Added X-GM-EXT-1 capability advertisement.
  • FETCH X-GM-LABELS — Parses FETCH (X-GM-LABELS) as a fetch attribute, calls GetGmailLabels on the connector, returns labels in Gmail format: X-GM-LABELS ("Paperless" "Notifications").
  • SEARCH X-GM-LABELS — Parses X-GM-LABELS as a search key so clients can filter messages by label (e.g. NOT X-GM-LABELS "Paperless"). The search operation calls GetGmailLabels on the connector for each candidate message with case-insensitive matching.
  • Pre-auth capability fix — Moved X-GM-EXT-1 to the pre-auth capability list. Python's imaplib checks capabilities before LOGIN and never re-reads them, so clients like Paperless-NGX weren't detecting support.

Proton Bridge

  • STORE backendMarkMessagesWithGmailLabels maps label names to Proton label IDs (auto-creating if needed), then calls LabelMessages/UnlabelMessages API. Messages stay in INBOX — labels are applied without moving.
  • FETCH/SEARCH backendGetGmailLabels calls GetMessage API to get LabelIDs, maps them back to names via the shared label cache, filtering for LabelTypeLabel only. Used by both FETCH and SEARCH operations.

Tests

telnet localhost 1143
a LOGIN <some@example.com> <password>
a LIST "" "Labels/%"
a SELECT "INBOX"
a UID SEARCH UNSEEN
a UID FETCH <UID> (BODY.PEEK[HEADER.FIELDS (SUBJECT)])
a UID FETCH <UID> (X-GM-LABELS)
a UID STORE <UID> +X-GM-LABELS ("__paperless_test_label__")
a UID FETCH <UID> (X-GM-LABELS)
a UID SEARCH X-GM-LABELS "__paperless_test_label__"
# a UID SEARCH NOT X-GM-LABELS "__paperless_test_label__"
a SELECT "Labels/__paperless_test_label__"
a UID SEARCH UNSEEN
a SELECT "INBOX"
a UID STORE <UID> -X-GM-LABELS ("__paperless_test_label__")
a UID FETCH <UID> (X-GM-LABELS)
a DELETE "Labels/__paperless_test_label__"
a LIST "" "Labels/%"
a LOGOUT
$ telnet localhost 1143
Trying ::1...
Connected to localhost.
Escape character is '^]'.
* OK [CAPABILITY AUTH=PLAIN ID IDLE IMAP4rev1 MOVE STARTTLS UIDPLUS UNSELECT X-GM-EXT-1] Proton Mail Bridge 03.22.00 - gluon session ID 2
a LOGIN <some@example.com> <password>
a OK [CAPABILITY AUTH=PLAIN ID IDLE IMAP4rev1 MOVE STARTTLS UIDPLUS UNSELECT X-GM-EXT-1] Logged in
a LIST "" "Labels/%"
* LIST (\Unmarked) "/" "Labels/Follow up"
* LIST (\Marked) "/" "Labels/Important"
a OK LIST
a SELECT "INBOX"
* FLAGS ($Forwarded Forwarded \Deleted \Flagged \Seen)
* 26487 EXISTS
* 0 RECENT
* OK [PERMANENTFLAGS ($Forwarded Forwarded \Deleted \Flagged \Seen)] Flags permitted
* OK [UIDNEXT 26545] Predicted next UID
* OK [UIDVALIDITY 96066389] UIDs valid
* OK [UNSEEN 26486] Unseen messages
a OK [READ-WRITE] SELECT
a UID SEARCH UNSEEN
* SEARCH 26543 26544
a OK command completed in 19322 microsec.
a UID FETCH 26543 (BODY.PEEK[HEADER.FIELDS (SUBJECT)])
* 26486 FETCH (BODY[HEADER.FIELDS (SUBJECT)] {59}
Subject: Proton Bridge with X-GM-EXT-1 support - Test 4

 UID 26543)
* 26487 FETCH (FLAGS (\Seen))
a OK [EXPUNGEISSUED] command completed in 1382 microsec.
a UID FETCH 26543 (X-GM-LABELS)
* 26486 FETCH (X-GM-LABELS ("Bjoern") UID 26543)
a OK [EXPUNGEISSUED] command completed in 311935 microsec.
a UID STORE 26543 +X-GM-LABELS ("__paperless_test_label__")
a OK command completed in 679973 microsec.
a UID FETCH 26543 (X-GM-LABELS)
* 26486 FETCH (X-GM-LABELS ("Bjoern" "__paperless_test_label__") UID 26543)
a OK [EXPUNGEISSUED] command completed in 321493 microsec.
a UID SEARCH X-GM-LABELS "__paperless_test_label__"
* SEARCH 26543
a OK [EXPUNGEISSUED] command completed in 18271 microsec.
a SELECT "Labels/__paperless_test_label__"
* FLAGS ($Forwarded Forwarded \Deleted \Flagged \Seen)
* 1 EXISTS
* 1 RECENT
* OK [PERMANENTFLAGS ($Forwarded Forwarded \Deleted \Flagged \Seen)] Flags permitted
* OK [UIDNEXT 2] Predicted next UID
* OK [UIDVALIDITY 96519480] UIDs valid
* OK [UNSEEN 1] Unseen messages
a OK [READ-WRITE] SELECT
a UID SEARCH UNSEEN
* SEARCH 1
a OK command completed in 264 microsec.
a SELECT "INBOX"
* FLAGS ($Forwarded Forwarded \Deleted \Flagged \Seen)
* 26486 EXISTS
* 0 RECENT
* OK [PERMANENTFLAGS ($Forwarded Forwarded \Deleted \Flagged \Seen)] Flags permitted
* OK [UIDNEXT 26545] Predicted next UID
* OK [UIDVALIDITY 96066389] UIDs valid
* OK [UNSEEN 26486] Unseen messages
a OK [READ-WRITE] SELECT
a UID STORE 26543 -X-GM-LABELS ("__paperless_test_label__")
a OK command completed in 400725 microsec.
a UID FETCH 26543 (X-GM-LABELS)
* 26486 FETCH (X-GM-LABELS ("Bjoern") UID 26543)
a OK command completed in 284999 microsec.
a DELETE "Labels/__paperless_test_label__"
a OK DELETE
a LIST "" "Labels/%"
* LIST (\Unmarked) "/" "Labels/Follow up"
* LIST (\Marked) "/" "Labels/Important"
a OK LIST
a LOGOUT
* BYE
a OK LOGOUT
Connection closed by foreign host.

Paperless-ngx logs:

paperless.log

[2026-02-22 04:21:44,001] [DEBUG] [paperless.tasks] Executing plugin ConsumerPreflightPlugin
[2026-02-22 04:21:44,014] [INFO] [paperless.tasks] ConsumerPreflightPlugin completed with no message
[2026-02-22 04:21:44,014] [DEBUG] [paperless.tasks] Skipping plugin CollatePlugin
[2026-02-22 04:21:44,017] [DEBUG] [paperless.tasks] Skipping plugin BarcodePlugin
[2026-02-22 04:21:44,017] [DEBUG] [paperless.tasks] Executing plugin WorkflowTriggerPlugin
[2026-02-22 04:21:44,101] [INFO] [paperless.matching] Document did not match Workflow: Import-Bjoern
[2026-02-22 04:21:44,101] [DEBUG] [paperless.matching] ("Document source MailFetch not in ['ApiUpload']",)
[2026-02-22 04:21:44,101] [INFO] [paperless.matching] Document matched WorkflowTrigger 3 from Workflow: Import-Bjoern
[2026-02-22 04:21:44,149] [INFO] [paperless.matching] Document did not match Workflow: Import-Other
[2026-02-22 04:21:44,150] [DEBUG] [paperless.matching] ('Document path /tmp/paperless/paperless-mail-h3aukvuh/Support_Case_Analysis_Report.pdf does not match */consume/Other/*',)
[2026-02-22 04:21:44,150] [INFO] [paperless.tasks] WorkflowTriggerPlugin completed with: Applying WorkflowAction 1 from Workflow: Import-Bjoern
[2026-02-22 04:21:44,150] [DEBUG] [paperless.tasks] Executing plugin ConsumeTaskPlugin
[2026-02-22 04:21:44,150] [INFO] [paperless.consumer] Consuming Support_Case_Analysis_Report.pdf
[2026-02-22 04:21:44,152] [DEBUG] [paperless.consumer] Detected mime type: application/pdf
[2026-02-22 04:21:44,160] [DEBUG] [paperless.consumer] Parser: RasterisedDocumentParser
[2026-02-22 04:21:44,165] [DEBUG] [paperless.consumer] Parsing Support_Case_Analysis_Report.pdf...
[2026-02-22 04:21:44,213] [INFO] [paperless.parsing.tesseract] pdftotext exited 0
[2026-02-22 04:21:44,587] [DEBUG] [paperless.parsing.tesseract] Calling OCRmyPDF with args: {'input_file': PosixPath('/tmp/paperless/paperless-ngxjzpdrcty/Support_Case_Analysis_Report.pdf'), 'output_file': PosixPath('/tmp/paperless/paperless-xw3sekya/archive.pdf'), 'use_threads': True, 'jobs': 4, 'language': 'deu', 'output_type': 'pdfa', 'progress_bar': False, 'color_conversion_strategy': 'RGB', 'skip_text': True, 'clean': True, 'deskew': True, 'rotate_pages': True, 'rotate_pages_threshold': 12.0, 'sidecar': PosixPath('/tmp/paperless/paperless-xw3sekya/sidecar.txt'), 'invalidate_digital_signatures': True}
[2026-02-22 04:21:44,935] [INFO] [ocrmypdf._pipelines.ocr] Start processing 2 pages concurrently
[2026-02-22 04:21:44,936] [INFO] [ocrmypdf._pipeline] skipping all processing on this page
[2026-02-22 04:21:44,936] [INFO] [ocrmypdf._pipeline] skipping all processing on this page
[2026-02-22 04:21:44,938] [INFO] [ocrmypdf._pipelines.ocr] Postprocessing...
[2026-02-22 04:21:45,223] [INFO] [ocrmypdf._pipeline] Image optimization ratio: 1.00 savings: 0.0%
[2026-02-22 04:21:45,223] [INFO] [ocrmypdf._pipeline] Total file size ratio: 0.05 savings: -2059.4%
[2026-02-22 04:21:45,225] [INFO] [ocrmypdf._pipelines._common] Output file is a PDF/A-2b (as expected)
[2026-02-22 04:21:45,230] [DEBUG] [paperless.parsing.tesseract] Incomplete sidecar file: discarding.
[2026-02-22 04:21:45,307] [INFO] [paperless.parsing.tesseract] pdftotext exited 0
[2026-02-22 04:21:45,308] [DEBUG] [paperless.consumer] Generating thumbnail for Support_Case_Analysis_Report.pdf...
[2026-02-22 04:21:45,312] [DEBUG] [paperless.parsing] Execute: convert -density 300 -scale 500x5000> -alpha remove -strip -auto-orient -define pdf:use-cropbox=true /tmp/paperless/paperless-xw3sekya/archive.pdf[0] /tmp/paperless/paperless-xw3sekya/convert.webp
[2026-02-22 04:21:46,736] [INFO] [paperless.parsing] convert exited 0
[2026-02-22 04:21:50,063] [DEBUG] [paperless.consumer] Saving record to database
[2026-02-22 04:21:50,063] [DEBUG] [paperless.consumer] Creation date from st_mtime: 2026-02-22 04:21:43.368249+01:00
[2026-02-22 04:21:50,065] [DEBUG] [paperless.templating] Parsing Workflow Jinja template: Support_Case_Analysis_Report
[2026-02-22 04:21:51,333] [INFO] [paperless.handlers] Assigning correspondent Sonstige to 2026-02-22T04:21:43.368249+01:00 Support_Case_Analysis_Report
[2026-02-22 04:21:51,346] [INFO] [paperless.handlers] Assigning document type Information to 2026-02-22T04:21:43.368249+01:00 Sonstige Support_Case_Analysis_Report
[2026-02-22 04:21:51,365] [INFO] [paperless.handlers] Tagging "2026-02-22T04:21:43.368249+01:00 Sonstige Support_Case_Analysis_Report" with "Depot, Versicherung"
[2026-02-22 04:21:51,496] [DEBUG] [paperless.index] Index updated for document 7160.
[2026-02-22 04:21:51,733] [DEBUG] [paperless.consumer] Deleting original file /tmp/paperless/paperless-mail-h3aukvuh/Support_Case_Analysis_Report.pdf
[2026-02-22 04:21:51,734] [DEBUG] [paperless.consumer] Deleting working copy /tmp/paperless/paperless-ngxjzpdrcty/Support_Case_Analysis_Report.pdf
[2026-02-22 04:21:51,740] [DEBUG] [paperless.parsing.tesseract] Deleting directory /tmp/paperless/paperless-xw3sekya
[2026-02-22 04:21:51,741] [INFO] [paperless.consumer] Document 2026-02-22 Sonstige Support_Case_Analysis_Report consumption finished
[2026-02-22 04:21:51,746] [INFO] [paperless.tasks] ConsumeTaskPlugin completed with: Success. New document id 7160 created

mail.log

[2026-02-22 04:21:40,536] [DEBUG] [paperless_mail] Skipping mail preprocessor MailMessageDecryptor
[2026-02-22 04:21:40,536] [DEBUG] [paperless_mail] Processing mail account Proton
[2026-02-22 04:21:40,601] [DEBUG] [paperless_mail] GMAIL Label Support: True
[2026-02-22 04:21:40,602] [DEBUG] [paperless_mail] AUTH=PLAIN Support: True
[2026-02-22 04:21:41,069] [DEBUG] [paperless_mail] Account Proton: Processing 1 rule(s)
[2026-02-22 04:21:41,072] [DEBUG] [paperless_mail] Rule Proton.Bjoern-PDF: Selecting folder INBOX
[2026-02-22 04:21:41,536] [DEBUG] [paperless_mail] Rule Proton.Bjoern-PDF: Searching folder with criteria ((NOT (X-GM-LABELS "Paperless") UNKEYWORD Paperless) SINCE 23-Jan-2026)
[2026-02-22 04:21:43,363] [DEBUG] [paperless_mail] Rule Proton.Bjoern-PDF: Processing mail Fwd: Proton Bridge with X-GM-EXT-1 support - Test 4 from <mail>@gmail.com with 1 attachment(s)
[2026-02-22 04:21:43,371] [INFO] [paperless_mail] Rule Proton.Bjoern-PDF: Consuming attachment Support_Case_Analysis_Report.pdf from mail Fwd: Proton Bridge with X-GM-EXT-1 support - Test 4 from <mail>@gmail.com
[2026-02-22 04:21:43,415] [DEBUG] [paperless_mail] Rule Proton.Bjoern-PDF: Processed 117 matching mail(s)

celery.log

[2026-02-22 04:21:43,416] [INFO] [celery.worker.strategy] Task documents.tasks.consume_file[ecaf3755-6e0c-4675-b481-4a7b9100368a] received
[2026-02-22 04:21:43,429] [INFO] [celery.app.trace] Task paperless_mail.tasks.process_mail_accounts[576a8f56-0d12-4d7f-beef-c4b5d6e593fd] succeeded in 2.9539029439911246s: 'Added 1 document(s).'
[2026-02-22 04:21:43,455] [DEBUG] [celery.pool] TaskPool: Apply <function fast_trace_task at 0xffff8fc1fec0> (args:('documents.tasks.consume_file', 'ecaf3755-6e0c-4675-b481-4a7b9100368a', {'lang': 'py', 'task': 'documents.tasks.consume_file', 'id': 'ecaf3755-6e0c-4675-b481-4a7b9100368a', 'shadow': None, 'eta': None, 'expires': None, 'group': 'ce2b51ce-2378-486a-b713-a485338694e0', 'group_index': 0, 'retries': 0, 'timelimit': [None, None], 'root_id': '576a8f56-0d12-4d7f-beef-c4b5d6e593fd', 'parent_id': '576a8f56-0d12-4d7f-beef-c4b5d6e593fd', 'argsrepr': "(ConsumableDocument(source=<DocumentSource.MailFetch: 3>, original_file=PosixPath('/tmp/paperless/paperless-mail-h3aukvuh/Support_Case_Analysis_Report.pdf'), original_path=None, mailrule_id=5, mime_type='application/pdf'), DocumentMetadataOverrides(filename='Support_Case_Analysis_Report.pdf', title='Support_Case_Analysis_Report', correspondent_id=None, document_type_id=None, tag_ids=[23, 1], storage_path_id=None, created=None, asn=None, owner_id=3, view_users=None, view_groups=None, change_users=None, change_groups=None, custom_fields=None))", 'kwargsrepr': '{}',... kwargs:{})
[2026-02-22 04:21:51,770] [INFO] [celery.app.trace] Task documents.tasks.consume_file[ecaf3755-6e0c-4675-b481-4a7b9100368a] succeeded in 7.831161381996935s: 'Success. New document id 7160 created'
[2026-02-22 04:21:51,772] [INFO] [celery.worker.strategy] Task paperless_mail.mail.apply_mail_action[9a3c9d52-dca5-4202-a7bd-df514e19c837] received
[2026-02-22 04:21:51,773] [DEBUG] [celery.pool] TaskPool: Apply <function fast_trace_task at 0xffff8fc1fec0> (args:('paperless_mail.mail.apply_mail_action', '9a3c9d52-dca5-4202-a7bd-df514e19c837', {'lang': 'py', 'task': 'paperless_mail.mail.apply_mail_action', 'id': '9a3c9d52-dca5-4202-a7bd-df514e19c837', 'shadow': None, 'eta': None, 'expires': None, 'group': None, 'group_index': None, 'retries': 0, 'timelimit': [None, None], 'root_id': '576a8f56-0d12-4d7f-beef-c4b5d6e593fd', 'parent_id': 'ecaf3755-6e0c-4675-b481-4a7b9100368a', 'argsrepr': "(['Success. New document id 7160 created'],)", 'kwargsrepr': "{'rule_id': 5, 'message_uid': '26546', 'message_subject': 'Fwd: Proton Bridge with X-GM-EXT-1 support - Test 4', 'message_date': datetime.datetime(2026, 2, 22, 4, 21, 9, tzinfo=datetime.timezone(datetime.timedelta(seconds=3600)))}", 'origin': 'gen3817@edd8936e3312', 'ignore_result': False, 'replaced_task_nesting': 0, 'stamped_headers': None, 'stamps': {}, 'properties': {'correlation_id': '9a3c9d52-dca5-4202-a7bd-df514e19c837', 'reply_to': '31e8b107-1a2b-308d-af48-f397b6cd116d', 'delivery_mode': 2, 'delivery_info':... kwargs:{})
[2026-02-22 04:21:54,379] [INFO] [celery.app.trace] Task paperless_mail.mail.apply_mail_action[9a3c9d52-dca5-4202-a7bd-df514e19c837] succeeded in 1.243677235004725s: None
image

@Mullayam
Copy link
Copy Markdown

@bolausson any plan to add QUOTA COMMAND

@bolausson
Copy link
Copy Markdown
Author

@bolausson any plan to add QUOTA COMMAND

I don't see why paperless-ngx would need that.

The sole purpose of this patch is to make the bride compatible with the way paperless-ngx tags (applies labels) to eMails.

Cheers,
Bjoern

B. Olausson added 7 commits May 17, 2026 00:59
Implement the X-GM-EXT-1 IMAP extension to support Gmail-style label
operations via STORE X-GM-LABELS commands. This allows IMAP clients like
Paperless-NGX to apply/remove labels without moving messages between
folders.

Changes:
- Advertise X-GM-EXT-1 capability in IMAP sessions
- Extend STORE command parser to handle X-GM-LABELS data item
- Add StoreGmailLabels method to state Mailbox
- Add SetGmailLabels to connector interface
- Route Gmail label STORE through connector to backend
Extend the FETCH command to recognize X-GM-LABELS as a fetch attribute,
allowing IMAP clients to read Gmail-style labels on messages. This
complements the existing STORE X-GM-LABELS support.

Changes:
- Parse X-GM-LABELS in FETCH attribute handler
- Add GetGmailLabels to connector interface for label retrieval
- Format response as X-GM-LABELS ("Label1" "Label2")
Python's imaplib sends CAPABILITY before LOGIN and never re-reads
capabilities after authentication. Moving X-GM-EXT-1 to the pre-auth
capability list so clients like paperless-ngx can detect Gmail label
support.
Parse X-GM-LABELS as a search key so clients like paperless-ngx can
filter messages by Gmail-style label (e.g. NOT X-GM-LABELS "Paperless").
The search operation calls GetGmailLabels on the connector for each
candidate message.
Replace per-message Proton API calls with local DB queries. The search
now resolves the label to a mailbox ID via the connector, queries the
local DB for all messages in that mailbox, and builds an in-memory set
for O(1) per-message lookups. This turns N API calls into 2 local
queries.
Python's imaplib sends labels without wrapping in parentheses:
  UID STORE 123 +X-GM-LABELS Paperless
The parser previously required parenthesized form only:
  UID STORE 123 +X-GM-LABELS (Paperless)
Now both forms are accepted.
Covers the previously-untested X-GM-LABELS extension surface:

- imap/command: STORE/FETCH/SEARCH parser tests, incl. the bare-label
  (Python imaplib) form and NOT X-GM-LABELS — the exact wire forms
  Paperless-NGX emits.
- internal/response: itemGmailLabels formatting (empty/quoting/spaces).
- connector dummy: store labels as non-exclusive label mailboxes so
  STORE/FETCH/SEARCH round-trip end-to-end without touching folder
  membership; previous methods were no-op stubs.
- tests: STORE -> FETCH -> STORE remove round trip, multi-message,
  labels with spaces, and SEARCH / NOT X-GM-LABELS (the Paperless
  dedupe query).
- Fix TestCapability/TestCapabilityAuthenticateDisabled/login/
  authenticate which now must advertise X-GM-EXT-1 (sorted last);
  these were broken when the feature commit started advertising it.
@bolausson bolausson force-pushed the dev branch 2 times, most recently from 1974e75 to fb4bd2d Compare May 17, 2026 00:48
bolausson pushed a commit to bolausson/proton-bridge that referenced this pull request May 17, 2026
Point the gluon dependency at the gluon module that carries the
X-GM-EXT-1 server support (depends on ProtonMail/gluon#450) and pin
golang.org/x/exp to the revision internal/usertypes expects so the
module graph resolves and builds.
@bolausson
Copy link
Copy Markdown
Author

This PR adds the X-GM-EXT-1 Gmail label extension (FETCH / STORE / SEARCH X-GM-LABELS) to Gluon.

Motivation: Paperless-NGX tags processed e-mails over IMAP using Gmail-style labels (STORE +X-GM-LABELS) and de-duplicates with SEARCH NOT X-GM-LABELS. Proton Bridge advertises no equivalent today, so Paperless-NGX's tag action silently fails against Bridge. This implements the server side (the connector side is ProtonMail/proton-bridge#521, which depends on this PR).

Rebased on current dev (mergeable, no conflicts) and self-contained — reviewable/mergeable independently of #521. Includes parser unit tests, end-to-end STORE/FETCH/SEARCH round-trip integration tests via the dummy connector, and the capability-advertisement test updates.

@Mullayam
Copy link
Copy Markdown

@bolausson can I use it explicitly
Like in any imap.cleint or it need specificly protonmail bridge or desktop version

@bolausson
Copy link
Copy Markdown
Author

@bolausson can I use it explicitly Like in any imap.cleint or it need specificly protonmail bridge or desktop version

X-GM-EXT-1 is a server-side IMAP capability, so it depends on what your IMAP client connects to, not the client itself!

Server:
You need Proton Bridge built from these changes (gluon#450 + proton-bridge#521). Official/released Proton Bridge does not include this yet! My PRs aren't merged, so you'd have to build Bridge + gluon yourself from the branches. Note this is Proton Bridge (the local IMAP/SMTP gateway for paid plans), not the Proton Mail desktop app!
The desktop app has no IMAP server as far as I know (I am not using it).

Client:
Any IMAP client can use it, but only if the client actually sends STORE/FETCH/SEARCH X-GM-LABELS. Most clients don't.
This work targets Paperless-NGX compatibility, which does. A generic client like e.g. Thunderbird might not expose label tagging through it (guessing here since the focus is on Paperless-NGX and I didn't look into other use cases)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants