⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 libgmail.py

📁 一个用Python的gmail功能库
💻 PY
📖 第 1 页 / 共 4 页
字号:
    def __init__(self, account = None, filename = ""):        """        """        if account:            self.state = (account.name, account._cookieJar)        elif filename:            self.state = load(open(filename, "rb"))        else:            raise ValueError("GmailSessionState must be instantiated with " \                             "either GmailAccount object or filename.")    def save(self, filename):        """        """        dump(self.state, open(filename, "wb"), -1)class _LabelHandlerMixin(object):    """    Note: Because a message id can be used as a thread id this works for          messages as well as threads.    """    def __init__(self):        self._labels = None            def _makeLabelList(self, labelList):        self._labels = labelList        def addLabel(self, labelName):        """        """        # Note: It appears this also automatically creates new labels.        result = self._account._doThreadAction(U_ADDCATEGORY_ACTION+labelName,                                               self)        if not self._labels:            self._makeLabelList([])        # TODO: Caching this seems a little dangerous; suppress duplicates maybe?        self._labels.append(labelName)        return result    def removeLabel(self, labelName):        """        """        # TODO: Check label is already attached?        # Note: An error is not generated if the label is not already attached.        result = \               self._account._doThreadAction(U_REMOVECATEGORY_ACTION+labelName,                                             self)                removeLabel = True        try:            self._labels.remove(labelName)        except:            removeLabel = False            pass            # If we don't check both, we might end up in some weird inconsistent state        return result and removeLabel    def getLabels(self):        return self._labels    class GmailThread(_LabelHandlerMixin):    """    Note: As far as I can tell, the "canonical" thread id is always the same          as the id of the last message in the thread. But it appears that          the id of any message in the thread can be used to retrieve          the thread information.        """    def __init__(self, parent, threadsInfo):        """        """        _LabelHandlerMixin.__init__(self)                # TODO Handle this better?        self._parent = parent        self._account = self._parent._account                self.id = threadsInfo[T_THREADID] # TODO: Change when canonical updated?        self.subject = threadsInfo[T_SUBJECT_HTML]        self.snippet = threadsInfo[T_SNIPPET_HTML]        #self.extraSummary = threadInfo[T_EXTRA_SNIPPET] #TODO: What is this?        # TODO: Store other info?        # Extract number of messages in thread/conversation.        self._authors = threadsInfo[T_AUTHORS_HTML]        self.info = threadsInfo            try:            # TODO: Find out if this information can be found another way...            #       (Without another page request.)            self._length = int(re.search("\((\d+?)\)\Z",                                         self._authors).group(1))        except AttributeError,info:            # If there's no message count then the thread only has one message.            self._length = 1        # TODO: Store information known about the last message  (e.g. id)?        self._messages = []        # Populate labels        self._makeLabelList(threadsInfo[T_CATEGORIES])    def __getattr__(self, name):        """        Dynamically dispatch some interesting thread properties.        """        attrs = { 'unread': T_UNREAD,                  'star': T_STAR,                  'date': T_DATE_HTML,                  'authors': T_AUTHORS_HTML,                  'flags': T_FLAGS,                  'subject': T_SUBJECT_HTML,                  'snippet': T_SNIPPET_HTML,                  'categories': T_CATEGORIES,                  'attach': T_ATTACH_HTML,                  'matching_msgid': T_MATCHING_MSGID,                  'extra_snippet': T_EXTRA_SNIPPET }        if name in attrs:            return self.info[ attrs[name] ];        raise AttributeError("no attribute %s" % name)            def __len__(self):        """        """        return self._length    def __iter__(self):        """        """        if not self._messages:            self._messages = self._getMessages(self)                    return iter(self._messages)    def __getitem__(self, key):        """        """        if not self._messages:            self._messages = self._getMessages(self)        try:            result = self._messages.__getitem__(key)        except IndexError:            result = []        return result    def _getMessages(self, thread):        """        """        # TODO: Do this better.        # TODO: Specify the query folder using our specific search?        items = self._account._parseSearchResult(U_QUERY_SEARCH,                                                 view = U_CONVERSATION_VIEW,                                                 th = thread.id,                                                 q = "in:anywhere")        result = []        # TODO: Handle this better?        # Note: This handles both draft & non-draft messages in a thread...        for key, isDraft in [(D_MSGINFO, False), (D_DRAFTINFO, True)]:            try:                msgsInfo = items[key]            except KeyError:                # No messages of this type (e.g. draft or non-draft)                continue            else:                # TODO: Handle special case of only 1 message in thread better?                if type(msgsInfo[0]) != types.ListType:                    msgsInfo = [msgsInfo]                for msg in msgsInfo:                    result += [GmailMessage(thread, msg, isDraft = isDraft)]                                   return resultclass GmailMessageStub(_LabelHandlerMixin):    """    Intended to be used where not all message information is known/required.    NOTE: This may go away.    """    # TODO: Provide way to convert this to a full `GmailMessage` instance    #       or allow `GmailMessage` to be created without all info?    def __init__(self, id = None, _account = None):        """        """        _LabelHandlerMixin.__init__(self)        self.id = id        self._account = _account            class GmailMessage(object):    """    """        def __init__(self, parent, msgData, isDraft = False):        """        Note: `msgData` can be from either D_MSGINFO or D_DRAFTINFO.        """        # TODO: Automatically detect if it's a draft or not?        # TODO Handle this better?        self._parent = parent        self._account = self._parent._account                self.author = msgData[MI_AUTHORFIRSTNAME].decode('utf-8')        self.author_fullname = msgData[MI_AUTHORNAME].decode('utf-8')        self.id = msgData[MI_MSGID]        self.number = msgData[MI_NUM]        self.subject = msgData[MI_SUBJECT].decode('utf-8')        self.to = [x.decode('utf-8') for x in msgData[MI_TO]]        self.cc = [x.decode('utf-8') for x in msgData[MI_CC]]        self.bcc = [x.decode('utf-8') for x in msgData[MI_BCC]]        self.sender = msgData[MI_AUTHOREMAIL].decode('utf-8')                # Messages created by google chat (from reply with chat, etc.)        # don't have any attachments, so we need this check not to choke        # on them        try:            self.attachments = [GmailAttachment(self, attachmentInfo)                    for attachmentInfo in msgData[MI_ATTACHINFO]]        except TypeError:            self.attachments = []        # TODO: Populate additional fields & cache...(?)        # TODO: Handle body differently if it's from a draft?        self.isDraft = isDraft                self._source = None    def _getSource(self):        """        """        if not self._source:            # TODO: Do this more nicely...?            # TODO: Strip initial white space & fix up last line ending            #       to make it legal as per RFC?            self._source = self._account.getRawMessage(self.id)        return self._source.decode('utf-8')    source = property(_getSource, doc = "")        class GmailAttachment:    """    """    def __init__(self, parent, attachmentInfo):        """        """        # TODO Handle this better?        self._parent = parent        self._account = self._parent._account        self.id = attachmentInfo[A_ID]        self.filename = attachmentInfo[A_FILENAME]        self.mimetype = attachmentInfo[A_MIMETYPE]        self.filesize = attachmentInfo[A_FILESIZE]        self._content = None    def _getContent(self):        """        """        if not self._content:            # TODO: Do this a more nicely...?            self._content = self._account._retrievePage(                _buildURL(view=U_ATTACHMENT_VIEW, disp="attd",                          attid=self.id, th=self._parent._parent.id))                    return self._content    content = property(_getContent, doc = "")    def _getFullId(self):        """        Returns the "full path"/"full id" of the attachment. (Used        to refer to the file when forwarding.)        The id is of the form: "<thread_id>_<msg_id>_<attachment_id>"                """        return "%s_%s_%s" % (self._parent._parent.id,                             self._parent.id,                             self.id)    _fullId = property(_getFullId, doc = "")class GmailComposedMessage:    """    """    def __init__(self, to, subject, body, cc = None, bcc = None,                 filenames = None, files = None):        """          `filenames` - list of the file paths of the files to attach.          `files` - list of objects implementing sub-set of                    `email.Message.Message` interface (`get_filename`,                    `get_content_type`, `get_payload`). This is to                    allow use of payloads from Message instances.                    TODO: Change this to be simpler class we define ourselves?        """        self.to = to        self.subject = subject        self.body = body        self.cc = cc        self.bcc = bcc        self.filenames = filenames        self.files = filesif __name__ == "__main__":    import sys    from getpass import getpass    try:        name = sys.argv[1]    except IndexError:        name = raw_input("Gmail account name: ")            pw = getpass("Password: ")    domain = raw_input("Domain? [leave blank for Gmail]: ")    ga = GmailAccount(name, pw, domain=domain)    print "\nPlease wait, logging in..."    try:        ga.login()    except GmailLoginFailure,e:        print "\nLogin failed. (%s)" % e.message    else:        print "Login successful.\n"        # TODO: Use properties instead?        quotaInfo = ga.getQuotaInfo()        quotaMbUsed = quotaInfo[QU_SPACEUSED]        quotaMbTotal = quotaInfo[QU_QUOTA]        quotaPercent = quotaInfo[QU_PERCENT]        print "%s of %s used. (%s)\n" % (quotaMbUsed, quotaMbTotal, quotaPercent)        searches = STANDARD_FOLDERS + ga.getLabelNames()        name = None        while 1:            try:                print "Select folder or label to list: (Ctrl-C to exit)"                for optionId, optionName in enumerate(searches):                    print "  %d. %s" % (optionId, optionName)                while not name:                    try:                        name = searches[int(raw_input("Choice: "))]                    except ValueError,info:                        print info                        name = None                if name in STANDARD_FOLDERS:                    result = ga.getMessagesByFolder(name, True)                else:                    result = ga.getMessagesByLabel(name, True)                                    if not len(result):                    print "No threads found in `%s`." % name                    break                name = None                tot = len(result)                                i = 0                for thread in result:                    print "%s messages in thread" % len(thread)                    print thread.id, len(thread), thread.subject                    for msg in thread:                        print "\n ", msg.id, msg.number, msg.author,msg.subject                        # Just as an example of other usefull things                        #print " ", msg.cc, msg.bcc,msg.sender                        i += 1                print                print "number of threads:",tot                print "number of messages:",i            except KeyboardInterrupt:                break                print "\n\nDone."

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -