Unicode problem mit ImapClient, die zweite

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
beatrix.w
User
Beiträge: 16
Registriert: Freitag 2. Mai 2014, 15:23

Hallo,

Python-Newbie hier. Bin mit meinem Script zum Abfragen einer Mailbox mit der ImapClient-Library schon recht weit gekommen. Aber irgendwie verstehe ich die Encodings in Python immer noch nicht korrekt. Der Code ist der folgende:

Code: Alles auswählen

        msgdict = imap_connection.fetch(messages[current_mail - 1], ['BODY.PEEK[]'])
        for message_id, message in msgdict.items():

            temp_folderitem, temp_path = tempfile.mkstemp()
            try:
               temp_binarystream = os.fdopen(temp_folderitem,'w')
               temp_binarystream.write(message['BODY[]'].encode('utf8', 'ignore'))
            except IOError, err:
                print "xxxerrorxxx: IOError:" + temp_path, err
                sys.exit(1)
            #end try
            temp_binarystream.close()
            print 'file:' + temp_path
Das Problem liegt in der Zeile

Code: Alles auswählen

temp_binarystream.write(message['BODY[]'].encode('utf8', 'ignore'))
Das verändert mir den MessageBody soweit, daß ich ihn in meinem Parser nicht parsen kann bei einigen Mails, z.B. in russisch. Im Hex-Editor kann ich erkennen, daß die originale Datei, die ich in AppleMail habe, mit den Daten aus message['BODY[]'] übereinstimmt. Wenn ich das encode weglasse, meckert Python über nicht encodierbares ascii.

Wie kann ich Python dazu bringen, daß er mir die original Daten schreibt und nicht die - im Fall der russischen Mail - Daten neu encodiert?

Grüße

Beatrix Willius
BlackJack

@beatrix.w: Das kommt ganz darauf an was die Originaldaten sind. Was hat ``message['BODY[]']`` denn für einen Typ? Wenn das `unicode` ist, dann hast Du schon ”verloren”. Falls es ein Bytestring ist macht das `encode()` so gar keinen Sinn.

Eine Datei die an den Namen `temp_binarystream` gebunden ist, würde ich übrigens auch im Binärmodus öffnen.
beatrix.w
User
Beiträge: 16
Registriert: Freitag 2. Mai 2014, 15:23

Der String ist ein Unicode-String - laut Debugger. Wieso habe ich dann verloren? Kann ich einem String in Python nicht sagen, daß er sein Encoding vergessen soll?

Beginn der kyrillischen Mail (wahrscheinlich Spam): Соберем для
Beginn der Mail in AppleMail in hex: D1 EE E1
Beginn der Mail in Python im Debugger: \xd1\xee\xe1\
Begin der Mail in Python in hex in Datei geschrieben: C3 91 C3 AE C3

Die Daten sehen vor dem Rausschreiben okay aus. Aber wie komme ich da dran?

Grüße

Beatrix Willius
BlackJack

@beatrix.w: Wenn der Wert schon `unicode` ist, dann sind die Daten bereits dekodiert und an der `unicode`-Zeichenkette selber kann man nicht mehr erkennen welche Kodierung das ursprünglich mal war. Wobei die Dekodierung auch irgendwie nicht zu den Daten passt. Das sieht aus wie dekodiert ohne tatsächlich zu dekodieren, also einfach Bytewert zu Codepoint.
Sirius3
User
Beiträge: 17738
Registriert: Sonntag 21. Oktober 2012, 17:20

Du dekodierst die Daten als Latin-1 und schreibst sie wieder als UTF8 kodiert in die Datei. Da kann dann natürlich nur Murx rauskommen.
BlackJack

@Sirius3: Das Problem dabei ist ja das die Daten nicht von beatrix.w dekodiert werden, also der Schritt nicht bewusst gemacht wird. Ich vermute mal ganz stark das die Daten in der Mail schon fehlerhaft sind, also dort Kodierungsangabe und die tatsächliche Kodierung der Daten nicht zusammen passen. Also zum Beispiel gar keine Kodierungsangabe drin steht, also implizit latin-1, der Text selber aber cp1251 kodiert ist.
beatrix.w
User
Beiträge: 16
Registriert: Freitag 2. Mai 2014, 15:23

@Blackjack: nein, die Daten sind nicht fehlerhaft. Bei Mails steht die Kodierung im Content Transfer Encoding. Aber einzelne Teile einer Mail können unterschiedliche Encodings haben. Also muß man erst die einzelnen Teile einer Mail trennen und am Schluß bekommen die Teilstücke die Kodierung verpaßt.

An dieser Stelle bin ich noch weit davon entfernt, an das Content Transfer Encoding zu kommen. Daher kann ich nicht so einfach eine beliebige Kodierung nehmen.
BlackJack

@beatrix.w: Also noch mal die Frage: was ist das überhaupt für ein Typ, denn ich bekomme da für den Schlüssel 'BODY[]' den Typ `str` und nicht `unicode`. Warum hast Du da `unicode`?
beatrix.w
User
Beiträge: 16
Registriert: Freitag 2. Mai 2014, 15:23

:-)

message ist ein Dictionary. message['BODY[]'] ist unicode - sagt der Debugger.

Das kommt vom ImapClient. So wirklich viel mache ich da doch gar nicht.
BlackJack

@beatrix.w: OMG, ich habe gerade IMAPClient aktualisiert (von 0.8 auf 0.11) und das macht IMAPClient ja tatsächlich. Warum nur!? Und mit welcher Kodierung? Das ist ja krank. Und kaputt.
BlackJack

Und nochmal: Es ist tatsächlich kaputt: http://librelist.com/browser//imapclien ... s-strings/

Bedeutet für Dich jetzt wahrscheinlich erst einmal, dass Du die Daten wieder als 'latin-1' kodieren musst und hoffen musst, dass Dir keine Mails unterkommen bei denen das irgendwie auf die Nase fällt oder kaputte Daten produziert.
beatrix.w
User
Beiträge: 16
Registriert: Freitag 2. Mai 2014, 15:23

Hahahha..........danke für's testen.

Ich habe schon versucht, den Author zu kontaktieren. Aber bisher ohne Erfolg. Und nein, meine Emails (und die meiner Kunden) können alle möglichen Encodings haben. Wie z.B. die russische, mit der ich schon getestet habe.

Wäre auch mit einem einigermaßen schnell-laufenden Workaround zufrieden. Werde mir mal den Link ansehen.
Antworten