13

大きな添付ファイル(約30MB)が含まれている可能性のあるGmailアカウントからすべてのメッセージを取得しようとしています。ファイル全体ではなく、名前だけが必要です。メッセージと添付ファイルの名前を取得するためのコードを見つけましたが、ファイルをダウンロードしてからその名前を読み取ります。

import imaplib, email

#log in and select the inbox
mail = imaplib.IMAP4_SSL('imap.gmail.com')
mail.login('username', 'password')
mail.select('inbox')

#get uids of all messages
result, data = mail.uid('search', None, 'ALL') 
uids = data[0].split()

#read the lastest message
result, data = mail.uid('fetch', uids[-1], '(RFC822)')
m = email.message_from_string(data[0][1])

if m.get_content_maintype() == 'multipart': #multipart messages only
    for part in m.walk():
        #find the attachment part
        if part.get_content_maintype() == 'multipart': continue
        if part.get('Content-Disposition') is None: continue

        #save the attachment in the program directory
        filename = part.get_filename()
        fp = open(filename, 'wb')
        fp.write(part.get_payload(decode=True))
        fp.close()
        print '%s saved!' % filename

これは1分に1回行う必要があるため、数百MBのデータをダウンロードできません。私はWebスクリプトの初心者ですが、誰か助けてもらえますか?私は実際にimaplibを使用する必要はありません、どんなpythonlibでも私にとっては大丈夫です。

よろしくお願いします

4

4 に答える 4

9

完全なコンテンツであるフェッチではなくRFC822、を指定できますBODYSTRUCTURE

結果のデータ構造imaplibはかなり紛らわしいですが、すべてをダウンロードしなくても、メッセージの各部分のファイル名、コンテンツタイプ、およびサイズを見つけることができるはずです。

于 2012-12-01T21:31:00.543 に答える
3

ファイル名について何か知っている場合は、imapSEARCHコマンドにX-GM-RAWgmail拡張機能を使用できます。これらの拡張機能を使用すると、Gmailの高度な検索クエリを使用してメッセージをフィルタリングできます。このようにして、ダウンロードを一致するメッセージに制限したり、不要なメッセージを除外したりできます。

mail.uid('search', None, 'X-GM-RAW', 
       'has:attachment filename:pdf in:inbox -label:parsed'))

上記では、「解析済み」というラベルのないINBOXでPDFが添付されたメッセージを検索します。

いくつかのプロのヒント:

  • すでに解析したメッセージにラベルを付けるので、それらを再度フェッチする必要はありません(上記の例の-label:parsedフィルター)
  • 標準のシーケンシャルIDの代わりに常にuidバージョンを使用してください(すでにこれを行っています)
  • 残念ながら、MIMEは厄介です。奇妙な(または明らかに間違った)ことを行うクライアントがたくさんあります。ヘッダーのみをダウンロードして解析することもできますが、問題を起こす価値はありますか?

[編集]

解析後にメッセージにラベルを付けると、すでに解析したメッセージをスキップできます。これは、クラスのメールボックスを監視するのに十分合理的である必要があります。

おそらく、あなたはインターネット帯域幅がプログラマーの時間よりも高価な世界の片隅に住んでいます。この場合、ヘッダーのみをフェッチして、 "Content-disposition" == "attachment; filename=somefilename.ext"を探すことができます。

于 2012-12-01T21:01:33.357 に答える
2

メッセージデータ項目のFETCHは、RFC822機能的にはと同等BODY[]です。IMAP4は、 RFC3501のセクション6.4.5にリストされている他のメッセージデータ項目をサポートします。

必要な情報だけを取得するには、別のメッセージデータ項目のセットをリクエストしてみてください。たとえば、試してみるRFC822.HEADERか、多分BODY.PEEK[MIME]

于 2012-12-01T21:16:05.590 に答える
1

古い質問ですが、今日私が思いついたこれに対する解決策を共有したかっただけです。添付ファイル付きのすべての電子メールを検索し、uid、送信者、件名、および添付ファイルのフォーマットされたリストを出力します。関連するコードを編集して、BODYSTRUCTUREのフォーマット方法を示しました。

    data   = mailobj.uid('fetch', mail_uid, '(BODYSTRUCTURE)')[1]
    struct = data[0].split()        
    list   = []                     #holds list of attachment filenames

    for j, k in enumerate(struct):
        if k == '("FILENAME"':
            count = 1
            val = struct[j + count]
            while val[-3] != '"':
                count += 1
                val += " " + struct[j + count]
            list.append(val[1:-3])
        elif k == '"FILENAME"':
            count = 1
            val = struct[j + count]
            while val[-1] != '"':
                count += 1
                val += " " + struct[j + count]
            list.append(val[1:-1])

GitHubにも公開しました。

編集

上記の解決策は良いですが、ペイロードから添付ファイル名を抽出するロジックは堅牢ではありません。ファイル名にスペースが含まれ、最初の単語が2文字しかない場合は、失敗します。

例: "adcdegh.png"。

これを試して:

import re # Somewhere at the top

result, data = mailobj.uid("fetch", mail_uid, "BODYSTRUCTURE")

itr = re.finditer('("FILENAME" "([^\/:*?"<>|]+)")', data[0].decode("ascii"))

for match in itr:
    print(f"File name: {match.group(2)}")

ここで正規表現をテストします。

于 2017-06-27T20:26:00.740 に答える