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
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.
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.