IMAP is more comprehensive and powerful. Twisted is a framework for compiling network applications using python. It is designed to be multitasking and runs through the entire library using asynchronous I/O.
1. Introduction to IMAP in twisted
Most network client libraries, such as poplib and imaplib, work in the same way. You need to write the program that calls these libraries. The library calls the server and your code (that is, the function does not return) until a result is obtained from the network.
Twisted returns this method in its header. When you access the network, you notify twisted of the function to pass the result to, and your real call will return immediately. When you get a result on the network, your function will be called, and the result will be used as a parameter. Twisted developers call this situation "Don't call us, we will call you". This mode is also applicable to event-based programs. A function called by a result is also called a callback function.
2. Understand the basics of twisted
#!/usr/bin/env pythonfrom twisted.internet import defer, reactor, protocolfrom twisted.mail.imap4 import IMAP4Clientimport sysclass IMAPClient(IMAP4Client): def connectionMade(self): print ‘I have successfully connected to the server‘ d=self.getCapabilities() d.addCallback(self.gotcapabilities) def gotcapabilities(self, caps): if caps==None: print ‘Server did not return a capability list.‘ else: for key, value in caps.items(): print ‘%s: %s‘ %(key, str(value)) self.logout() reactor.stop() class IMAPFactory(protocol.ClientFactory): protocol=IMAPClient def clientConnectionFailed(self, connector, reason): print ‘Client connection failed:‘, reason reactor.stop() reactor.connectTCP(sys.argv[1], 143, IMAPFactory())reactor.run()
Most twisted client programs basically have two classes: a protocol class (imapclient in this example) and a factory class (imapfactory ). Factory class management and server connection, protocol class implementation and server session. In this example, when the program starts, create a network connection. The default IMAP port is 143, and an imapfactory object is also passed. Reactor. Run () in the last line of the program (). In twisted, the reactor is used to process network events. It is returned only when the reactor. Stop () is called and the call to reactor. Run () is returned. After a connection is established, the reactor calls connectionmade ().
Getcapabilities () can return a series of optional features supported by the IMAP server. It returns an object called deferred, which is the core of the event-based model in twisted. It notifies twisted of what to do when receiving a reply. Once a deferred object is received, the program calls addcallback on the object, which notifies the reactor of the function to be called after receiving the response. Here, gotcapabilities is the only method that does not overload the base class method. No parentheses are used when calling gotcapabilities because you do not want to call gotcapabilities () when calling addcallback (). Instead, you only pass the function to addcallback (), and let twisted call it later. The gotcapabilities function receives a parameter from twisted, which is the result of your request to getcapabilities. Log out and stop the reactor. The program ends.
1. Logon:
#!/usr/bin/env python#-*-coding:utf-8-*-from twisted.internet import defer, reactor, protocolfrom twisted.mail.imap4 import IMAP4Clientimport sys, getpassclass IMAPClient(IMAP4Client): def connectionMade(self): print ‘I have successfully connected to the server‘ IMAPLogin(self) print ‘connectionMade returning‘ class IMAPFactory(protocol.ClientFactory): protocol=IMAPClient def __init__(self, username, password): self.username=username self.password=password def clientConnectionFailed(self, connector, reason): print ‘Client connection failed:‘, reason reactor.stop() class IMAPLogin(object): def __init__(self, proto): self.proto=proto self.factory=proto.factory d=self.proto.login(self.factory.username, self.factory.password) d.addCallback(self.loggedin) d.addCallback(self.stopreactor) print "IMAPLogic.__init__returning" def loggedin(self, data): print "I‘m logged in" return self.logout() def logout(self): print ‘Logging out‘ d=self.proto.logout() return d def stopreactor(self, data=None): print ‘Stopping reactor‘ reactor.stop() password=getpass.getpass("Enter password for %s on %s: " %(sys.argv[2], sys.argv[1])) reactor.connectTCP(sys.argv[1], 143, IMAPFactory(sys.argv[2], password))reactor.run()
The program first connects the reactor and then the reactor runs run. This will call the connectionmade method in the protol class. Connecitonmade initializes an imaplogic instance. When initializing an imaplogic instance, The protol class calls the login method to generate a deferred Object D, and then adds two callback functions. A deferred (deferred) object. After obtaining the result from the network, it takes the result as a parameter and calls the callback function. In this example, when a user logs on, twisted obtains the response from the network and calls the loggedin function as a parameter. The loggedin function drops the yo function logout, And the logout function returns the deferred object generated by the logout method of the proto class. Because this object does not have the callback function, it is directly passed to the next Callback Function of the first deferred object, that is, stopreactor ().
We can simply think that the deferred objects are passed between these functions... (Personal understanding)
2. handle errors
Twisted cannot generate exceptions, but there is a concept of calling errback, which is similar to callback, but it is called only when an error occurs.
#!/usr/bin/env pythonfrom twisted.internet import defer, reactor, protocolfrom twisted.mail.imap4 import IMAP4Clientimport sys, getpassclass IMAPClient(IMAP4Client): def connectionMade(self): print ‘I have successfully connected to the server‘ IMAPLogic(self) print ‘connectionMade returning‘ class IMAPFactory(protocol.ClientFactory): protocol=IMAPClient def __init__(self, username, password): self.username=username self.password=password def clientConnectionFailed(self, connector, reason): print ‘Client connection failed:‘, reason reactor.stop() class IMAPLogic(object): def __init__(self, proto): self.proto=proto self.factory=proto.factory self.logintries=1 d=self.login() d.addCallback(self.loggedin) d.addErrback(self.loginerror) d.addCallback(self.logout) d.addCallback(self.stopreactor) d.addErrback(self.errorhappened) print ‘IMAPLogic.__init__ returning‘ def login(self): print ‘Logging in..‘ return self.proto.login(self.factory.username, self.factory.password) def loggedin(self, data): print "I‘m logged in" def logout(self, data=None): d=self.proto.logout() return d def stopreactor(self, data=None): print ‘Stopping reactor‘ reactor.stop() def errorhappened(self, failure): print ‘An error occured:‘, failure.getErrorMessage() print ‘Because of the error , I am logging out and stopping reactor...‘ d=self.logout() d.addBoth(self.stopreactor) return failure def loginerror(self, failure): print ‘Your login failed (attempt %d).‘ % self.logintries if self.logintries>=3: print ‘You have triedto log in three times;I am giving up‘ return failure self.logintries+=1 sys.stdout.write(‘New username: ‘) self.factory.username=sys.stdin().readline().strip().encode(‘utf-8‘) self.factory.password=getpass.getpass("New password: ").encode(‘utf-8‘) d=self.login() d.addErrback(self.loginerror) return d password=getpass.getpass("Enter password for %s on %s: " % (sys.argv[2], sys.argv[1])).encode(‘utf-8‘)reactor.connectTCP(sys.argv[1], 143, IMAPFactory(sys.argv[2].encode(‘utf-8‘), password))reactor.run()
3. Basic download
Download the entire Email:
#!/usr/bin/env pythonfrom twisted.internet import defer,reactor,protocolfrom twisted.mail.imap4 import IMAP4Clientimport sys, getpass, emailclass IMAPClient(IMAP4Client): def connectionMade(self): IMAPLogin(self)class IMAPFactory(protocol.ClientFactory): protocol=IMAPClient def __init__(self, username, password): self.username=username self.password=password def clientConnectionFailed(self, connector, reason): print ‘Client connnection failed:‘, reason reactor.stop() class IMAPLogin(object): def __init__(self, proto): self.proto=proto self.factory=proto.factory d=self.proto.login(self.factory.username, self.factory.password) d.addCallback(lambda x: self.proto.examine(‘INBOX‘)) d.addCallback(lambda x: self.proto.fetchSpecific(‘1:*‘, peek=1)) d.addCallback(self.gotmessages) d.addCallback(self.logout) d.addCallback(self.stopreactor) d.addErrback(self.errorhappened) def gotmessages(self, data): destfd=open(sys.argv[3], ‘at‘) for key, value in data.items(): print ‘Writing message‘, key msg=email.message_from_string(value[0][2]) destfd.write(msg.as_string(unixfrom=1)) destfd.write(‘\n‘) destfd.close() def logout(self, data=None): return self.proto.logout() def stopreactor(self, data=None): reactor.stop() def errorhappened(self, failure): print ‘An error occured:‘, failure.getErrorMessage() print ‘Because of the error, I am logging out and stopping reactor...‘ d=self.logout() d.addBoth(self.stopreactor) return failure password=getpass.getpass(‘Enter password for %s on %s:‘%(sys.argv[2], sys.argv[1]))#print passwordreactor.connectTCP(sys.argv[1], 143, IMAPFactory(sys.argv[2], password))reactor.run()
The fetchspecific () function can download multiple emails from one email folder. The first parameter, '1: * 'is the range of all emails in the folder. By setting peek to true, emails are not changed when you read them, if peek is not set, the \ seen flag is added to all downloaded emails. The gotmessages () function is called by the downloaded email. It is passed into a dictionary. The key of the dictionary is the number of the email, and its value is a list of the components of the email.
This article from the "Lotus miss" blog, please be sure to keep this source http://liandesinian.blog.51cto.com/7737219/1567661
Chapter 2 IMAP