Analizza il contenuto dell'email dalla risposta citata


86

Sto cercando di capire come analizzare il testo di un'e-mail da qualsiasi testo di risposta citato che potrebbe includere. Ho notato che di solito i client di posta elettronica mettono un "In tale data così e così hanno scritto" o antepongono le righe con una parentesi angolare. Sfortunatamente, non tutti lo fanno. Qualcuno ha qualche idea su come rilevare a livello di codice il testo di risposta? Sto usando C # per scrivere questo parser.


2
Hai avuto fortuna con questo? Sto cercando di fare esattamente la stessa cosa.
steve_c

qualsiasi soluzione finale con un esempio di codice sorgente completo al lavoro?
Kiquenet

Quotequail lo fa in Python
philfreo

Qualcuno può aiutare per la sua versione php?
user4271704

Risposte:


60

Ho fatto molte più ricerche su questo ed ecco cosa ho trovato. Ci sono fondamentalmente due situazioni in cui stai facendo questo: quando hai l'intero thread e quando non lo fai. Lo suddividerò in queste due categorie:

Quando hai il filo:

Se hai l'intera serie di e-mail, puoi ottenere un livello molto elevato di certezza che ciò che stai rimuovendo sia effettivamente testo citato. Ci sono due modi per farlo. Uno, è possibile utilizzare l'ID messaggio, l'ID in risposta e l'indice thread del messaggio per determinare il singolo messaggio, il genitore e il thread a cui appartiene. Per ulteriori informazioni su questo argomento , vedere RFC822 , RFC2822 , questo interessante articolo sul threading o questo articolo sul threading . Dopo aver riassemblato il thread, puoi rimuovere il testo esterno (come le righe A, Da, CC, ecc ...) e il gioco è fatto.

Se i messaggi con cui stai lavorando non hanno le intestazioni, puoi anche utilizzare la corrispondenza di somiglianza per determinare quali parti di un'email sono il testo di risposta. In questo caso sei bloccato con la corrispondenza di somiglianza per determinare il testo che viene ripetuto. In questo caso potresti voler esaminare un algoritmo Levenshtein Distance come questo su Code Project o questo .

Non importa cosa, se sei interessato al processo di threading, dai un'occhiata a questo fantastico PDF sul riassemblaggio di thread di posta elettronica .

Quando non hai il thread:

Se sei bloccato con un solo messaggio dal thread, devi provare a indovinare qual è la citazione. In tal caso, ecco i diversi metodi di citazione che ho visto:

  1. una linea (come si vede in Outlook).
  2. Parentesi angolari
  3. "---Messaggio originale---"
  4. "In quel giorno così e così, così e così ha scritto:"

Rimuovi il testo da lì in basso e il gioco è fatto. Lo svantaggio di ognuno di questi è che tutti presumono che il mittente abbia messo la propria risposta sopra il testo citato e non l'ha intercalata (come era il vecchio stile su Internet). Se succede, buona fortuna. Spero che questo aiuti alcuni di voi là fuori!


32

Prima di tutto, questo è un compito complicato.

È necessario raccogliere le risposte tipiche da diversi client di posta elettronica e preparare espressioni regolari corrette (o qualsiasi altra cosa) per analizzarle. Ho raccolto risposte da outlook, thunderbird, gmail, apple mail e mail.ru.

Sto usando espressioni regolari per analizzare la risposta nel modo seguente: se l'espressione non corrisponde, provo a usare quella successiva.

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);

Per rimuovere la citazione alla fine:

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

Ecco la mia piccola raccolta di risposte ai test (campioni divisi per --- ):

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

Cordiali saluti, Oleg Yaroshevych


E se non conosco l'indirizzo e-mail?
harsimranb

@ Shyamal-Parikh questo non funzionerà per le e-mail html, ma in genere un messaggio di testo normale è incluso anche nei messaggi e-mail
maembe

25

Grazie, Goleg, per le regex! Davvero aiutato. Questo non è C #, ma per i googler là fuori, ecco il mio script di analisi di Ruby:

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

Finora ha funzionato abbastanza bene.


1
Dovresti fare una domanda ruby ​​e rispondere con questo codice invece di pubblicarla su ac # question.
Matthieu

6
@ Matthieu, non è solo una domanda C #, ma una domanda di analisi di e-mail e posta elettronica. del tutto rilevante a mio parere.
Trento

@Trent: il tag C # dovrebbe essere eliminato allora.
Matthieu

7
La cosa divertente è che ho trovato questa domanda su Google per l'argomento (non la lingua) e in realtà avevo bisogno di implementare qualcosa in Ruby. Quindi, saluti!
bratsche

2
Questa è la migliore risposta finora. Regex è piuttosto indipendente dalla lingua. Grazie per il post
superluminary

11

Il modo di gran lunga più semplice per farlo è posizionare un indicatore nel contenuto, come ad esempio:

--- Si prega di rispondere sopra questa riga ---

Come avrai sicuramente notato, analizzare il testo citato non è un compito banale poiché diversi client di posta elettronica citano il testo in modi diversi. Per risolvere correttamente questo problema è necessario tenere conto e testare in ogni client di posta elettronica.

Facebook può farlo, ma a meno che il tuo progetto non abbia un budget elevato, probabilmente non puoi.

Oleg ha risolto il problema utilizzando le espressioni regolari per trovare il testo "Il 13 luglio 2012, alle 13:09, xxx ha scritto:". Tuttavia, se l'utente elimina questo testo o risponde in fondo all'e-mail, come fanno molte persone, questa soluzione non funzionerà.

Allo stesso modo, se il client di posta elettronica utilizza una stringa di data diversa o non include una stringa di data, la regex avrà esito negativo.


Questo approccio fallisce con le risposte alle risposte a meno che non inserisca quella riga ogni volta che rispondi.
jpw

1
Sì, ha degli svantaggi. Se l'utente elimina la risposta sopra la stringa di riga, la tua risposta fallirà. Prendo questo caso e invio all'utente un messaggio diretto per fargli sapere che il messaggio non è riuscito, con un link per rispondere tramite l'app web. La maggior parte degli utenti sembra essere in grado di usarlo senza troppi problemi.
superluminario

Questa dovrebbe essere la risposta accettata. Tuttavia, aggiungerei l'informazione che la risposta non avrà successo se la linea viene rimossa.
Benni

@Benni - sì, fallirà se la linea viene rimossa. Sfortunatamente, non esiste un modo standard per citare il testo tra i client di posta elettronica. Nel caso in cui la riga venga rimossa, potresti considerare tutto il testo come una risposta. Non credo che in questo caso sia possibile una soluzione perfetta.
superluminario

@superluminary volevo dire, lo aggiungerei alla riga. Quindi è qualcosa di simile -- Please reply above this line. DO NOT REMOVE IT! --. Inoltre, quello che ho sperimentato è che non funzionerà sempre poiché alcuni client di posta elettronica aggiungono una xxx wrote on <datetime>:riga prima dell'intera citazione e quindi prima di quella riga. Questa riga potrebbe essere analizzata con regex, tuttavia potrebbe essere in lingue diverse e in un formato diverso poiché i client di posta elettronica differiscono.
Benni

6

Non esiste un indicatore universale di una risposta in un'e-mail. Il meglio che puoi fare è cercare di catturare i modelli più comuni e analizzare i nuovi modelli non appena li incontri.

Tieni presente che alcune persone inseriscono le risposte all'interno del testo citato (il mio capo ad esempio risponde alle domande sulla stessa riga in cui ho chiesto loro) quindi qualunque cosa tu faccia, potresti perdere alcune informazioni che avresti voluto conservare.


gmail lo fa ... almeno sembra che lo faccia. Da quello che ricordo c'è un ID thread che non cambia tra l'originale e le risposte ...
kenny

Gmail potrebbe aggiungere ">" come fanno altri client di posta elettronica, ma non è uno standard per le email e non è qualcosa su cui puoi contare
3Doubloons

5

Ecco la mia versione C # del codice Ruby di @ hurshagrawal. Non conosco Ruby molto bene quindi potrebbe essere spento, ma penso di aver capito bene.

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();
}

3

Se controlli il messaggio originale (ad es. Notifiche da un'applicazione web), puoi inserire un'intestazione distinta e identificabile e utilizzarla come delimitatore per il post originale.


0

Questa è una buona soluzione. Trovato dopo aver cercato così a lungo.

Un'aggiunta, come accennato in precedenza, riguarda le maiuscole e le minuscole, quindi le espressioni sopra non hanno analizzato correttamente le mie risposte gmail e outlook (2010), per le quali ho aggiunto le seguenti due espressioni regolari. Fammi sapere per eventuali problemi.

//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),

Saluti


Qualcuno può aiutare per la sua versione php?
user4271704


-1

È un vecchio post, tuttavia, non sono sicuro che tu sappia che github ha una libreria Ruby che estrae la risposta. Se usi .NET, ne ho uno .NET su https://github.com/EricJWHuang/EmailReplyParser


1
I collegamenti a risorse esterne sono incoraggiati, ma aggiungi un contesto attorno al collegamento in modo che gli altri utenti abbiano un'idea di cosa sia e perché sia ​​lì. Cita sempre la parte più rilevante di un collegamento importante, nel caso in cui il sito di destinazione non sia raggiungibile o rimanga permanentemente offline.
pableiros

tieni aggiornata quella libreria? Sono venuto a cercare perché la libreria C # non analizza correttamente una semplice e-mail da Outlook da Office 365. Quindi ho guardato nel codice sorgente di ruby ​​e ho scoperto che c'era un caso di test identico nei loro casi di test così chiaramente che pensano che dovrebbero analizzare esso.
Greg Veres

-1

Se utilizzi l'API di SigParser.com , ti fornirà un array di tutte le email suddivise in una catena di risposte da una singola stringa di testo email. Quindi, se ci sono 10 e-mail, riceverai il testo per tutte e 10 le e-mail.

inserisci qui la descrizione dell'immagine

Puoi visualizzare le specifiche API dettagliate qui.

https://api.sigparser.com/

inserisci qui la descrizione dell'immagine

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.