使用IMAP在Twisted中获取电子邮件

本教程将介绍使用IMAP在Twisted中获取电子邮件的处理方法,这篇教程是从别的地方看到的,然后加了一些国外程序员的疑问与解答,希望能对你有所帮助,好了,下面开始学习吧。

使用IMAP在Twisted中获取电子邮件 教程 第1张

问题描述

我正在尝试使用Twisted在Gmail帐户上获取电子邮件,至少可以说这是一种痛苦,查看电子邮件是他们清晰的解释和结构(充其量似乎是被黑客攻击在一起的)。我试图抓住附件,但附件看不到任何地方。

我正在使用扭转和修改它的示例IMAP客户端,我正在使用fetchAll(‘1:和我似乎找不到任何实际解释电子邮件的东西(好像没有人理解它)

那么Stackoverflow,我错过了什么?

代码

#!/usr/bin/env python

# Copyright (c) Twisted Matrix Laboratories.
# See LICENSE for details.


"""
 Simple IMAP4 client which displays the subjects of all messages in a
 particular mailbox.
 """

import sys

from twisted.internet import protocol
from twisted.internet import ssl
from twisted.internet import defer
from twisted.internet import stdio
from twisted.mail import imap4
from twisted.protocols import basic
from twisted.python import util
from twisted.python import log



class TrivialPrompter(basic.LineReceiver):
 from os import linesep as delimiter

 promptDeferred = None

 def prompt(self, msg):
  assert self.promptDeferred is None
  self.display(msg)
  self.promptDeferred = defer.Deferred()
  return self.promptDeferred

 def display(self, msg):
  self.transport.write(msg)

 def lineReceived(self, line):
  if self.promptDeferred is None:
return
  d, self.promptDeferred = self.promptDeferred, None
  d.callback(line)



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

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



class SimpleIMAP4ClientFactory(protocol.ClientFactory):
 usedUp = False

 protocol = SimpleIMAP4Client


 def __init__(self, username, onConn):
  self.ctx = ssl.ClientContextFactory()

  self.username = username
  self.onConn = onConn


 def buildProtocol(self, addr):
  """
Initiate the protocol instance. Since we are building a simple IMAP
client, we don't bother checking what capabilities the server has. We
just add all the authenticators twisted.mail has.  Note: Gmail no
longer uses any of the methods below, it's been using XOAUTH since
2010.
"""
  assert not self.usedUp
  self.usedUp = True

  p = self.protocol(self.ctx)
  p.factory = self
  p.greetDeferred = self.onConn

  p.registerAuthenticator(imap4.PLAINAuthenticator(self.username))
  p.registerAuthenticator(imap4.LOGINAuthenticator(self.username))
  p.registerAuthenticator(
  imap4.CramMD5ClientAuthenticator(self.username))

  return p


 def clientConnectionFailed(self, connector, reason):
  d, self.onConn = self.onConn, None
  d.errback(reason)



def cbServerGreeting(proto, username, password):
 """
  Initial callback - invoked after the server sends us its greet message.
  """
 # Hook up stdio
 tp = TrivialPrompter()
 stdio.StandardIO(tp)

 # And make it easily accessible
 proto.prompt = tp.prompt
 proto.display = tp.display

 # Try to authenticate securely
 return proto.authenticate(password
).addCallback(cbAuthentication, proto
  ).addErrback(ebAuthentication, proto, username, password
)


def ebConnection(reason):
 """
  Fallback error-handler. If anything goes wrong, log it and quit.
  """
 log.startLogging(sys.stdout)
 log.err(reason)
 return reason


def cbAuthentication(result, proto):
 """
  Callback after authentication has succeeded.

  Lists a bunch of mailboxes.
  """
 return proto.list("", "*"
 ).addCallback(cbMailboxList, proto
)


def ebAuthentication(failure, proto, username, password):
 """
  Errback invoked when authentication fails.

  If it failed because no SASL mechanisms match, offer the user the choice
  of logging in insecurely.

  If you are trying to connect to your Gmail account, you will be here!
  """
 failure.trap(imap4.NoSupportedAuthentication)
 return proto.prompt(
"No secure authentication available. Login insecurely? (y/N) "
).addCallback(cbInsecureLogin, proto, username, password
  )


def cbInsecureLogin(result, proto, username, password):
 """
  Callback for "insecure-login" prompt.
  """
 if result.lower() == "y":
  # If they said yes, do it.
  return proto.login(username, password
).addCallback(cbAuthentication, proto
  )
 return defer.fail(Exception("Login failed for security reasons."))


def cbMailboxList(result, proto):
 """
  Callback invoked when a list of mailboxes has been retrieved.
  """
 result = [e[2] for e in result]
 s = '
'.join(['%d. %s' % (n + 1, m) for (n, m) in zip(range(len(result)), result)])
 if not s:
  return defer.fail(Exception("No mailboxes exist on server!"))
 return proto.prompt(s + "
Which mailbox? [1] "
).addCallback(cbPickMailbox, proto, result
  )


def cbPickMailbox(result, proto, mboxes):
 """
  When the user selects a mailbox, "examine" it.
  """
 mbox = mboxes[int(result or '1') - 1]
 return proto.examine(mbox
 ).addCallback(cbExamineMbox, proto
)


def cbExamineMbox(result, proto):
 """
  Callback invoked when examine command completes.

  Retrieve the subject header of every message in the mailbox.
  """
 # FETCH ALL HEADERS? WHERE IS A ONE FOR AN ATTACHMENT
 return proto.fetchAll('1:*').addCallback(cbFetch, proto)


def cbFetch(result, proto):
 """
  Finally, display headers.
  """
 if result:
  keys = result.keys()
  keys.sort()
  k = keys[-1]
  proto.display('%s %s' % (k, result[k]))
 else:
  print "Hey, an empty mailbox!"

 return proto.logout()


def cbClose(result):
 """
  Close the connection when we finish everything.
  """
 from twisted.internet import reactor
 reactor.stop()


def main():
 hostname = raw_input('IMAP4 Server Hostname: ')
 port = raw_input('IMAP4 Server Port (the default is 143, 993 uses SSL): ')
 username = raw_input('IMAP4 Username: ')
 password = util.getPassword('IMAP4 Password: ')

 onConn = defer.Deferred(
 ).addCallback(cbServerGreeting, username, password
).addErrback(ebConnection
 ).addBoth(cbClose)

 factory = SimpleIMAP4ClientFactory(username, onConn)

 from twisted.internet import reactor
 if port == '993':
  reactor.connectSSL(hostname, int(port), factory, ssl.ClientContextFactory())
 else:
  if not port:
port = 143
  reactor.connectTCP(hostname, int(port), factory)
 reactor.run()


if __name__ == '__main__':
 main()

推荐答案

首先,IMAP4是一个复杂的邮件处理协议(可能没有必要),而Twisted的客户端实现(必然)复杂,无法完全支持该协议。要了解更多内容,您应该考虑花一些时间阅读解释协议的标准:rfc3501和twisted's api的相关部分。

这就是说,看起来您使用的是IMAP4Client.fetchAll(),矛盾的是,它获取了信封&数据、消息的头和元数据。返回电子邮件正文的类似调用实际上也是fetchFull()

好了关于使用IMAP在Twisted中获取电子邮件的教程就到这里就结束了,希望趣模板源码网找到的这篇技术文章能帮助到大家,更多技术教程可以在站内搜索。