AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein Delphi Plaintext aus .EML-Datei extrahieren?
Thema durchsuchen
Ansicht
Themen-Optionen

Plaintext aus .EML-Datei extrahieren?

Ein Thema von PeterPanino · begonnen am 7. Apr 2016 · letzter Beitrag vom 8. Apr 2016
Antwort Antwort
Seite 1 von 2  1 2      
PeterPanino

Registriert seit: 4. Sep 2004
1.465 Beiträge
 
Delphi 10.4 Sydney
 
#1

Plaintext aus .EML-Datei extrahieren?

  Alt 7. Apr 2016, 18:06
Hallo und schönen Tag!

Ich möchte in Delphi 10 Seattle den Plaintext des body und die anderen Mailfelder aus einer .EML-Datei (von Thunderbird gespeichert, kann eine HTML-Mail oder eine Plaintext-Mail enthalten) auslesen. Das funktioniert mit dem folgenden Code nur zum Teil:

Delphi-Quellcode:
//uses IdText...

procedure TForm1.ExtractPlainTextFromEMLFileContainingHTMLMail;
// Drop a TIdMessage component on the form and name it "IdMessage"
var
  IndyStringList: TStringList;
  IndyStream: TMemoryStream;
  I: Integer;
const
  CRLF = #13#10;
begin
  IndyStringList := TStringList.Create;
  IndyStream := TMemoryStream.Create;
  try
    IndyStringList.LoadFromFile('C:\Ihre Bestellung.eml');
    IndyStringList.Add(CRLF + '.' + CRLF);
    IndyStringList.SaveToStream(IndyStream);
    IndyStream.Position := 0;
    IdMessage.Clear;
    IdMessage.LoadFromStream(IndyStream);
    Memo1.Clear;
    Memo1.Lines.Assign(IdMessage.Headers);
    Memo2.Clear;
    Memo2.Lines.Add(IdMessage.From.Text);
    Memo2.Lines.Add(IdMessage.Recipients.EMailAddresses);
    Memo2.Lines.Add(IdMessage.Subject);
    Memo2.Lines.Add(DateTimeToStr(IdMessage.Date));
    Memo2.Lines.Add('');
    for I := 0 to IdMessage.MessageParts.Count - 1 do
      if IdMessage.MessageParts.Items[I] is IdText.TidText then
      begin
        Memo2.Lines.Add(IdText.TidText(IdMessage.MessageParts.Items[I]).Body.Text);
        // This is called TWICE. The first time it gets this text:
        // 'This is a multi-part message in MIME format.'
        // The second time it gets the HTML code of the message body
        // So how can I get the plain-text of the message body?
      end;
  finally
    IndyStringList.Free;
    IndyStream.Free;
  end;
end;
In der for-Schleife erhalte ich zwei Ergebnisse:

1. Wie kann das Programm zur Laufzeit wissen, welches der beiden der Plaintext-body ist?

2. Wenn das Ergebnis ein HTML-Code ist: Wie kann aus diesem der Plaintext decodiert werden?
  Mit Zitat antworten Zitat
nahpets
(Gast)

n/a Beiträge
 
#2

AW: Plaintext aus .EML-Datei extrahieren?

  Alt 7. Apr 2016, 18:31
Ob plain/text oder html/text sollte im Contenttyp stehen.

Sowas in der Art: Content-Type: text/plain; charset="utf-8" bzw. Content-Type: text/html; charset="utf-8"

Wenn ich unbedingt aus HTML reinen Text machen muss, dann gehe ich so vor:
  1. Vor allen < einen Zeilenumbruch einfügen.
  2. Hinter allen > einen Zeilenumbruch einfügen.
  3. Alle Texte, die sich zwischen zwei mit < beginnenden Zeilen befinden, zu einer Zeile zusammenfügen.
  4. Aus allen Zeilen, die mit < beginnen, eine Leerzeile machen.
  5. Mehrere aufeinanderfolgende Leerzeilen durch eine Leerzeile ersetzen.
  6. "Überlange" Zeilen mit WrapText auf das gewünschte Maß "stutzen".
Dabei geht natürlich jegliche Textformatierung verloren.
  Mit Zitat antworten Zitat
PeterPanino

Registriert seit: 4. Sep 2004
1.465 Beiträge
 
Delphi 10.4 Sydney
 
#3

AW: Plaintext aus .EML-Datei extrahieren?

  Alt 7. Apr 2016, 18:48
Ob plain/text oder html/text sollte im Contenttyp stehen.
Das beantwortet aber nicht die Frage, welches der beiden der Plaintext-body ist. Denn es könnte ja auch eine Plaintext-Mail mit dem body 'This is a multi-part message in MIME format.' sein.
  Mit Zitat antworten Zitat
nahpets
(Gast)

n/a Beiträge
 
#4

AW: Plaintext aus .EML-Datei extrahieren?

  Alt 7. Apr 2016, 19:11
Jeder Part einer Mail sollte seinen eigenen Contenttyp haben.

Gibt es in 'ner Mail sowohl HTML als auch reinen Text, so sollte die Mail zwei MessageParts haben, einen mit Contenttyp html/text und einen mit plain/text. Für die Mail selbst gilt: 'This is a multi-part message in MIME format.'

Das musst Du halt nachschauen und dann den gewünschten Teil verarbeiten.

Beide Teile müssten vom Typ IdText.TidText sein.
  Mit Zitat antworten Zitat
PeterPanino

Registriert seit: 4. Sep 2004
1.465 Beiträge
 
Delphi 10.4 Sydney
 
#5

AW: Plaintext aus .EML-Datei extrahieren?

  Alt 7. Apr 2016, 21:24
Vielen Dank, ContentType war der richtige Tipp. Dieser Code ergibt jetzt den body:

Delphi-Quellcode:
for I := 0 to IdMessage.MessageParts.Count - 1 do
begin
  if IdMessage.MessageParts.Items[I] is IdText.TidText then
  begin
    if IdText.TidText(IdMessage.MessageParts.Items[I]).ContentType = 'text/htmlthen
      Memo2.Lines.Add(IdText.TidText(IdMessage.MessageParts.Items[I]).Body.Text);
  end;
end;
  Mit Zitat antworten Zitat
PeterPanino

Registriert seit: 4. Sep 2004
1.465 Beiträge
 
Delphi 10.4 Sydney
 
#6

AW: Plaintext aus .EML-Datei extrahieren?

  Alt 7. Apr 2016, 21:44
I habe mir jetzt selbst eine Email geschickt, die sowohl Reintext als auch HTML enthält, und die empfangene Email dann als .EML abgespeichert:

reintext-un-html.png

Wenn ich aber die IdMessage.MessageParts.Items dieser .EML-datei durchgehe, so ist keines darunter, das den ContentType plain/text hat! Wieso nicht?
  Mit Zitat antworten Zitat
PeterPanino

Registriert seit: 4. Sep 2004
1.465 Beiträge
 
Delphi 10.4 Sydney
 
#7

AW: Plaintext aus .EML-Datei extrahieren?

  Alt 7. Apr 2016, 21:52
Grummel! Es muss nicht 'plain/text' heißen, sondern 'text/plain; format=flowed' - dann kriege ich den Plaintext-body!

Aber was bedeutet "format=flowed"?
  Mit Zitat antworten Zitat
PeterPanino

Registriert seit: 4. Sep 2004
1.465 Beiträge
 
Delphi 10.4 Sydney
 
#8

AW: Plaintext aus .EML-Datei extrahieren?

  Alt 7. Apr 2016, 22:15
Ich habe jetzt diesen Code produziert:

Delphi-Quellcode:
for I := 0 to IdMessage.MessageParts.Count - 1 do
begin
  if IdMessage.MessageParts.Items[I] is IdText.TidText then
  begin
    if Pos('text/plain', IdText.TidText(IdMessage.MessageParts.Items[I]).ContentType) > 0 then
    begin
      PlaintextBody := IdText.TidText(IdMessage.MessageParts.Items[I]).Body.Text;
      BREAK;
    end
    else if IdText.TidText(IdMessage.MessageParts.Items[I]).ContentType = 'text/htmlthen
      HTMLBody := IdText.TidText(IdMessage.MessageParts.Items[I]).Body.Text;
  end;
end;

if PlaintextBody <> 'then
  Memo2.Lines.Add(PlaintextBody)
else if HTMLBody <> 'then
  Memo2.Lines.Add(ExtractTextFrom(HTMLBody));
Haltet ihr das für einigermaßen sicher?
  Mit Zitat antworten Zitat
PeterPanino

Registriert seit: 4. Sep 2004
1.465 Beiträge
 
Delphi 10.4 Sydney
 
#9

AW: Plaintext aus .EML-Datei extrahieren?

  Alt 8. Apr 2016, 07:30
Die Sache ist doch um einiges komplexer als ich dachte: "multi-part" oder "multipart", unterschiedliche Ebenen.

Delphi-Quellcode:
procedure TForm1.ExtractPlainTextFromEMLFile;
// Drop a TIdMessage component on the form and name it "IdMessage"
var
  IndyStringList: TStringList;
  IndyStream: TMemoryStream;
  I: Integer;
  HTMLBody, PlaintextBody: string;
const
  CRLF = #13#10;
begin
  IndyStringList := TStringList.Create;
  IndyStream := TMemoryStream.Create;
  try
    IndyStringList.LoadFromFile(Trim(Edit1.Text));
    IndyStringList.Add(CRLF + '.' + CRLF);
    IndyStringList.SaveToStream(IndyStream);
    IndyStream.Position := 0;
    IdMessage.Clear;
    IdMessage.LoadFromStream(IndyStream);
    Memo1.Clear;
    Memo1.Lines.Assign(IdMessage.Headers);
    Memo2.Clear;
    Memo2.Lines.Add(IdMessage.From.Text);
    Memo2.Lines.Add(IdMessage.Recipients.EMailAddresses);
    Memo2.Lines.Add(IdMessage.Subject);
    Memo2.Lines.Add(DateTimeToStr(IdMessage.Date));
    Memo2.Lines.Add('');

    if (Pos('multi-part', IdMessage.ContentType) > 0) or (Pos('multipart', IdMessage.ContentType) > 0) then
    begin
      for I := 0 to IdMessage.MessageParts.Count - 1 do
      begin
        if IdMessage.MessageParts.Items[I] is IdText.TidText then
        begin
          if Pos('text/plain', IdText.TidText(IdMessage.MessageParts.Items[I]).ContentType) > 0 then
          begin
            PlaintextBody := IdText.TidText(IdMessage.MessageParts.Items[I]).Body.Text;
            BREAK;
          end
          else if IdText.TidText(IdMessage.MessageParts.Items[I]).ContentType = 'text/htmlthen
            HTMLBody := IdText.TidText(IdMessage.MessageParts.Items[I]).Body.Text;
        end;
      end;

      if PlaintextBody <> 'then
        Memo2.Lines.Add(Trim(PlaintextBody))
      else if HTMLBody <> 'then
        Memo2.Lines.Add(ExtractTextFrom(HTMLBody))
      else Memo2.Lines.Add('The body could not be extracted from the .EML file. Please report this error and attach your .EML file');
    end
    else
    begin
      Memo2.Lines.Add(Trim(IdMessage.Body.Text));
    end;
  finally
    IndyStringList.Free;
    IndyStream.Free;
  end;
end;
Ich stelle jetzt mal das ganze Projekt online (s. Anhang) mit der Bitte, das mit euren .EML-Dateien zu verifizieren. Ich habe es mit einer großen Menge von .EML-Dateien verwendet und bisher hat es mit allen funktioniert. Solltet ihr eine .EML-Datei finden, die nicht funktioniert, so bitte ich euch, diese zu anonymisieren und hier online zu stellen, damit ich den Code ggf. anpassen kann.
Angehängte Dateien
Dateityp: zip OpenEMLFiles.zip (49,5 KB, 41x aufgerufen)
  Mit Zitat antworten Zitat
nahpets
(Gast)

n/a Beiträge
 
#10

AW: Plaintext aus .EML-Datei extrahieren?

  Alt 8. Apr 2016, 12:22
Hallo,

hier findest Du eine Seite mit 'ner Liste von Mimetypen, das ist das, womit Du rechnen solltest/kannst/musst: SelfHTML - Mime-Typen

Die Methode, den Text über den TWebBrowser zu holen, finde ich gut.

Ansonsten sieht Dein Programm so aus, als sollte das funktionieren.

Was mir auffiel:

Nachdem Du den PlainTextBody gefunden hast, verlässt Du die Schleife mit break, beim HTMLBody nicht.

Sollten in 'nem EML mehrere PlainTextBodys sein, so übernimmst Du damit den ersten, beim HTMLBody jedoch den letzten.

Zugebenermaßen weiß ich nicht, ob es auch nur annähernd spezifikationskonform ist, wenn es in 'nem EML mehrere Plaintext-Bodys oder HTML-Bodys gibt / geben darf / geben kann.
  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 22:28 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