Getting email message after IMAP IDLE command exis

2019-06-13 01:46发布

问题:

Is it safe to use the total number of messages in the exists response as a way to then get the uid?

7.3.1. EXISTS Response

Contents: none

  The EXISTS response reports the number of messages in the mailbox.
  This response occurs as a result of a SELECT or EXAMINE command,
  and if the size of the mailbox changes (e.g., new messages).

  The update from the EXISTS response MUST be recorded by the
  client.

Example: S: * 23 EXISTS

In app output

2013-02-02 01:24:42-0500 [IMAP4Client (TLSMemoryBIOProtocol),client] C: '0005 IDLE'
2013-02-02 01:24:42-0500 [IMAP4Client (TLSMemoryBIOProtocol),client] S: '+ idling'
2013-02-02 01:25:17-0500 [IMAP4Client (TLSMemoryBIOProtocol),client] S: '* 6 EXISTS'
2013-02-02 01:25:47-0500 [IMAP4Client (TLSMemoryBIOProtocol),client] S: '* 7 EXISTS'

Modified version of twisted's IMAP Client Protocol

class IMAP4Client(imap4.IMAP4Client):
    """
        A client with callbacks for greeting messages from an IMAP server and new messages.
        """
    greetDeferred = None

    def __init__(self, *args, **kw):

        # is IDLE active
        self.idle_active = False
        # do we want to support IDLE
        self.idle_enabled = False
        imap4.IMAP4Client.__init__(self, *args, **kw)

    def serverGreeting(self, caps):
        self.serverCapabilities = caps
        if self.greetDeferred is not None:
            d, self.greetDeferred = self.greetDeferred, None
            d.callback(self)

    def enable_IDLE(self):
        print "Enabling Idle...."
        self.idle_enabled = True
        if self.queued == []:# if there is no current command
            # issue the idle command
            cmd = Command("IDLE", continuation = self.idle_continuation)
            d = self.sendCommand(cmd)
            # THEN mark it active NOT BEFORE as, if IDLE is active when a command is sent (such as the above IDLE command) it stops IDLE by sending the DONE line
            self.idle_active = True
            d.addCallback(self.idle_done)
            return d
        else:
            pass # IDLE will be enables when queued commands in waiting are done

    def lineReceived(self, line):
        print "S: %s" % str(repr(line))
        return imap4.IMAP4Client.lineReceived(self, line)

    def sendLine(self, line):
        print "C: %s" % str(repr(line))
        return imap4.IMAP4Client.sendLine(self, line)

    def idle_continuation(self, *args, **kw):
        pass# ignore for now

    def sendCommand(self, cmd):
        cmd.defer = Deferred()

        # checks to see if IDLE command can be enabled when this command is done
        cmd.defer.addCallback(self.command_done)

        if self.idle_active: # if we are waiting for IDLE
            self.sendLine("DONE")
            # append it to the queue and wait for the idle deferred callback
            self.queued.append(cmd)
            return cmd.defer

        if self.waiting:
            self.queued.append(cmd)
            return cmd.defer

        t = self.makeTag()
        self.tags[t] = cmd
        self.sendLine(cmd.format(t))
        self.waiting = t
        self._lastCmd = cmd
        return cmd.defer

    def command_done(self, result):
        print "A command was finished"
        print "Waiting %s" % self.waiting
        print self.queued
        print "IDLE Enabled %s" % self.idle_enabled

        # cannot use if not self.waiting so check if the command queue is empty 
        empty_queue = (self.queued == [])

        if empty_queue and self.idle_enabled: # yay no commands enable IDLE
            print "Enabling idle"
            self.idle_active = True
            # issue the command
            self.idle_active = True
            cmd = Command("IDLE", continuation = self.idle_continuation)
            d = self.sendCommand(cmd)
            d.addCallback(self.idle_done)
            return d
        return result

    def idle_done(self, result):
        print "IDLE Done"
        self.idle_active = False
        # twisted's own handling of the command queue should handle sending the next command
        # so there is no need to grab the next command as when the OK Response after DONE 
        # trigger it

回答1:

Uh... "safe"? If you're not controlling a nuclear power plant, then probably. Here's a rule of thumb: will someone be injured when your software fails? If not, whatever it does is safe.

How about "correct"? No, it is incorrect, because the EXISTS response tells you how many messages exist in the mailbox. It does not tell you the UID of any of them.



回答2:

I am of the opinion that using the number of messages in the mailbox is 'safe enough' provided you act immediately and are ready to fall back to a SEARCH if the mailbox is suddenly different when you need to display it (perhaps a message was removed by another client). This is really only applicable for non-destructive operations so approach EXPUNGE with some caution if you really need to use it.