Analysieren Sie den E-Mail-Inhalt aus der angegebenen Antwort

86

Ich versuche herauszufinden, wie der Text einer E-Mail aus einem zitierten Antworttext heraus analysiert werden kann. Mir ist aufgefallen, dass E-Mail-Clients normalerweise ein "An so und so einem Datum so und so geschrieben" setzen oder den Zeilen eine spitze Klammer voranstellen. Leider macht das nicht jeder. Hat jemand eine Idee, wie man Antworttext programmgesteuert erkennt? Ich benutze C #, um diesen Parser zu schreiben.

VanOrman
quelle
2
Hattest du Glück damit? Ich möchte genau das Gleiche tun.
steve_c
Gibt es eine endgültige Lösung mit einem vollständigen Quellcodebeispiel?
Kiquenet
Quotequail tut dies in Python
Philfreo
Kann jemand für seine PHP-Version helfen?
user4271704

Antworten:

60

Ich habe viel mehr danach gesucht und hier ist, was ich gefunden habe. Grundsätzlich gibt es zwei Situationen, in denen Sie dies tun: Wenn Sie den gesamten Thread haben und wenn Sie dies nicht tun. Ich werde es in diese beiden Kategorien aufteilen:

Wenn Sie den Thread haben:

Wenn Sie die gesamte Serie von E-Mails haben, können Sie ein sehr hohes Maß an Sicherheit erreichen, dass das, was Sie entfernen, tatsächlich zitierter Text ist. Es gibt zwei Möglichkeiten, dies zu tun. Zum einen können Sie die Nachrichten-ID, die In-Reply-To-ID und den Thread-Index der Nachricht verwenden, um die einzelne Nachricht, ihre übergeordnete Nachricht und den Thread zu bestimmen, zu dem sie gehört. Weitere Informationen hierzu finden Sie in RFC822 , RFC2822 , in diesem interessanten Artikel zum Threading oder in diesem Artikel zum Threading . Nachdem Sie den Thread neu zusammengestellt haben, können Sie den externen Text (z. B. An, Von, CC usw.) entfernen und fertig.

Wenn die Nachrichten, mit denen Sie arbeiten, keine Überschriften haben, können Sie mithilfe der Ähnlichkeitsübereinstimmung auch bestimmen, welche Teile einer E-Mail der Antworttext sind. In diesem Fall müssen Sie keine Ähnlichkeitsanpassung durchführen, um den Text zu bestimmen, der wiederholt wird. In diesem Fall möchten Sie möglicherweise einen Levenshtein-Entfernungsalgorithmus wie diesen in Code Project oder diesen untersuchen .

Egal was passiert, wenn Sie am Threading-Prozess interessiert sind, lesen Sie dieses großartige PDF zum Zusammensetzen von E-Mail-Threads .

Wenn Sie den Thread nicht haben:

Wenn Sie nur eine Nachricht aus dem Thread haben, müssen Sie versuchen, das Zitat zu erraten. In diesem Fall sind hier die verschiedenen Zitiermethoden, die ich gesehen habe:

  1. eine Linie (wie im Ausblick zu sehen).
  2. Winkelhalterungen
  3. "---Originale Nachricht---"
  4. "An so und so schrieb so und so:"

Entfernen Sie den Text von dort unten und Sie sind fertig. Der Nachteil bei all diesen ist, dass sie alle davon ausgehen, dass der Absender ihre Antwort über den zitierten Text gestellt und ihn nicht verschachtelt hat (wie es der alte Stil im Internet war). Wenn das passiert, viel Glück. Ich hoffe das hilft einigen von euch da draußen!

VanOrman
quelle
31

Zuallererst ist dies eine schwierige Aufgabe.

Sie sollten typische Antworten von verschiedenen E-Mail-Clients sammeln und korrekte reguläre Ausdrücke (oder was auch immer) vorbereiten, um sie zu analysieren. Ich habe Antworten von Outlook, Thunderbird, Google Mail, Apple Mail und mail.ru gesammelt.

Ich verwende reguläre Ausdrücke, um die Antwort auf folgende Weise zu analysieren: Wenn der Ausdruck nicht übereinstimmt, versuche ich, den nächsten zu verwenden.

new Regex("From:\\s*" + Regex.Escape(_mail), RegexOptions.IgnoreCase);
new Regex("<" + Regex.Escape(_mail) + ">", RegexOptions.IgnoreCase);
new Regex(Regex.Escape(_mail) + "\\s+wrote:", RegexOptions.IgnoreCase);
new Regex("\\n.*On.*(\\r\\n)?wrote:\\r\\n", RegexOptions.IgnoreCase | RegexOptions.Multiline);
new Regex("-+original\\s+message-+\\s*$", RegexOptions.IgnoreCase);
new Regex("from:\\s*$", RegexOptions.IgnoreCase);

So entfernen Sie das Zitat am Ende:

new Regex("^>.*$", RegexOptions.IgnoreCase | RegexOptions.Multiline);

Hier ist meine kleine Sammlung von Testantworten (Beispiele geteilt durch --- ):

From: test@test.com [mailto:test@test.com] 
Sent: Tuesday, January 13, 2009 1:27 PM
----
2008/12/26 <test@test.com>

>  text
----
test@test.com wrote:
> text
----
      test@test.com wrote:         text
text
----
2009/1/13 <test@test.com>

>  text
----
 test@test.com wrote:         text
 text
----
2009/1/13 <test@test.com>

> text
> text
----
2009/1/13 <test@test.com>

> text
> text
----
test@test.com wrote:
> text
> text
<response here>
----
--- On Fri, 23/1/09, test@test.com <test@test.com> wrote:

> text
> text

Viele Grüße, Oleg Yaroshevych

Oleg Yaroshevych
quelle
Was ist, wenn ich die E-Mail-Adresse nicht kenne?
Harsimranb
@ Shyamal-Parikh dies funktioniert nicht für HTML-E-Mails, aber in der Regel ist eine Klartext-Nachricht auch in E-Mail-Nachrichten enthalten
maembe
25

Danke, Goleg, für die Regexes! Wirklich geholfen. Dies ist kein C #, aber für die Googler da draußen ist hier mein Ruby-Parsing-Skript:

def extract_reply(text, address)
    regex_arr = [
      Regexp.new("From:\s*" + Regexp.escape(address), Regexp::IGNORECASE),
      Regexp.new("<" + Regexp.escape(address) + ">", Regexp::IGNORECASE),
      Regexp.new(Regexp.escape(address) + "\s+wrote:", Regexp::IGNORECASE),
      Regexp.new("^.*On.*(\n)?wrote:$", Regexp::IGNORECASE),
      Regexp.new("-+original\s+message-+\s*$", Regexp::IGNORECASE),
      Regexp.new("from:\s*$", Regexp::IGNORECASE)
    ]

    text_length = text.length
    #calculates the matching regex closest to top of page
    index = regex_arr.inject(text_length) do |min, regex|
        [(text.index(regex) || text_length), min].min
    end

    text[0, index].strip
end

Bisher hat es ziemlich gut funktioniert.

Hurshagrawal
quelle
1
Sie sollten eine Ruby-Frage stellen und mit diesem Code beantworten, anstatt sie auf einer ac # -Frage zu veröffentlichen.
Matthieu
5
@Matthieu, es ist nicht nur eine C # -Frage, sondern eine E-Mail- und E-Mail-Analyse-Frage. total relevant meiner meinung nach.
Trent
@Trent: Das C # -Tag sollte dann gelöscht werden.
Matthieu
7
Das Lustige ist, dass ich diese Frage von Googeln für das Thema (nicht die Sprache) gefunden habe und tatsächlich etwas in Ruby implementieren musste. Also, Prost!
Bratsche
2
Dies ist die bisher beste Antwort. Regex ist ziemlich sprachunabhängig. Danke fürs Schreiben
superluminary
11

Der mit Abstand einfachste Weg, dies zu tun, besteht darin, einen Marker in Ihren Inhalten zu platzieren, z.

--- Bitte antworten Sie über dieser Zeile ---

Wie Sie zweifellos bemerkt haben, ist das Parsen von zitiertem Text keine triviale Aufgabe, da verschiedene E-Mail-Clients Text auf unterschiedliche Weise zitieren. Um dieses Problem richtig zu lösen, müssen Sie jeden E-Mail-Client berücksichtigen und testen.

Facebook kann dies, aber wenn Ihr Projekt nicht über ein großes Budget verfügt, können Sie dies wahrscheinlich nicht.

Oleg hat das Problem mithilfe von Regexes gelöst, um den Text "Am 13. Juli 2012, um 13:09 Uhr schrieb xxx:" zu finden. Wenn der Benutzer diesen Text jedoch löscht oder wie viele andere Personen am Ende der E-Mail antwortet, funktioniert diese Lösung nicht.

Wenn der E-Mail-Client eine andere Datumszeichenfolge verwendet oder keine Datumszeichenfolge enthält, schlägt der reguläre Ausdruck ebenfalls fehl.

überleuchtet
quelle
Dieser Ansatz schlägt bei Antworten auf Antworten fehl, es sei denn, Sie setzen diese Zeile bei jeder Antwort.
JPW
1
Ja, es hat Nachteile. Wenn der Benutzer die Antwort über der Zeilenzeichenfolge löscht, schlägt Ihre Antwort fehl. Ich fange diesen Fall auf und sende dem Benutzer eine direkte Nachricht, in der er darüber informiert wird, dass seine Nachricht fehlgeschlagen ist, mit einem Link, über den er über die Web-App antworten kann. Die meisten Benutzer scheinen in der Lage zu sein, es ohne allzu große Probleme zu verwenden.
Superluminary
Dies sollte die akzeptierte Antwort sein. Ich würde jedoch die Information hinzufügen, dass die Antwort nicht erfolgreich sein wird, wenn die Zeile entfernt wird.
Benni
@Benni - ja, es wird fehlschlagen, wenn die Zeile entfernt wird. Leider gibt es keine Standardmethode zum Zitieren von Text über E-Mail-Clients hinweg. Wenn die Zeile entfernt wird, können Sie den gesamten Text als Antwort behandeln. Ich denke nicht, dass in diesem Fall eine perfekte Lösung möglich ist.
Superluminary
@superluminary Ich meinte, ich würde es der Zeile hinzufügen. Also ist es so etwas wie -- Please reply above this line. DO NOT REMOVE IT! --. Außerdem habe ich festgestellt, dass dies nicht immer funktioniert, da einige E-Mail-Clients xxx wrote on <datetime>:vor dem gesamten Angebot und daher vor dieser Zeile eine Zeile hinzufügen . Diese Zeile kann mit Regex analysiert werden, sie kann jedoch in verschiedenen Sprachen und in einem anderen Format vorliegen, da sich E-Mail-Clients unterscheiden.
Benni
6

Es gibt keinen universellen Indikator für eine Antwort in einer E-Mail. Das Beste, was Sie tun können, ist zu versuchen, die häufigsten zu finden und neue Muster zu analysieren, wenn Sie auf sie stoßen.

Denken Sie daran, dass einige Personen Antworten in den zitierten Text einfügen (mein Chef beantwortet beispielsweise Fragen in derselben Zeile, in der ich sie gestellt habe). Wenn Sie also etwas tun, verlieren Sie möglicherweise einige Informationen, die Sie gerne behalten hätten.

3Doubloons
quelle
Google Mail macht es ... zumindest scheint es das zu tun.
Soweit
Google Mail fügt möglicherweise wie andere E-Mail-Clients '>' hinzu, aber es ist kein Standard für E-Mails und nichts,
worauf
5

Hier ist meine C # -Version von @ hurshagrawals Ruby-Code. Ich kenne Ruby nicht wirklich gut, also könnte es aus sein, aber ich denke, ich habe es richtig gemacht.

public string ExtractReply(string text, string address)
{
    var regexes = new List<Regex>() { new Regex("From:\\s*" + Regex.Escape(address), RegexOptions.IgnoreCase),
                        new Regex("<" + Regex.Escape(address) + ">", RegexOptions.IgnoreCase),
                        new Regex(Regex.Escape(address) + "\\s+wrote:", RegexOptions.IgnoreCase),
                        new Regex("\\n.*On.*(\\r\\n)?wrote:\\r\\n", RegexOptions.IgnoreCase | RegexOptions.Multiline),
                        new Regex("-+original\\s+message-+\\s*$", RegexOptions.IgnoreCase),
                        new Regex("from:\\s*$", RegexOptions.IgnoreCase),
                        new Regex("^>.*$", RegexOptions.IgnoreCase | RegexOptions.Multiline)
                    };

    var index = text.Length;

    foreach(var regex in regexes){
        var match = regex.Match(text);

        if(match.Success && match.Index < index)
            index = match.Index;
    }

    return text.Substring(0, index).Trim();
}
Austin
quelle
3

Wenn Sie die ursprüngliche Nachricht steuern (z. B. Benachrichtigungen von einer Webanwendung), können Sie einen eindeutigen, identifizierbaren Header einrichten und diesen als Trennzeichen für den ursprünglichen Beitrag verwenden.

Eric R. Rath
quelle
0

Dies ist eine gute Lösung. Fand es nach so langer Suche.

Ein Zusatz, wie oben erwähnt, ist fallweise, so dass die obigen Ausdrücke meine Antworten auf Google Mail und Outlook (2010) nicht korrekt analysiert haben, für die ich die folgenden zwei Regex (s) hinzugefügt habe. Lassen Sie mich für alle Probleme wissen.

//Works for Gmail
new Regex("\\n.*On.*<(\\r\\n)?" + Regex.Escape(address) + "(\\r\\n)?>", RegexOptions.IgnoreCase),
//Works for Outlook 2010
new Regex("From:.*" + Regex.Escape(address), RegexOptions.IgnoreCase),

Prost

Amit M.
quelle
Kann jemand für seine PHP-Version helfen?
user4271704
Überprüfen Sie dies für die PHP-Version. stackoverflow.com/questions/14916618/… github.com/willdurand/EmailReplyParser
FullStackDev
-1

Es ist ein alter Beitrag, jedoch nicht sicher, ob Sie wissen, dass Github eine Ruby- Bibliothek hat, die die Antwort extrahiert. Wenn Sie .NET verwenden, habe ich ein .NET unter https://github.com/EricJWHuang/EmailReplyParser

Eric Huang
quelle
1
Links zu externen Ressourcen werden empfohlen. Fügen Sie jedoch einen Kontext um den Link hinzu, damit Ihre Mitbenutzer eine Vorstellung davon haben, was es ist und warum es dort ist. Zitieren Sie immer den relevantesten Teil eines wichtigen Links, falls die Zielwebsite nicht erreichbar ist oder dauerhaft offline ist.
Pableiros
Halten Sie diese Bibliothek auf dem neuesten Stand? Ich bin auf die Suche gekommen, weil die C # -Bibliothek eine einfache E-Mail aus Outlook aus Office 365 nicht richtig analysiert. Dann habe ich im Ruby-Quellcode nachgesehen und festgestellt, dass in ihren Testfällen ein identischer Testfall vorhanden war, sodass sie der Meinung sind, dass sie analysiert werden sollten es.
Greg Veres
-1

Wenn Sie die API von SigParser.com verwenden , erhalten Sie eine Reihe aller ausgebrochenen E-Mails in einer Antwortkette aus einer einzelnen E-Mail-Textzeichenfolge. Wenn es also 10 E-Mails gibt, erhalten Sie den Text für alle 10 E-Mails.

Geben Sie hier die Bildbeschreibung ein

Die detaillierte API-Spezifikation können Sie hier anzeigen.

https://api.sigparser.com/

Geben Sie hier die Bildbeschreibung ein

Paul Mendoza
quelle