AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Netzwerke .eml Dateien auslesen - wie decodieren?
Thema durchsuchen
Ansicht
Themen-Optionen

.eml Dateien auslesen - wie decodieren?

Ein Thema von nezumi7 · begonnen am 5. Nov 2013 · letzter Beitrag vom 17. Dez 2013
Antwort Antwort
Seite 1 von 2  1 2      
nezumi7

Registriert seit: 11. Apr 2011
71 Beiträge
 
#1

.eml Dateien auslesen - wie decodieren?

  Alt 5. Nov 2013, 08:27
Hallo,

ich habe alle meine emails als ".eml"-Dateien auf der Festplatte gespeichert. Um da ein System reinzubringen, möchte ich Absender, Empfänger, Datum, Betreff, Anhänge(Namen) und den Nachrichtentext auslesen und in einer Datenbank ablegen.

Ich muss die Nachrichten nicht vom Server abholen und brauch keine Internetverbindung.

Bei Indy gibts ein Beispiel für ein email-Programm, das ich versucht habe so zu ändern, dass anstatt "Retrieve.Message", die Nachricht von der Festplatte geladen wird.


Code:
begin
If opendialog1.Execute then begin
{stTemp := Statusbar1.Panels[1].text;
   if lvHeaders.Selected = nil then
      begin
         Exit;
      end; }
//Showbusy(true);
   Msg.Clear;
   Memo1.Clear;
   //lvMessageParts.Items.Clear;
   From.Caption := '';
   Cc.Caption := '';
   Subject.Caption := '';
   Date.Caption := '';
   Receipt.Caption := '';
   Organization.Caption := '';
   Priority.Caption := '';
   pnlAttachments.visible := false;

//get message and put into MSG
   //ShowStatus('Retrieving message "' + lvHeaders.Selected.SubItems.Strings[3] + '"');
   //POP.Retrieve(lvHeaders.Selected.Index + 1, Msg);
   msg.LoadFromFile(opendialog1.FileName);
   //statusbar1.Panels[0].text := lvHeaders.Selected.SubItems.Strings[3];
//Setup fields on screen from MSG
   From.Caption := Msg.From.Text;
   Recipients.Caption := Msg.Recipients.EmailAddresses;
   Cc.Caption := Msg.CCList.EMailAddresses;
   Subject.Caption := Msg.Subject;
   Date.Caption := FormatDateTime('dd mmm yyyy hh:mm:ss', Msg.Date);
   Receipt.Caption := Msg.ReceiptRecipient.Text;
   Organization.Caption := Msg.Organization;
   Priority.Caption := IntToStr(Ord(Msg.Priority) + 1);
//Setup attachments list
   ShowStatus('Decoding attachments (' + IntToStr(Msg.MessageParts.Count) + ')');
   for intIndex := 0 to Pred(Msg.MessageParts.Count) do
      begin
         if (Msg.MessageParts.Items[intIndex] is TIdAttachmentFile) then
            begin //general attachment
               pnlAttachments.visible := true;
               li := lvMessageParts.Items.Add;
               li.ImageIndex := 8;
               li.Caption := TIdAttachmentFile(Msg.MessageParts.Items[intIndex]).Filename;
               li.SubItems.Add(TIdAttachmentFile(Msg.MessageParts.Items[intIndex]).ContentType);
            end
         else
            begin //body text
               if Msg.MessageParts.Items[intIndex] is TIdText then
                  begin
                     Memo1.Lines.Clear;
                     Memo1.Lines.AddStrings(TIdText(Msg.MessageParts.Items[intIndex]).Body);
                  end
            end;
      end;
   //ShowStatus(stTemp);
   //Showbusy(false);

end;
end;
Das klappt alles wunderbar, nur beim eigentlichen Nachrichtentext kommt entweder gar nix, oder ein Text mit lauter html-tags oder es werden Umlaute nicht richtig dargestellt.

Ich weiß, dass man das noch irgendwie decodieren muss ("quoted-printable", "mime", "utf-8"), hab aber keine Idee, wie das geht.

Kann mir da jemand einen Tipp geben?
Geht das überhaupt grundsätzlich?

Danke,
Stephan
  Mit Zitat antworten Zitat
mjustin

Registriert seit: 14. Apr 2008
3.006 Beiträge
 
Delphi 2009 Professional
 
#2

AW: .eml Dateien auslesen - wie decodieren?

  Alt 5. Nov 2013, 09:36
Ist es eventuell eine ältere Indy Version? Aktuell ist 10.6, und man muss sie nach dem Download nicht "installieren" sondern nur die Source-Verzeichnisse dem Projekt hinzufügen. (Die alte Indy Version braucht dazu auch nicht deinstalliert zu werden.)
Michael Justin
  Mit Zitat antworten Zitat
nezumi7

Registriert seit: 11. Apr 2011
71 Beiträge
 
#3

AW: .eml Dateien auslesen - wie decodieren?

  Alt 5. Nov 2013, 14:13
Vielen Dank für den Tipp. Ich habe Delphi 6 und Indy 10 Komma irgendwas, werde das heute Abend dann mal mit Indy 10.6 ausprobieren und berichten.

Wenn ich Dich richtig verstanden habe, braucht man überhaupt keinen Decoder einbauen und verwenden? Mich macht stutzig, dass es bei Indy so viele davon gibt...

LG, Stephan.
  Mit Zitat antworten Zitat
nezumi7

Registriert seit: 11. Apr 2011
71 Beiträge
 
#4

AW: .eml Dateien auslesen - wie decodieren?

  Alt 5. Nov 2013, 18:01
So, ich hab jetzt die neueste Indy Version (10.6). Leider ist das Problem dadurch nicht behoben...

Hat noch jemand eine Idee?

LG, Stephan.
  Mit Zitat antworten Zitat
Benutzerbild von Harry Stahl
Harry Stahl

Registriert seit: 2. Apr 2004
Ort: Bonn
2.538 Beiträge
 
Delphi 11 Alexandria
 
#5

AW: .eml Dateien auslesen - wie decodieren?

  Alt 6. Nov 2013, 14:55
Das kann man gar nicht so abschließend beantworten. Aber vielleicht helfen ein paar Informationen weiter, mit denen Du Deine eigenen Rückschlüsse ziehen kannst:

Mails bestehen grob gesagt aus Header, Body und Anhängen.

Der Mailtext wird dabei oft als "text/plain" verschickt, dann ist er im Body zu finden. Oder (nur) als "text/html", dann ist er bei den Indys in den Messageparts zu finden. Oft gibt es auch beides, also den reinen Text und eine alternative Fassung des Textes, die ist dann auch den "Messageparts" zu finden. Das sind dann i.d.R. HTML-Fassungen, könnte aber auch (ganz, ganz selten) RTF sein. Im Mailheader ist darüber eine Info zu finden, dort steht dann z.B. "multipart/alternative". Ich habe aber auch schon erlebt, dass im Body-Text eine Art Mini-HTML verwendet wurde, der Text aber als "text/plain" deklariert wurde.

Und Letzteres ist ein Beispiel für die ganzen Probleme beim Mails entschlüsseln und auch für die Limits, die in den Indy-Komponenten stecken. Indy's arbeiten voll RFC-Konform, also nach internationalen Standards. Aber that's it. Wenn eine Mail einen Standard nicht einhält, dann wird eben ein Fehler ausgeworfen, eine weitere Abarbeitung der Mail findet dann ab der fehlerhaften Stelle nicht mehr statt.

Und es sind massenweise fehlerhafte Mails unterwegs, von irgendwelchen Web-Mailversendern, Eigenkonstruktionen von Firmen, was auch immer. Aus diesem Grunde rufe ich für mein Mail-Programm (Safer Mail) die Mails in der RAW-Fassung ab, also so, wie der Server mir die Daten anliefert, die Interpretation der Mails mache ich dann selber (was auch nicht einfach ist und selbst nach 10 Jahren Arbeit daran immer wieder nachtjustiert werden muss).

Will damit sagen, dass Du für Dein Projekt möglicherweise nicht alles 100%-tig dekodieren kannst, es sei denn, Du willst einen irren Aufwand dafür betreiben.

Du solltest also für Dein Projekt prüfen, ob der Body einen Text hat. Wenn ja, OK. Wenn nicht, dann must Du die Messageparts durchlaufen und anhand der Content-Type-Informationen prüfen, welche Textart vorliegt. Dann kannst Du z.B. aus einer HTML-Mail eine reine Textmail machen (hier gibt es diverse Units im Netz zu finden, nach "HTML to Text" suchen), es sei denn Du willst lieber die HTML-Fassung verwenden, die könntest Du dann in einer TWebbrowser-Komponente anzeigen lassen. Wenn der HTML-Text aber Schadcode enthalten sollte, könnte das ein Risiko sein, weil die TWebBrowser-Komponente für sich alleine keine Schutzfunktionen bietet.

Da gibt es aber auch noch ein paar andere Fallstricke, z.B. bei Textteilen, die als "inline" deklariert sind (prüft man im "Content-Disposition"-Eintrag). Die landen in den Messageparts und Du musst dann unter Umständen aus mehreren Messageparts einen einheitlichen Text gestalten. So gibt es Konstruktionen (z.B. bei Apple-Mails hatte ich schon diverse Fälle), wo der eigentliche Mailtext aus einer Komposition von einfachen ANSI-Texten und HTML-Texten bestand. Um das irgendwie anzeigen zu können, muss man daraus entweder einen neuen HTML-Text basteln oder eben alles in reinen Text umwandeln.

Soweit die TidMessage-Komponente die Decodierung des in der Mail verwendeten Charsets nicht anbietet oder aufgrund einer fehlerhaften Komposition der Mail nicht schafft, musst Du den Mailtext selbst decodieren. Da kann z.B. in der einfachsten Form die Funktion "Utf8ToAnsi" verwendet werden, wenn ein UTF-8 codierter Text vorliegt. Die charset-Information findest Du im Header als Zusatz für den Content-Type bzw. jeweils bei den Messageparts.

Leider kann ich keinen Beispiel-Source-Code posten, da ich es ja wie gesagt, für meine Zwecke anders gelöst habe (neben den erläuterten technischen Gründen vor allem aber, um das Bedrohungspotential der Mail besser beurteilen zu können, bzw. in den Griff zu bekommen). Aber ich hoffe, die Ausführungen bringen Dich ein wenig weiter.

Geändert von Harry Stahl ( 6. Nov 2013 um 15:15 Uhr)
  Mit Zitat antworten Zitat
nezumi7

Registriert seit: 11. Apr 2011
71 Beiträge
 
#6

AW: .eml Dateien auslesen - wie decodieren?

  Alt 6. Nov 2013, 18:46
Hallo Harry,

super! Vielen Dank für Deine ausführlichen Erläuterungen. Das hilft mir auf jeden Fall schon mal weiter, weil ich einfach nicht wusste, ob man nicht lediglich bei einer Indy Komponente irgendeine Eigenschaft einstellen muss - und gut ist. So wie Du schreibst, ist wohl trotz Indy noch viel Handarbeit erforderlich und jetzt weiß ich zumindest, wo ich ansetzen muss, um mich da durchzufrickeln...

Thanks a lot,

Stephan
  Mit Zitat antworten Zitat
musicman56
(Gast)

n/a Beiträge
 
#7

AW: .eml Dateien auslesen - wie decodieren?

  Alt 7. Nov 2013, 02:06
Hallo Harry,

von mir auch ein herzliches Dankeschön. Ich kämpfe gerade auch mit diesem Thema.
  Mit Zitat antworten Zitat
nezumi7

Registriert seit: 11. Apr 2011
71 Beiträge
 
#8

AW: .eml Dateien auslesen - wie decodieren?

  Alt 1. Dez 2013, 09:57
So, ich nochmal,

nachdem ich mein Prog so einigermaßen hinbekommen habe, taucht ein Problem auf, an dem ich mir die Zähne ausbeiße.

Erst Mal der Code, soweit relevant:

Delphi-Quellcode:
msg.LoadFromFile(FileName);
If (msg.ContentType = 'text/plain') or (msg.ContentType = 'text/html') then begin
   vtext := msg.Body.Text;
end else begin
      for intIndex := 0 to Pred(msg.MessageParts.Count) do begin
         
         if (msg.MessageParts.Items[intIndex] is TIdAttachmentFile) then begin //general attachment
         Listbox1.Items.Add(TIdAttachmentFile(msg.MessageParts.Items[intIndex]).Filename);
         end else begin //body text
            
            if msg.MessageParts.Items[intIndex] is TIdText then begin
            sl_temp.AddStrings(TIdText(msg.MessageParts.Items[intIndex]).Body);
            end
      
         end;
      end;
vtext := sl_temp.Text;
sl_temp.Clear;
end;

If (Pos('<html>',Copy(vtext,1,20)) > 0)
or ((Pos('<',Copy(vtext,1,5)) > 0) and ((Pos('>',Copy(vtext,1,100)) > 0) or (Pos('style=',Copy(vtext,1,100)) > 0) or (Pos('class=',Copy(vtext,1,100)) > 0) ))
then begin
vtext := htmltotxt(vtext);
end;
If Pos('Ã',vtext) > 0 then begin
   temp := vtext;
   vtext := utf8toansi(vtext);
      If vtext = 'then begin
      vtext := temp;
      vtext := utf8decode2(vtext);
      end;
end;
Wie ihr seht,lege ich den eigentlichen Text der email in der Variablen "vtext" ab.

Bei einigen emails kommt da aber nur der halbe Text an. Nach langem Rumgesuche habe ich festgestellt, dass der Text immer dort abgeschnitten wird, wo eine Zeile nur aus einem einzelnen Punkt besteht. Das ist vor allem dort so, wo im nicht decodierten Text der Zeilenumbruch durch ein = gekennzeichnet wird (weiß nicht, was das für ein Format ist), also z.B.:

"Er wohnt dort =FCbrigens in London=
."

Hier hat der Punkt wohl nicht mehr in die Zeile gepasst und ist in die nächste gerutscht. Wenn ich den Text mit dem obigen Code lade, hört er vor dem Punkt auf (obwohl die email noch weitergeht).

Jetzt meine Frage:

Kann ich die Nachricht, nachdem ich sie in "msg" geladen habe textmäßig bearbeiten und dann wieder an msg übergeben? Dann würde ich nämlich erst alle Zeilen löschen, die nur aus einem Punkt bestehen.

Also z.B. so:
Delphi-Quellcode:
stringlist1 := msg.text;
lc := stringlist1.count;
i := 0;
repeat
if stringlist1.strings[i] = '.then begin
stringlist1.delete[i];
dec(lc);
end else begin
inc(i);
end;
until
i=lc;

msg.text := stringlist1.text
Aber das geht natürlich nicht, weil es ja sowas wie "msg.text" nicht gibt.

Any idea??
  Mit Zitat antworten Zitat
Klaus01

Registriert seit: 30. Nov 2005
Ort: München
5.771 Beiträge
 
Delphi 10.4 Sydney
 
#9

AW: .eml Dateien auslesen - wie decodieren?

  Alt 1. Dez 2013, 10:15
.. ob das hier eine Rolle spielt weiß ich nicht.
Aber wenn ich mich recht entsinne bezeichnet ein allenstehender "." in einer Zeile
im pop3 Protokoll das Ende einer Nachricht.

Grüße
Klaus
Klaus
  Mit Zitat antworten Zitat
nezumi7

Registriert seit: 11. Apr 2011
71 Beiträge
 
#10

AW: .eml Dateien auslesen - wie decodieren?

  Alt 1. Dez 2013, 11:47
ja, das hab ich auch gelesen. Hilft mir aber nicht weiter.

Ich hab jetzt versucht, die .eml Datei in eine Stringlist zu laden (da will ich dann die Punkte rausmachen), den Stringlist-Text in ein MemoryStream zu schreiben und von dort die IDMessage zu laden:

Delphi-Quellcode:
procedure TForm1.Button6Click(Sender: TObject);
var
sl: TStringlist;
eintrag, empf: String;
tsm: TMemoryStream;
begin
If OpenDialog1.Execute then begin
sl := TStringlist.Create;
tsm := TMemoryStream.Create;
sl.LoadFromFile(OpenDialog1.FileName);
//hier noch: einzelne Punkte rausmachen
sl.SaveToStream(tsm);
msg.LoadFromStream(tsm);

empf := msg.From.Text;
Label1.Caption := empf;

tsm.Free;
sl.Free;
end;

end;
....geht aber nicht. (Label1 müsste ja z.B. den Empfänger anzeigen. Tuts aber nicht. "empf" ist leer)
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 20:50 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz