Skip to content

[patch] Implement IMAP NOTIFY #617

@shamefulCake1

Description

@shamefulCake1

Dear imapclient developers, the patch below implements a (rudimentary) support for IMAP NOTIFY (being able to IDLE events in many mailboxes and selecting interesting events)

From 8df794a20dfd4193208f7db1e864561bc79a8610 Mon Sep 17 00:00:00 2001
From: Lockywolf <>
Date: Thu, 11 Sep 2025 16:27:25 +0800
Subject: [PATCH] Add support for IMAP NOTIFY extension

---
 imapclient/imapclient.py | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/imapclient/imapclient.py b/imapclient/imapclient.py
index e86cefc..dd1a48c 100644
--- a/imapclient/imapclient.py
+++ b/imapclient/imapclient.py
@@ -76,6 +76,10 @@ if "ENABLE" not in imaplib.Commands:
 if "MOVE" not in imaplib.Commands:
     imaplib.Commands["MOVE"] = ("AUTH", "SELECTED")
 
+# ...and NOTIFY
+if "NOTIFY" not in imaplib.Commands:
+    imaplib.Commands["NOTIFY"] = ("AUTH", "SELECTED")
+
 # System flags
 DELETED = rb"\Deleted"
 SEEN = rb"\Seen"
@@ -884,6 +888,27 @@ class IMAPClient:
         tag = self._imap._command("NOOP")
         return self._consume_until_tagged_response(tag, "NOOP")
 
+    @require_capability("NOTIFY")
+    def notify(self, *args):
+        """Set up kinds of messages available through IDLE.
+        @args is passed without processing to the server,
+        is is usualy something like
+        "set (selected-delayed (MessageNew MessageExpunge FlagChange))\
+        (personal (MessageNew MessageExpunge FlagChange\
+        MailboxName SubscriptionChange))".
+        """
+        self._idle_tag = self._imap._command("NOTIFY", *args)
+        resp = self._imap._get_response()
+        if resp is None:
+            raise exceptions.IMAPClientError("Unexpected NOTIFY response: %s" % resp)
+        resp = resp.decode("ascii") # maybe this.decode_utf7()?
+        resp = resp.split(" ")
+        tag = resp[0]
+        okp = resp[1]
+        comment = resp[2]
+        if okp != "OK":
+            raise exceptions.IMAPClientError("NOTIFY response not OK: %s" % resp)
+
     @require_capability("IDLE")
     def idle(self):
         """Put the server into IDLE mode.
-- 
2.46.4

Please consider accepting it into master.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions