IMAP4 讀取收件箱的問題

以下文章轉載: 

https://www.cnblogs.com/xiaowuyi/archive/2013/08/07/3244760.html

所謂無痕取信,目前主要是指從郵箱中把信件收取後,郵箱內狀態不發生任何改變。這裏的狀態主要是指兩部分,一部分是郵件狀態不變,即已讀與未讀狀態不變,另一部分是指郵箱記錄的登陸IP不發生改變。本文中所說的僞“無痕”取信主要是指實現第一部分。

一、準備知識
1、Imaplib

IMAP4.append(mailbox, flags, date_time, message):Append message to named mailbox.

IMAP4.authenticate(mechanism, authobject):Authenticate command — requires response processing.mechanism specifies which authentication mechanism is to be used - it should appear in the instance variable capabilities in the form AUTH=mechanism.

IMAP4.check():Checkpoint mailbox on server.

IMAP4.close():Close currently selected mailbox. Deleted messages are removed from writable mailbox. This is the recommended command before LOGOUT.

IMAP4.copy(message_set, new_mailbox):Copy message_set messages onto end of new_mailbox.

IMAP4.create(mailbox):Create new mailbox named mailbox.

IMAP4.delete(mailbox):Delete old mailbox named mailbox.

IMAP4.deleteacl(mailbox, who):Delete the ACLs (remove any rights) set for who on mailbox.

IMAP4.expunge():Permanently remove deleted items from selected mailbox. Generates an EXPUNGE response for each deleted message. Returned data contains a list of EXPUNGE message numbers in order received.

IMAP4.fetch(message_set, message_parts):Fetch (parts of) messages. message_parts should be a string of message part names enclosed within parentheses, eg: "(UID BODY[TEXT])". Returned data are tuples of message part envelope and data.

IMAP4.getacl(mailbox):Get the ACLs for mailbox. The method is non-standard, but is supported by the Cyrus server.

IMAP4.getannotation(mailbox, entry, attribute):Retrieve the specified ANNOTATIONs for mailbox. The method is non-standard, but is supported by the Cyrus server.

IMAP4.getquota(root):Get the quota root‘s resource usage and limits. This method is part of the IMAP4 QUOTA extension defined in rfc2087.

IMAP4.getquotaroot(mailbox):Get the list of quota roots for the named mailbox. This method is part of the IMAP4 QUOTA extension defined in rfc2087.

IMAP4.list([directory[, pattern]]):List mailbox names in directory matching pattern. directory defaults to the top-level mail folder, and pattern defaults to match anything. Returned data contains a list of LIST responses.

IMAP4.login(user, password):Identify the client using a plaintext password. The password will be quoted.

IMAP4.login_cram_md5(user, password):Force use of CRAM-MD5 authentication when identifying the client to protect the password. Will only work if the server CAPABILITY response includes the phrase AUTH=CRAM-MD5.

IMAP4.logout():Shutdown connection to server. Returns server BYE response.

IMAP4.lsub([directory[, pattern]]):List subscribed mailbox names in directory matching pattern. directory defaults to the top level directory and pattern defaults to match any mailbox. Returned data are tuples of message part envelope and data.

IMAP4.myrights(mailbox):Show my ACLs for a mailbox (i.e. the rights that I have on mailbox).

IMAP4.namespace():Returns IMAP namespaces as defined in RFC2342.

IMAP4.noop():Send NOOP to server.

IMAP4.open(host, port):Opens socket to port at host. This method is implicitly called by the IMAP4 constructor. The connection objects established by this method will be used in the read, readline, send, and shutdown methods. You may override this method.

IMAP4.partial(message_num, message_part, start, length):Fetch truncated part of a message. Returned data is a tuple of message part envelope and data.

IMAP4.proxyauth(user):Assume authentication as user. Allows an authorised administrator to proxy into any user’s mailbox.

IMAP4.read(size):Reads size bytes from the remote server. You may override this method.

IMAP4.readline():Reads one line from the remote server. You may override this method.

IMAP4.recent():Prompt server for an update. Returned data is None if no new messages, else value of RECENT response.

IMAP4.rename(oldmailbox, newmailbox):Rename mailbox named oldmailbox to newmailbox.

IMAP4.response(code):Return data for response code if received, or None. Returns the given code, instead of the usual type.

IMAP4.search(charset, criterion[, ...]):Search mailbox for matching messages. charset may be None, in which case no CHARSET will be specified in the request to the server. The IMAP protocol requires that at least one criterion be specified; an exception will be raised when the server returns an error.

IMAP4.send(data):Sends data to the remote server. You may override this method.

IMAP4.setacl(mailbox, who, what):Set an ACL for mailbox. The method is non-standard, but is supported by the Cyrus server.

IMAP4.setannotation(mailbox, entry, attribute[, ...]):Set ANNOTATIONs for mailbox. The method is non-standard, but is supported by the Cyrus server.

IMAP4.setquota(root, limits):Set the quota root‘s resource limits. This method is part of the IMAP4 QUOTA extension defined in rfc2087.

IMAP4.shutdown():Close connection established in open. This method is implicitly called by IMAP4.logout(). You may override this method.

IMAP4.socket():Returns socket instance used to connect to server.

IMAP4.sort(sort_criteria, charset, search_criterion[, ...]):The sort command is a variant of search with sorting semantics for the results. Returned data contains a space separated list of matching message numbers.

IMAP4.status(mailbox, names):Request named status conditions for mailbox.

IMAP4.store(message_set, command, flag_list):Alters flag dispositions for messages in mailbox. command is specified by section 6.4.6 of RFC 2060 as being one of “FLAGS”, “+FLAGS”, or “-FLAGS”, optionally with a suffix of ”.SILENT”.

IMAP4.thread(threading_algorithm, charset, search_criterion[, ...]):The thread command is a variant of search with threading semantics for the results. Returned data contains a space separated list of thread members.

IMAP4.uid(command, arg[, ...]):Execute command args with messages identified by UID, rather than message number. Returns response appropriate to command. At least one argument must be supplied; if none are provided, the server will return an error and an exception will be raised.

IMAP4.unsubscribe(mailbox):Unsubscribe from old mailbox.

IMAP4.xatom(name[, arg[, ...]]):Allow simple extension commands notified by server in CAPABILITY response.

IMAP4_SSL.ssl():Returns SSLObject instance used for the secure connection with the server.

IMAP4.PROTOCOL_VERSION:The most recent supported protocol in the CAPABILITY response from the server.

IMAP4.debug:Integer value to control debugging output. The initialize value is taken from the module variable Debug. Values greater than three trace each command.

2、imap 命令詳解

CREATE <folder>:CREATE可以創建指定名字的新郵箱。郵箱名稱通常是帶路徑的文件夾全名。(有些IMAP客戶機使用郵件夾稱呼新郵箱)
C: A003 CREATE owatagusiam/                 /*創建一個新目錄owatagusiam*/
S: A003 OK CREATE completed
C: A004 CREATE owatagusiam/blurdybloop  
/* 在創建的目錄owatagusiam下創建一個名爲blurdybloop 的郵箱,當然可以省略第一步,直接A004 CREATE owatagusiam/blurdybloop ,表示在新的目錄owatagusiam 下創建了一個名爲blurdybloop 的郵箱*/         
S: A004 OK CREATE completed

DELETE <folder>:DELETE命令刪除指定名字的文件夾。文件夾名字通常是帶路徑的文件夾全名,當郵箱被刪除後,其中的郵件也不復存在。
C: A683 DELETE blurdybloop
S: A683 OK DELETE completed 
C: A684 DELETE foo
S: A684 NO Name "foo" has inferior hierarchical names
C: A685 DELETE foo/bar 
S: A685 OK DELETE Completed

RENAME <old folder><new folder>:RENAME命令可以修改文件夾的名稱,它使用兩個參數:當前郵箱名和新郵箱名,兩個參數的命名符合標準路徑命名規則。
C: A683 RENAME blurdybloop sarasoop
S: A683 OK RENAME completed
C: A684 RENAME stuff/junk newbox         /*把stuff目錄(文件夾)下的郵箱junk改名爲newbox*/
S: A684 OK RENAME Completed

LIST <BASE><template>:LIST命令用於列出郵箱中已有的文件夾,有點像操作系統的列目錄命令,有兩個參數,郵箱路徑參數BASE:表示用戶登陸目錄;第二個參數template:表示希望顯示的郵箱名。這個命令可以包含起始的路徑位置和需要列出的文件夾所符合的特徵,可以使用通配符"*"。
C: A101 LIST "" ""
S: * LIST (\Noselect) "/" ""
S: A101 OK LIST Completed
C: A102 LIST #news.comp.mail.misc ""
S: * LIST (\Noselect) "." #news.
S: A102 OK LIST Completed
C: A103 LIST /usr/staff/jones ""
S: * LIST (\Noselect) "/" /
S: A103 OK LIST Completed
C: A202 LIST ~/Mail/ %
S: * LIST (\Noselect) "/" ~/Mail/foo
S: * LIST () "/" ~/Mail/meetings
S: A202 OK LIST completed

APPEND <folder><attributes><date/time><size><mail data>:APPEND命令允許Client上載一個郵件到指定的Folder(文件夾/郵箱)中。命令中包含了新郵件的屬性、日期/時間、大小,隨後是郵件數據。
C: A003 APPEND saved-messages (\Seen) {310}
C: Date: Mon, 7 Feb 1994 21:52:25 -0800 (PST)
C: From: Fred Foobar <[email protected]>
C: Subject: afternoon meeting
C: To: [email protected]
C: Message-Id: <[email protected]>
C: MIME-Version: 1.0
C: Content-Type: TEXT/PLAIN; CHARSET=US-ASCII
C:
C: Hello Joe, do you think we can meet at 3:30 tomorrow?
C:
S: A003 OK APPEND completed

SELECT <folder>:SELECT命令讓Client選定某個郵箱(Folder),表示即將對該郵箱(Folder)內的郵件作操作。郵箱標誌的當前狀態也返回給了用戶,同時返回的還有一些關於郵件和郵箱的附加信息。
C: A142 SELECT INBOX
S: * 172 EXISTS
S: * 1 RECENT
S: * OK [UNSEEN 12] Message 12 is first unseen
S: * OK [UIDVALIDITY 3857529045] UIDs valid
S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
S: * OK [PERMANENTFLAGS (\Deleted \Seen \*)] Limited
S: A142 OK [READ-WRITE] SELECT completed

FETCH <mail id><datanames>:FETCH 命令用於讀取郵件的文本信息,且僅用於顯示的目的。包含兩個參數,messageset:表示希望讀取的郵件號列表,IAMP服務器郵箱中的每個郵件都有 一個唯一的ID標識,(郵件號列表參數可以是一個郵件號,也可以是由逗號分隔的多個郵件號,或者由冒號間隔的一個範圍),IMAP服務器返回郵件號列表中 全部郵件的指定數據項內容。
數據名參數確定能夠被獨立返回的郵件的一部分,下面我們看看各參數返回的郵件信息:
ALL:只返回按照一定格式的郵件摘要,包括郵件標誌、RFC822.SIZE、自身的時間和信封信息。IMAP客戶機能夠將標準郵件解析成這些信息並顯示出來。
BODY:只返回郵件體文本格式和大小的摘要信息。IMAP客戶機可以識別這些細膩,並向用戶顯示詳細的關於郵件的信息。其實是一些非擴展的BODYSTRUCTURE的信息。
FAST:只返回郵件的一些摘要,包括郵件標誌、RFC822.SIZE、和自身的時間。
FULL:同樣的還是一些摘要信息,包括郵件標誌、RFC822.SIZE、自身的時間和BODYSTRUCTURE的信息。
BODYSTRUCTUR: 是郵件的[MIME-IMB]的體結構。這是服務器通過解析[RFC-2822]頭中的[MIME-IMB]各字段和[MIME-IMB]頭信息得出來 的。包括的內容有:郵件正文的類型、字符集、編碼方式等和各附件的類型、字符集、編碼方式、文件名稱等等。
ENVELOPE:信息的信封結構。是服務器通過解析[RFC-2822]頭中的[MIME-IMB]各字段得出來的,默認各字段都是需要的。主要包括:自身的時間、附件數、收件人、發件人等。
FLAGS:此郵件的標誌。
INTERNALDATE:自身的時間。
RFC822.SIZE:郵件的[RFC-2822]大小
RFC822.HEADER:在功能上等同於BODY.PEEK[HEADER],
RFC822:功能上等同於BODY[]。
RFC822.TEXT:功能上等同於BODY[TEXT]
UID:返回郵件的UID號,UID號是唯一標識郵件的一個號碼。
BODY[section] <<partial>>:返回郵件的中的某一指定部分,返回的部分用section來表示,section部分包含的信息通常是 代表某一部分的一個數字或者是下面的某一個部分:HEADER, HEADER.FIELDS, HEADER.FIELDS.NOT, MIME, and TEXT。如果section部分是空的話,那就代表返回全部的信息,包括頭信息。
BODY[HEADER]返回完整的文件頭信息。
BODY[HEADER.FIELDS ()]:在小括號裏面可以指定返回的特定字段。
BODY[HEADER.FIELDS.NOT ()]:在小括號裏面可以指定不需要返回的特定字段。
BODY[MIME]:返回郵件的[MIME-IMB]的頭信息,在正常情況下跟BODY[HEADER]沒有區別。
BODY[TEXT]:返回整個郵件體,這裏的郵件體並不包括郵件頭。

STORE <mail id><new attributes>:STORE 命令用於修改指定郵件的屬性,包括給郵件打上已讀標記、刪除標記,等等。STORE命令當前只有兩個數據項類型可用,FLAGS:表示郵件的一組標誌; FLAGS.SLIENT,表示一組郵件的標誌,通過在兩種數據項前加上加號或者減號可以進一步改變它們的執行情況,加號表示數據項的值添加到郵件中,減 號表示將數據項的值從郵件中刪除。
C: A003 STORE 2:4 +FLAGS (\Deleted)      /*冒號表示間隔的一個範圍:給從2到4的郵件設置Deleted屬性*/
S: * 2 FETCH FLAGS (\Deleted \Seen)
S: * 3 FETCH FLAGS (\Deleted)
S: * 4 FETCH FLAGS (\Deleted \Flagged \Seen)
S: A003 OK STORE completed
同時改命令還可以用於把郵件標記爲未讀等等。在web上可以對郵件進行的操作在imap中都可以實現。

CLOSE:CLOSE命令表示Client結束對當前Folder(文件夾/郵箱)的訪問,關閉郵箱該郵箱中所有標誌爲、DELETED的郵件就被從物理上刪除。CLOSE沒有命令參數。隨後可以SELECT另一Folder。
C: A341 CLOSE
S: A341 OK CLOSE completed


EXPUNGE:EXPUNGE命令在不關閉郵箱的情況下刪除所有的標誌爲、DELETED的郵件。EXPUNGE刪除的郵件將不可以恢復。 
C: A202 EXPUNGE
S: * 3 EXPUNGE
S: * 3 EXPUNGE
S: * 5 EXPUNGE
S: * 8 EXPUNGE
S: A202 OK EXPUNGE completed

LOGOUT:LOGOUT命令結束本次IMAP會話。
C: A023 LOGOUT
S: * BYE IMAP4rev1 Server logging out
S: A023 OK LOGOUT completed
(Server and client then close the connection)

EXAMINE <mailbox>:
EXAMINE命令以只讀方式打開郵箱,參數是需要打開的郵箱的名字,使用EXAMINE命令打開的郵箱不允許對郵件進行改動,因此不能增加或刪除郵件的標誌。

SUBSCRIBE <mailbox>:SUBSCRIBE命令用來在客戶機的活動郵箱列表中增加一個郵箱,該命令只有一個參數,希望添加的郵箱名。
C: A114 SUBSCRIBE new/anotherbox
S: A114 OK SUBSCRIBE completed

UNSUBSCRIBE <mailbox>:UNSUBSCRIBE命令用來從活動列表中去掉一個郵箱,一個參數:希望去掉的郵箱名。
C: A115 UNSUBSCRIBE new/anotherbox
S: A115 OK SUBSCRIBE completed

LSUB <folder><mailbox>:LSUB命令修正了LIST命令,LIST返回用戶$HOME目錄下所有的文件,但LSUB命令只顯示那些使用SUBSCRIBE命令設置爲活動郵箱的文件。兩個參數:郵箱路徑和郵箱名。
C: A116 LSUB “” *
S:* LSUB () “/” stuff/junk
S:* LSUB () “/” neebox
S:* LSUB () “/” new/anotherbox
S: A116 OK LSUB completed

STATUS <mailbox>(<parameter1>  < parameter2>  ……<parameter5>):STATUS命令查詢郵箱的當前狀態。第一個參數是需要查詢的郵箱名,第二個參數是客戶機需要查詢的項目列表(要查詢顯示的信息),當在圓括號中。STATUS可以在不使用SELECT命令(打開郵箱)或者EXAMINE(以只讀方式打開郵箱)前提下獲取郵箱的信息。
STATUS命令可以獲得的數據項
項 目                 說  明
MESSAGE         郵箱中的郵件總數
RECENT         郵箱中標誌爲\RECENT的郵件數
UIDNEXT         可以分配給新郵件的下一個UID
UIDVALIDITY         郵箱的UID有效性標誌
UNSEEN         郵箱中沒有被標誌爲\UNSEEN的郵件數
C: A117 STATUS inbox  (message recent unseen)
S:* STATUS inbox (MESSAGE 1 RECENT 0 UNSENN 0)
S: A117 OK STATUS completed
C: A118 STATUS newbox  (message recent unseen)
S:* STATUS inbox (MESSAGE 1 RECENT 0 UNSENN 2)
S: A118 OK STATUS completed

CHECK :CHECK命令用來在郵箱設置一個檢查點。沒有參數。就是IMAP中的sync命令。任何未完成的操作,例如從服務器內存向硬盤寫數據,都將會被做完以保持郵箱的一致性狀態。該命令確保乃村中的磁盤緩衝數據都被寫到了磁盤上。

SEARCH [CHARSET specification] (search criteria):命 令可以根據搜索條件在處於活動狀態的郵箱中搜索郵件,然後顯示匹配的郵件編號。字符集標誌參數[CHARSET specification]由CHARSET和註冊的字符集標誌符組成,缺省的標誌符是US-ASCⅡ,所以該參數長省略。search criteria:查詢條件參數,明確查詢的關鍵字和值。查詢關鍵字有幾十種。
C: A119 SEARCH header subject another
S: SEARCH 1 2
S:* A119 OK SEARCH completed
C: A120 SEARCH header subject another
S: *SEARCH 2
S: A120 OK SEARCH completed
C: A121 SEARCH UNSEEN
S: *SEARCH 1 2
S: A120 OK SEARCH completed
以上每個例子都在郵件頭的Subject:字段中查詢一個不同的單詞。服務器返回條件的郵件號列表,如果沒有匹配郵件則返回不帶UID的SEARCH單詞。

COPY <mail id><mailboxname>:COPY命令可以把郵件從一個郵箱複製到另一個郵箱,兩個參數:mail id是希望從活動郵箱中複製的郵件的標號,mailboxname是希望郵件被複制到的郵箱。
IAMP沒有定義移動郵件的命令,移動操作相當於先把郵件複製到新郵箱中,然後對源郵箱中的郵件設置\DELETED標誌。下一次執行檢查點過後,新郵箱中的郵件被刪除,新郵件就被顯示出來。

UID:UID 命令和FETCH、COPY、STORE命令或者SEARCH命令一起使用,它允許這些命令使用郵件的UID號而不是在郵箱中的順序號。UID號是唯一標 識郵件系統中郵件的32位證書。通常這些命令都使用順序號來標識郵箱中的郵件,使用UID可以使IMAP客戶機記住不同IMAP會話中的郵件。

CAPABILITY:CAPABILITY命令請求返回IMAP服務器支持的功能列表,服務器收到客戶機發送的CAPABILITY命令後將返回該服務器所支持的功能。無參數。
C: A122 CAPABILITY
S:*A122 CAPABILITY IMAP4 IMAP4REVl NAMESPACE IDLE SCAN SORT   MAILBOX
--REFERRALS [ic:ccc] LOGIN-REFERRALS AUTH=LOGIN THREAD=
ORDERDSUBJECT
S: A122 OK CAPABILITY completed

NOOP:NOOP命令什麼也不做,用來向服務器發送自動命令,防止因長時間處於不活動狀態而導致連接中斷,服務器對該命令的響應始終爲肯定。無參數。

LOGOUT:LOGOUT命令使當前登陸用戶退出登陸並關閉所有打開的郵箱,任何做了\DELETED標誌的郵件都將在這個時候被刪除。

二、以yahoo郵箱爲例進行僞無痕收信
    要做到郵件狀態不發生變化,實現上關鍵在fetch的參數上。如果我們僅是讀取郵件頭BODY.PEEK[HEADER],那麼郵件的狀態是不發生變化的。如果我們要讀取全部郵件內容,那麼必須使用BODY.PEEK[],這樣才能保證不發生變化。如下面的例子:

複製代碼
#-*- coding:UTF-8 -*-
#@小五義 http://www.cnblogs.com/xiaowuyi

import imaplib, string, email
import os
M = imaplib.IMAP4_SSL("imap.mail.yahoo.com","993")
t=0
try:
    try:
        M.login('[email protected]','YYYY')####YYYY爲密碼
    except Exception,e:
        #print "wrong!"
        print 'login error: %s' % e
        M.close()
    
    M.select('INBOX',False)
    
   # result, message = M.select()
    typ, data = M.search(None, 'ALL')
    for num in string.split(data[0]):
        try:
            typ, data = M.fetch(num, '(UID BODY.PEEK[])')
            msg = email.message_from_string(data[0][1])
            t=t+1
            filename=str(t)+".eml"
            f=open(filename,'wb')
            f.write(str(msg))
            f.close
        except Exception,e:
            print 'got msg error: %s' % e            
    print "OK!"
    M.logout()
except Exception, e:
    print 'imap error: %s' % e
    M.close()
複製代碼

前面說的有些抽象,typ, data = M.fetch(num, '(UID BODY.PEEK[])')在這一句中,可以償試着將UID BODY.PEEK[HEADER]、UID BODY[]、RFC822、RFC822.HEADER等進行收信比較,將會更加直觀。這裏就不再一一解釋。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章