Unicode Emails vom Server als HTML files sichern oder so aehnlich..
Unicode Emails vom Server als HTML files sichern oder so aehnlich..
am 14.06.2006 11:45:29 von wolfgang
Hallo NG,
ich habe ein Problem mit Japanern :-) Sie schicken UTF8 Mails.
Ich hole Emails von einem IMAP Server ab ud speichere sie incl.
Anhängen als HTML Files auf einer Pladde. Das geht seit langem etwa
so: (sinngemäss, habe zwecks Erklärung massig Zeugs, z.B. das
attachement handling und die HTML-isierung rausgeworfen ):
use Mail::IMAPClient; # for the imap server connection
use MIME::Parser; # for the mime mail parsing
use MIME::Parser::Filer; # to store parser objects to disk
use MIME::WordDecoder; # to handle iso-8859-1 encoded strings
$wd =3D supported MIME::WordDecoder "ISO-8859-1";
$parser =3D MIME::Parser->new(output_to_core=3D>'ALL');
$parser->extract_uuencode(1);
$imap =3D Mail::IMAPClient->new( Server =3D> "MyMailServer",
User =3D> $cfg{'user'},
Password =3D> $cfg{'password'});
if ($imap->select("Inbox")) {
my @msgs =3D $imap->messages;
foreach $this(@msgs) {
my $hdref =3D $imap->parse_headers($this,'ALL');
my %hd =3D %{$hdref};
my @hdr =3D @{$hd{'Subject'}};
$hdr[0] =3D $wd->decode($hdr[0]);
$hdr[0] =3D~ s/re: ?|aw: ?|wg: ?|fw: ?//gi;
$hdr[0] =3D~ s/^ +//;
my $decoded_header =3D $hdr[0];
$parser->output_dir("$cfg{'tempdir'}"); # Kram auf Platte legen
$parser->parse_data($msg);
my @alltxt =3D glob "$cfg{'tempdir'}/*.txt";
foreach $fi(@alltxt) {
open G,"<$fi";
while () {
$thistext .=3D $wd->decode($_);
}
close G;
}
}
}
Das PROBLEM ist jetzt, dass da zunehmend Mails in nicht-ISO8859-1
ankommen. Es gibt welche, die sind nur in Teilen anders codiert, zum
Beispiel sieht dann der Subject so aus:
Subject:
=3D?iso-2022-jp?B?U09OWRskQiEhGyhCSWNoaW5vbWl5YS9GYWlsdXJlIE FuYWx5c2k=3D?=
=3D
=3D?iso-2022-jp?B?cyBJbml0aWF0aW9uIGZvcm06IDA2LTA4OTsgUURCIE pvYiAxNTk3Mg=3D=
=3D?=3D
und welche die sind offenbar komplett UTF8.
Meine drei probleme sind jetzt:
1) Wie bzw. wo mache ich die Konvertierung ? Kann das schon
MAIL::IMAPClient ( habe ich aber nichts dazu gefunden ) oder
MIME::WordDecoder ? Eher nicht, oder, da der UTF8 Kram ja sozusagen
eine Ebene tiefer liegt.
Es scheint ja sowas wie
http://search.cpan.org/~dankogai/Encode-2.18/Unicode/Unicode .pm
zu geben, aber erstens habe ich das noch nicht verstanden und zweitens
bleibt dann noch die zweite Frage:
2) Wie entscheide ich wann ich was decodieren muss ? Oder kann ich
einen UTF8 decoder einfach immer auf den gesamten Inhalt loslassen ?
3) WO decodiere ich ( also im Ablauf ) ? Ich glaube es müsste so sein:
- String "as is" vom Server holen
- UTF8 decodieren wenn nötig
- Header parsen (my $hdref =3D $imap->parse_headers($this,'ALL');)
- TEXT der Header und ev. des Bodys ggf. weiter konvertieren ( von
iso-2022-jp nach iso8859-1 oder so )
ODER: ( alternative und vermutlich bessere Methode, weiss nur nicht wie
realisieren ) : Mailstring gar nicht dekodieren sondern als UTF8-HTML
sichern. Aber wie mach ich dann das mit den Headern ( ich "html-isiere
den Body indem ich z.B. aus me@you.com ein
href=3D"mailto:me@you.com">my@you.com mache. Das wird dann mit nem
UTF8 Mailstring "etwas" schwierig, oder ?
Gruss und danke für die Lesegeduld...
Wolfgang
Re: Unicode Emails vom Server als HTML files sichern oder so aehnlich..
am 14.06.2006 12:16:17 von Oliver Block
wolfgang wrote:
> Hallo NG,
>
> ich habe ein Problem mit Japanern :-) Sie schicken UTF8 Mails.
[...]
> Das PROBLEM ist jetzt, dass da zunehmend Mails in nicht-ISO8859-1
> ankommen.
Das war wahrscheinlich schon vorher so, nur ist es Dir nicht aufgefallen.
Jede Mail enthält entweder ein Feld Content-Type, oder es wird angenommen,
daß es sich um 'text/plain' im US-ASCII Format handelt. Falls Content-Type
zwar einen anderen Type enthält, aber das Content-Type Feld kein charset
Parameter, wie z.B. charset=UTF-8, oder charset=ISO-8859-1, dann wird
angenommen es handelt sich um charset=US-ASCII.
> Es gibt welche, die sind nur in Teilen anders codiert, zum
> Beispiel sieht dann der Subject so aus:
>
> Subject:
> =?iso-2022-jp?B?U09OWRskQiEhGyhCSWNoaW5vbWl5YS9GYWlsdXJlIEFu YWx5c2k=?=
> =?iso-2022-jp?B?cyBJbml0aWF0aW9uIGZvcm06IDA2LTA4OTsgUURCIEpv YiAxNTk3Mg==?=
Das sind sog. 'encoded words' (RFC2047), Der Zeichensatz ist hier übrigens
nicht UTF-8 wie Du sehen kannst, sondern ISO-2022-jp. Das B, nach dem
zweiten ? verrät Dir, daß der Inhalt nach dem 3. ? BASE64 encodiert ist.
Hier könnte außer dem B noch ein Q stehen. Das wäre ein Indikator für ein
'quoted printable' encoding.
perldoc Encode::MIME::Header
Für weiteres:
perldoc MIME::Tools (line 367 "Understand how international characters are
represented")
Gruß,
Oliver
Re: Unicode Emails vom Server als HTML files sichern oder so aehnlich..
am 15.06.2006 22:40:56 von hjp-usenet2
wolfgang wrote:
> ich habe ein Problem mit Japanern :-) Sie schicken UTF8 Mails.
Dein Beispiel ist aber ISO-2022-JP, nicht UTF-8.
> Ich hole Emails von einem IMAP Server ab ud speichere sie incl.
> Anhängen als HTML Files auf einer Pladde. Das geht seit langem etwa
> so: (sinngemäss, habe zwecks Erklärung massig Zeugs, z.B. das
> attachement handling und die HTML-isierung rausgeworfen ):
>
> use Mail::IMAPClient; # for the imap server connection
> use MIME::Parser; # for the mime mail parsing
> use MIME::Parser::Filer; # to store parser objects to disk
> use MIME::WordDecoder; # to handle iso-8859-1 encoded strings
MIME::WordDecoder kann laut Manpage nur ISO-8859-*, für alles andere
muss man sich selber Decoder schreiben. Ein kurzer Test bestätigt das:
% cat test-mime-worddecoder
#!/usr/bin/perl
use MIME::WordDecoder;
my $h =
'=?iso-2022-jp?B?U09OWRskQiEhGyhCSWNoaW5vbWl5YS9GYWlsdXJlIEF uYWx5c2k=?=
=?iso-2022-jp?B?cyBJbml0aWF0aW9uIGZvcm06IDA2LTA4OTsgUURCIEpv YiAxNTk3Mg==?=
';
my $h2 = unmime($h);
print "$h2\n";
% ./test-mime-worddecoder
ignoring text in character set `ISO-2022-JP'
at ./test-mime-worddecoder line 9
ignoring text in character set `ISO-2022-JP'
at ./test-mime-worddecoder line 9
11
Somit weià ich jetzt wieder, warum ich das nicht verwende, sondern meine
eigene Implementation geschrieben habe. Sind ohnehin nur ein paar
Zeilen:
---8<------8<------8<------8<------8<------8<------8<------8<---
=head2 _decode_rfc2047
decode a string encoded according to RFC 2047
The returned string is in internal perl string representation and has
the UTF-8 flag set if it contains any non-ascii characters.
=cut
use MIME::Words qw(:all);
sub _decode_rfc2047 {
my ($enc) = @_;
my @words = decode_mimewords($enc);
my $dec = "";
for (@words) {
eval {
$dec .= $_->[1] ? decode($_->[1], $_->[0]) : $_->[0];
};
if ($@) {
# if decoding fails for any reason (usually unknown charset)
# we just append he encoded word.
$dec .= $_->[0];
}
}
return $dec;
}
---8<------8<------8<------8<------8<------8<------8<------8<---
hp
--
_ | Peter J. Holzer | Man könnte sich [die Diskussion] auch
|_|_) | Sysadmin WSR/LUGA | sparen, wenn man sie sich einfach sparen
| | | hjp@hjp.at | würde.
__/ | http://www.hjp.at/ | -- Ralph Angenendt in dang 2006-04-15
Re: Unicode Emails vom Server als HTML files sichern oder so aehnlich..
am 17.06.2006 00:10:43 von Oliver Block
Peter J. Holzer wrote:
> MIME::WordDecoder kann laut Manpage nur ISO-8859-*, für alles andere
> muss man sich selber Decoder schreiben. Ein kurzer Test bestätigt das:
Eigentlich muß er den ganzen WordDecoder auf UTF-8 umstellen. Aber
das mag sich schwieriger anhören, als es letztendlich ist.
Alle ISO-8859 Zeichensätze sind bis Zeichen 0x7F UTF-8 Untermenge. Das
gleiche gilt komplett für US-ASCII. Er muß also ISO-8859 mit Zeichencodes >
127 in UTF-8 umwandeln. Wie das geht verrät RFC3629. Aber natürlich sollten
auch Funktionen der Module 'Encode' oder 'Recode' verwenden werden können.
Dann braucht er nur eine Funktion zu schreiben, die auf diese Module
zurückgreift und beim Erstellen (new) übergeben.
Gruß,
Oliver
Re: Unicode Emails vom Server als HTML files sichern oder so aehnlich..
am 17.06.2006 19:25:14 von hjp-usenet2
Oliver Block wrote:
> Peter J. Holzer wrote:
>> MIME::WordDecoder kann laut Manpage nur ISO-8859-*, für alles andere
>> muss man sich selber Decoder schreiben. Ein kurzer Test bestätigt das:
>
> Eigentlich muà er den ganzen WordDecoder auf UTF-8 umstellen. Aber
> das mag sich schwieriger anhören, als es letztendlich ist.
Die gröÃte Schwierigkeit dabei ist wohl, zu verstehen, was
MIME::WordDecoder überhaupt macht. Ich bin mir jedenfalls nach dem
Durchlesen der Doku und überfliegen des Source-Codes nicht sicher, ob
ich es verstanden habe (nein, ich schreibe jetzt keine Testprogramme,
um meine Vorstellungen zu überprüfen). Ziemlich klar ist aber, dass es
geschrieben wurde, bevor perl Characterstrings hatte.
> Alle ISO-8859 Zeichensätze sind bis Zeichen 0x7F UTF-8 Untermenge. Das
> gleiche gilt komplett für US-ASCII. Er muà also ISO-8859 mit Zeichencodes >
> 127 in UTF-8 umwandeln. Wie das geht verrät RFC3629.
Nein, RFC 3629 verrät, wie man ISO-10646 Codepoints in UTF-8 umwandelt.
Das ist nur für US-ASCII und ISO-8859-1 ohne Ãnderungen anwendbar. Alle
anderen ISO-8859-*-Charsets muss man zunächst auf ISO-10646 mappen. Und
im konkreten Fall geht es ohnehin um ISO-2022-JP, nicht um ISO-8859.
> Aber natürlich sollten auch Funktionen der Module 'Encode' oder
> 'Recode' verwenden werden können.
Encode ist wohl das Mittel der Wahl wenn man perl 5.8.x zur Verfügung
hat.
> Dann braucht er nur eine Funktion zu schreiben, die auf diese Module
> zurückgreift und beim Erstellen (new) übergeben.
Diese Funktion ist aller Wahrscheinlichkeit nach mindestens so
kompliziert wie es gleich selber zu machen.
hp
--
_ | Peter J. Holzer | Man könnte sich [die Diskussion] auch
|_|_) | Sysadmin WSR/LUGA | sparen, wenn man sie sich einfach sparen
| | | hjp@hjp.at | würde.
__/ | http://www.hjp.at/ | -- Ralph Angenendt in dang 2006-04-15
Re: Unicode Emails vom Server als HTML files sichern oder so aehnlich..
am 18.06.2006 01:24:29 von Oliver Block
Peter J. Holzer wrote:
> Die größte Schwierigkeit dabei ist wohl, zu verstehen, was
> MIME::WordDecoder überhaupt macht.
Es dekodiert sog. 'encoded words'. Email Header dürfen 7Bit-Zeichen
(US-ASCII) enthalten (RFC2822). Encoded words bieten die Möglichkeit auch
8Bit Zeichen einzusetzen. (RFC2047). Weil encoded words vor dem Versenden
entweder base64- oder 'quoted-printable'-kodiert werden, enthalten die
Emailheader nun wieder ausschließlich 7Bit Zeichen. Der empfangende MUA
(Mail User Agent) muß nun die 'encoded words' dekodieren. Dafür wird
MIME::WordDecoder eingesetzt.
> Ziemlich klar ist aber, dass es
> geschrieben wurde, bevor perl Characterstrings hatte.
???. Bisher war für mich ein String ein String. Genaugenommen erscheint in
Perl ja alles irgendwie wie ein String.:)
> Nein, RFC 3629 verrät, wie man ISO-10646 Codepoints in UTF-8 umwandelt.
> Das ist nur für US-ASCII und ISO-8859-1 ohne Änderungen anwendbar.
Fast richtig.
> Alle
> anderen ISO-8859-*-Charsets muss man zunächst auf ISO-10646 mappen.
Alle ISO-8859-* sind bis Zeichen 127 identisch. Erst ab 128 unterscheiden
sie sich.
Aber es bleibt das Problem der Zeichen 128- / Hier ja noch andere
Zeichensätze.
>> Dann braucht er nur eine Funktion zu schreiben, die auf diese Module
>> zurückgreift und beim Erstellen (new) übergeben.
>
> Diese Funktion ist aller Wahrscheinlichkeit nach mindestens so
> kompliziert wie es gleich selber zu machen.
Nein. Du mußt nur eine Callback-Funktion definieren, die Encode/Recode auf
'$_' anwendet. Auf den ersten Blick scheint das ein 3-Zeiler zu sein.
Gruß,
Oliver
Re: Unicode Emails vom Server als HTML files sichern oder so aehnlich..
am 18.06.2006 07:42:46 von Slaven Rezic
Oliver Block writes:
> Peter J. Holzer wrote:
[...]
>
> > Ziemlich klar ist aber, dass es
> > geschrieben wurde, bevor perl Characterstrings hatte.
>
> ???. Bisher war für mich ein String ein String. Genaugenommen erscheint in
> Perl ja alles irgendwie wie ein String.:)
>
Peter spricht wahrscheinlich auf den Unterschied zwischen "octets" und
"characters", wie er in Description/Terminology der Encode-Manpage
beschrieben ist, an.
Gruß,
Slaven
--
Slaven Rezic - slaven rezic de
tknotes - A knotes clone, written in Perl/Tk.
http://ptktools.sourceforge.net/#tknotes
Re: Unicode Emails vom Server als HTML files sichern oder so aehnlich..
am 18.06.2006 12:44:32 von hjp-usenet2
Oliver Block wrote:
> Peter J. Holzer wrote:
>> Die gröÃte Schwierigkeit dabei ist wohl, zu verstehen, was
>> MIME::WordDecoder überhaupt macht.
>
> Es dekodiert sog. 'encoded words'. Email Header dürfen 7Bit-Zeichen
> (US-ASCII) enthalten (RFC2822). Encoded words bieten die Möglichkeit auch
> 8Bit Zeichen einzusetzen. (RFC2047).
Das brauchst Du mir nicht zu erklären. Ich habe den Vorgänger von RFC
2047 gelesen, als er neu war. Das war Ende 1993.
Das Problem ist, dass die Doku IMHO widersprüchlich ist und der Code
soweit ich sehe nicht mal das abdeckt, was die Doku zu versprechen
scheint (Abgesehen davon, dass er ziemlich redundant ist).
>> Ziemlich klar ist aber, dass es geschrieben wurde, bevor perl
>> Characterstrings hatte.
>
> ???. Bisher war für mich ein String ein String. Genaugenommen erscheint in
> Perl ja alles irgendwie wie ein String.:)
Seit Perl 5.6 sind Strings in Perl nicht mehr Folgen von 8-Bit-Werten
sondern Folgen von 32-Bit-Werten. Intern werden sie entweder als
einfache Bytestrings (nur möglich, wenn alle Zeichen Codes <= 0xFF
haben) oder als UTF-8-kodierte Strings abgespeichert.
Für den Programmierer ergibt sich daraus zusätzlich noch die
Schwierigkeit, dass er sich darüber im Klaren sein muss, ob seine
Strings jetzt "Byte-Semantik" (d.h., sie stellen eine Folge von
8-Bit-Werten dar, deren Bedeutung nur durch die Programmlogik bestimmt
wird) oder "Character Semantik" (d.h., es sind Folgen von
(Unicode-)Zeichen) haben. (Streng genommen ist das nicht neu, man konnte
nur früher den Unterschied zwischen "8-Bit-Byte" und "8-Bit-Character"
häufiger ignorieren)
Das MIME::WordDecoder Modul kennt offensichtlich nur Byte-Strings. Es
verwendet auch des Encode-Modul nicht. Daraus läÃt sich schlieÃen, dass
es vor Perl 5.8.0 geschrieben wurde und seitdem nicht mehr aktualisiert
wurde. In der Tat ist durch Encode der ganze Mechanismus mit dem
Registrieren von charsets einigermaÃen sinnlos geworden und man könnte
das 600-Zeilen Modul auf ca. 50 Zeilen (inkl. Doku) kürzen.
>> Nein, RFC 3629 verrät, wie man ISO-10646 Codepoints in UTF-8 umwandelt.
>> Das ist nur für US-ASCII und ISO-8859-1 ohne Ãnderungen anwendbar.
>
> Fast richtig.
Was ist daran falsch?
>> Alle anderen ISO-8859-*-Charsets muss man zunächst auf ISO-10646
>> mappen.
>
> Alle ISO-8859-* sind bis Zeichen 127 identisch. Erst ab 128 unterscheiden
> sie sich.
Erzähl mir was neues. Das ist irrelevant. Wenn Du ISO-8859-2 richtig
behandeln willst, musst Du auch die Zeichen über 0x7F richtig behandeln.
Wenn Du nur Zeichen bis 0x7F richtig behandelst, dann behandelst Du
US-ASCII, nicht ISO-8859-2.
>>> Dann braucht er nur eine Funktion zu schreiben, die auf diese Module
>>> zurückgreift und beim Erstellen (new) übergeben.
>>
>> Diese Funktion ist aller Wahrscheinlichkeit nach mindestens so
>> kompliziert wie es gleich selber zu machen.
>
> Nein. Du muÃt nur eine Callback-Funktion definieren, die Encode/Recode auf
> '$_' anwendet. Auf den ersten Blick scheint das ein 3-Zeiler zu sein.
Ungefähr so lange ist meine Lösung auch.
hp
--
_ | Peter J. Holzer | Man könnte sich [die Diskussion] auch
|_|_) | Sysadmin WSR/LUGA | sparen, wenn man sie sich einfach sparen
| | | hjp@hjp.at | würde.
__/ | http://www.hjp.at/ | -- Ralph Angenendt in dang 2006-04-15
Re: Unicode Emails vom Server als HTML files sichern oder so aehnlich..
am 19.06.2006 23:25:59 von Michael Perle
Peter J. Holzer wrote:
> Seit Perl 5.6 sind Strings in Perl nicht mehr Folgen von 8-Bit-Werten
> sondern Folgen von 32-Bit-Werten. Intern werden sie entweder als
> einfache Bytestrings (nur möglich, wenn alle Zeichen Codes <= 0xFF
> haben) oder als UTF-8-kodierte Strings abgespeichert.
>
> Für den Programmierer ergibt sich daraus zusätzlich noch die
> Schwierigkeit, dass er sich darüber im Klaren sein muss, ob seine
> Strings jetzt "Byte-Semantik" (d.h., sie stellen eine Folge von
> 8-Bit-Werten dar, deren Bedeutung nur durch die Programmlogik bestimmt
> wird) oder "Character Semantik" (d.h., es sind Folgen von
> (Unicode-)Zeichen) haben.
Ich habe mir meinen Reim draufgemacht und seit langem
ohne Probleme alle möglichen Zeichensaetze bearbeitet:
Alles, was ich lese, dekodiere ich (binmode oder Encode).
Dann ist es fuer mich ein "Perl-String".
Wie der Perl-String kodiert ist kann mir im Prinzip
wurscht sein. Ob es UTF-8 plus Unicode-Flag ist oder ein
perl-eigener Dialekt, würde ich zwar gerne wissen, aber
ich brauche es nicht. Ich kann alles mit dem String
machen, was ich will.
Wenn ich ihn dann ausgeben will, dann brauche
ich den (Perl-) String nur in das gewuenschte Format
zu kodieren (Encode::encode) oder -- noch einfacher --
den zum schreiben geoeffneten Dateihandle mittels
binmode vorzubereiten.
Um den Programmcode nicht mit erweiterten Zeichensaetzen
zu "belasten" lasse ich den Code wo irgend moeglich in
7-Bit-ASCII. Da ich sowieso sehr gerne Konfigurationen
und HTML-Templates etc. verwende, gehoeren die meisten
Strings fuer mich ohnehin nicht direkt in den Code.
Vielleicht hilft es ja ein bisschen, und vielleicht
weisz irgendein Schlaumeier genaueres dazu zu sagen.
MP