web-dev-qa-db-fra.com

Analyser le contenu de l'e-mail de la réponse citée

J'essaie de comprendre comment analyser le texte d'un courrier électronique à partir de tout texte de réponse cité qu'il pourrait inclure. J'ai remarqué qu'habituellement, les clients de messagerie mettaient un "à telle date, telle ou telle écrit" ou préfixaient les lignes avec un crochet. Malheureusement, tout le monde ne le fait pas. Quelqu'un at-il une idée sur la façon de détecter par programme le texte de réponse? J'utilise C # pour écrire cet analyseur.

80
VanOrman

J'ai fait beaucoup plus de recherches à ce sujet et voici ce que j'ai trouvé. Vous faites essentiellement ceci dans deux situations: quand vous avez le fil entier et quand vous n’avez pas. Je vais le diviser en deux catégories:

Quand vous avez le fil:

Si vous avez toute la série de courriels, vous pouvez être très sûr que ce que vous supprimez est bien un texte cité. Il y a deux façons de faire ça. Premièrement, vous pouvez utiliser l'ID de message, l'ID de réponse et l'index de fil de discussion du message pour déterminer le message individuel, son parent et le fil auquel il appartient. Pour plus d'informations à ce sujet, voir RFC822 , RFC2822 , cet article intéressant sur le threading ou cet article sur le threading . Une fois que vous avez ré-assemblé le fil, vous pouvez alors supprimer le texte externe (comme les lignes À, De, CC, etc.) et vous avez terminé. 

Si les messages avec lesquels vous travaillez ne comportent pas d'en-tête, vous pouvez également utiliser la correspondance de similarité pour déterminer les parties du courrier électronique qui constituent le texte de réponse. Dans ce cas, vous êtes contraint de faire une correspondance de similarité pour déterminer le texte répété. Dans ce cas, vous pouvez examiner un algorithme Levenshtein Distance tel que celui-ci sur Code Project ou celui-ci

Quoi qu'il en soit, si le processus de thread vous intéresse, consultez cet excellent PDF pour réassembler les threads de messagerie .

Quand vous n'avez pas le fil:

Si vous êtes coincé avec un seul message du fil, vous devez essayer de deviner quelle est la citation. Dans ce cas, voici les différentes méthodes de citation que j'ai vues:

  1. une ligne (comme dans Outlook).
  2. Équerres
  3. "--- Message d'origine ---"
  4. "Ce jour-là, un tel a écrit:"

Supprimez le texte de là-bas et vous avez terminé. L'inconvénient de l'un d'entre eux est qu'ils supposent tous que l'expéditeur a placé sa réponse sur le texte cité et ne l'a pas entrelacée (comme c'était le cas à l'ancienne sur Internet). Si cela se produit, bonne chance. J'espère que cela aide certains d'entre vous là-bas!

57
VanOrman

Tout d’abord, c’est une tâche délicate.

Vous devez collecter les réponses types de différents clients de messagerie et préparer des expressions rationnelles correctes (ou autre) pour les analyser. J'ai collecté les réponses d'Outlook, Thunderbird, Gmail, Apple mail et mail.ru.

J'utilise des expressions régulières pour analyser la réponse de la manière suivante: si l'expression ne correspond pas, j'essaie d'utiliser la suivante.

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

Pour supprimer la citation à la fin:

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

Voici ma petite collection de réponses aux tests (échantillons divisés par --- ):

From: [email protected] [mailto:[email protected]] 
Sent: Tuesday, January 13, 2009 1:27 PM
----
2008/12/26 <[email protected]>

>  text
----
[email protected] wrote:
> text
----
      [email protected] wrote:         text
text
----
2009/1/13 <[email protected]>

>  text
----
 [email protected] wrote:         text
 text
----
2009/1/13 <[email protected]>

> text
> text
----
2009/1/13 <[email protected]>

> text
> text
----
[email protected] wrote:
> text
> text
<response here>
----
--- On Fri, 23/1/09, [email protected] <[email protected]> wrote:

> text
> text

Cordialement, Oleg Yaroshevych

27
Oleg Yaroshevych

Merci Goleg pour les regex! Vraiment aidé. Ce n'est pas C #, mais pour les googlers, voici mon script d'analyse 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

Cela a plutôt bien fonctionné jusqu'à présent.

22
hurshagrawal

Pour ce faire, le moyen le plus simple consiste à placer un marqueur dans votre contenu, par exemple:

--- S'il vous plaît répondez au-dessus de cette ligne ---

Comme vous l'avez sans doute remarqué, l'analyse du texte cité n'est pas une tâche triviale, car différents clients de messagerie citent le texte de différentes manières. Pour résoudre ce problème correctement, vous devez prendre en compte et tester chaque client de messagerie.

Facebook peut le faire, mais à moins que votre projet ait un gros budget, vous ne pourrez probablement pas.

Oleg a résolu le problème en utilisant des expressions rationnelles pour trouver le texte "Le 13 juillet 2012 à 13:09, xxx a écrit:". Toutefois, si l'utilisateur supprime ce texte ou répond au bas de l'e-mail, comme le font beaucoup de personnes, cette solution ne fonctionnera pas.

De même, si le client de messagerie utilise une chaîne de date différente ou n'inclut pas de chaîne de date, l'expression régulière échouera.

11
superluminary

Il n'y a pas d'indicateur universel de réponse dans un courrier électronique. Le mieux que vous puissiez faire est d’essayer d’attraper les modèles les plus courants et d’analyser les nouveaux modèles au fur et à mesure que vous les rencontrez.

N'oubliez pas que certaines personnes insèrent des réponses dans le texte cité (mon patron, par exemple, répond aux questions sur la même ligne que je leur ai posée). Ainsi, quoi que vous fassiez, vous pourriez perdre certaines informations que vous auriez aimé garder.

6
3Doubloons

Voici ma version C # du code Ruby de @ hurshagrawal. Je ne connais pas très bien Ruby, donc ça pourrait être éteint, mais je pense que j'ai bien compris.

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

Si vous contrôlez le message d'origine (par exemple, les notifications provenant d'une application Web), vous pouvez mettre en place un en-tête distinct identifiable et l'utiliser comme délimiteur pour la publication d'origine.

3
Eric R. Rath

C'est une bonne solution. Je l'ai trouvé après avoir cherché si longtemps.

Un ajout, comme mentionné ci-dessus, est judicieux, donc les expressions ci-dessus n’ont pas analysé correctement mes réponses gmail et Outlook (2010), pour lesquelles j’ai ajouté les deux expressions rationnelles suivantes. Faites le moi savoir pour tout problème.

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

À votre santé

1
Amit M

Si vous utilisez l'API de SigParser.com , vous obtiendrez un tableau de tous les e-mails dissociés d'une chaîne de réponse à partir d'une seule chaîne de texte. Donc, s'il y a 10 courriels, vous aurez le texte pour chacun des 10 courriels. 

 enter image description here

Vous pouvez voir les spécifications détaillées de l'API ici.

https://api.sigparser.com/

 enter image description here

0
Paul Mendoza

C'est un vieux post, cependant, je ne sais pas si vous savez que github a une librairie Ruby qui extrait la réponse. Si vous utilisez .NET, j’en ai un .NET à https://github.com/EricJWHuang/EmailReplyParser

0
Eric Huang