引用された返信からメールの内容を解析する


86

引用された返信テキストからメールのテキストを解析する方法を見つけようとしています。私は通常、電子メールクライアントが「そのような日付にそう書かれた」を付けるか、行の前に山かっこを付けることに気づきました。残念ながら、誰もがこれを行うわけではありません。プログラムで返信テキストを検出する方法について誰かが何か考えを持っていますか?このパーサーの作成にはC#を使用しています。


2
これで運が良かったですか?私はまったく同じことをしたいと思っています。
steve_c 2008年

完全なソースコードサンプルが機能する最終的な解決策はありますか?
キケネット2013年

QuotequailはPythonでこれを行います
philfreo 2014年

誰かがそのphpバージョンを手伝ってもらえますか?
user4271704 2015年

回答:


60

私はこれについてもっと多くの検索をしました、そしてこれが私が見つけたものです。これを行うには、基本的に2つの状況があります。スレッド全体がある場合とない場合です。私はそれをそれらの2つのカテゴリーに分けます:

スレッドがある場合:

一連の電子メール全体がある場合は、削除するものが実際に引用されたテキストであるという非常に高いレベルの保証を実現できます。これを行うには2つの方法があります。1つは、メッセージのMessage-ID、In-Reply-To ID、およびThread-Indexを使用して、個々のメッセージ、その親、およびメッセージが属するスレッドを判別できます。詳細については、RFC822RFC2822スレッドに関するこの興味深い記事、またはスレッドに関するこの記事を参照してください。。スレッドを再構築したら、外部テキスト(To、From、CCなどの行など)を削除して完了です。

使用しているメッセージにヘッダーがない場合は、類似性マッチングを使用して、電子メールのどの部分が返信テキストであるかを判別することもできます。この場合、繰り返されるテキストを決定するために類似性マッチングを行うことに固執しています。この場合、あなたはに見たいと思うかもしれませんレーベンシュタイン距離アルゴリズムのようなコードプロジェクトで、この1またはこのいずれか

いずれにせよ、スレッド化プロセスに興味がある場合は、電子メールスレッドの再構築に関するこのすばらしいPDFを確認してください。

スレッドがない場合:

スレッドからのメッセージが1つしかない場合は、見積もりが何であるかを推測する必要があります。その場合、私が見たさまざまな見積もり方法は次のとおりです。

  1. 線(見通しに見られるように)。
  2. 角括弧
  3. " - -オリジナルメッセージ - -"
  4. 「あんな日に、あんなに書いた:」

そこからテキストを削除すれば完了です。これらのいずれかの欠点は、送信者が引用されたテキストの上に返信を置き、それをインターリーブしなかったと想定していることです(インターネットの古いスタイルのように)。それが起こったら、頑張ってください。これが皆さんのお役に立てば幸いです。


32

まず第一に、これはトリッキーな作業です。

さまざまな電子メールクライアントから一般的な応答を収集し、それらを解析するために正しい正規表現(またはその他)を準備する必要があります。Outlook、Thunderbird、Gmail、Apple Mail、mail.ruからの回答を集めました。

正規表現を使用して、次の方法で応答を解析しています。式が一致しなかった場合は、次の式を使用しようとします。

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

最後に引用を削除するには:

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

これが私の小さなテスト応答のコレクションです(サンプルを---で割ったもの):

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

よろしく、Oleg Yaroshevych


メールアドレスがわからない場合はどうなりますか?
harsimranb 2015年

Shyamal-パリキ@これは通常、平文のメッセージは、電子メールメッセージではないHTMLメールのための作業が、含まれています
maembe

25

正規表現をありがとう、ゴレグ!本当に助かりました。これはC#ではありませんが、そこにいるグーグルのために、これが私の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

これまでのところ、かなりうまく機能しています。


1
ac#の質問に投稿するのではなく、ルビーの質問をしてこのコードで答える必要があります。
マシュー2011年

6
@Matthieu、これはC#の質問だけでなく、電子メールと電子メールの解析の質問です。私の意見では完全に関連しています。
トレント

@Trent:C#タグを削除する必要があります。
マシュー2012

7
面白いことに、この質問は(言語ではなく)トピックについてグーグルで見つけたので、実際にはRubyで何かを実装する必要がありました。だから、乾杯!
bratsche 2012

2
これはこれまでのところ最良の応答です。正規表現はかなり言語に依存しません。投稿していただきありがとうございます
超輝かしい2012

11

これを行う最も簡単な方法は、次のようなマーカーをコンテンツに配置することです。

---この行の上に返信してください---

お気づきのことと思いますが、引用されたテキストを解析することは簡単な作業ではありません。さまざまな電子メールクライアントがさまざまな方法でテキストを引用するからです。この問題を適切に解決するには、すべての電子メールクライアントを考慮してテストする必要があります。

Facebookはこれを行うことができますが、プロジェクトに大きな予算がない限り、おそらくできません。

Olegは、正規表現を使用して問題を解決し、「2012年7月13日、13:09にxxxが書き込みました:」というテキストを見つけました。ただし、多くの人が行うように、ユーザーがこのテキストを削除したり、電子メールの下部に返信したりすると、このソリューションは機能しません。

同様に、電子メールクライアントが別の日付文字列を使用している場合、または日付文字列が含まれていない場合、正規表現は失敗します。


このアプローチは、返信するたびにその行を入力しない限り、返信への返信では失敗します。
jpw 2014年

1
はい、欠点があります。ユーザーが行文字列より上の応答を削除すると、応答は失敗します。私はこのケースを見つけて、メッセージが失敗したことを知らせるダイレクトメッセージを、Webアプリ経由で返信するためのリンクとともにユーザーに送信します。ほとんどのユーザーはそれほど問題なくそれを使用できるようです。
スーパールミナリー2014年

これは受け入れられた答えでなければなりません。ただし、行を削除すると回答が成功しないという情報を追加します。
Benni 2016

@ Benni-はい、行が削除されると失敗します。残念ながら、電子メールクライアント間でテキストを引用する標準的な方法は1つではありません。行が削除された場合、すべてのテキストを返信として扱うことができます。この場合、完璧な解決策は不可能だと思います。
スーパールミナリー2017年

@superluminaryつまり、行に追加します。だからそれはのようなものです-- Please reply above this line. DO NOT REMOVE IT! --。また、私が経験したことは、一部の電子メールクライアントはxxx wrote on <datetime>:引用全体の前に、したがってその行の前に行を追加するため、常に機能するとは限らないということです。この行は正規表現で解析できますが、電子メールクライアントが異なるため、言語や形式が異なる場合があります。
Benni 2017年

6

電子メールには返信の普遍的な指標はありません。あなたができる最善のことは、最も一般的なパターンを見つけて、それらに出くわしたときに新しいパターンを解析することです。

引用されたテキスト内に返信を挿入する人もいることを覚えておいてください(たとえば、私の上司は私が尋ねたのと同じ行で質問に答えます)。そのため、何をしても、保持したい情報が失われる可能性があります。


Gmailはそれをします...少なくともそれはそれをするようです。私が覚えていることから、元のスレッドIDと返信の間で変更されないスレッドIDがいくつかあります...
kenny

Gmailは他のメールクライアントと同じように「>」を追加するかもしれませんが、それはメールの標準ではなく、
信頼

5

これが@hurshagrawalのRubyコードのC#バージョンです。Rubyのことはよくわからないので、うまくいかないかもしれませんが、正解だと思います。

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

元のメッセージ(Webアプリケーションからの通知など)を制御する場合は、識別可能な個別のヘッダーを配置し、それを元の投稿の区切り文字として使用できます。


0

これは良い解決策です。長い間検索して見つけました。

1つ追加すると、前述のように、これはケースワイズであるため、上記の式ではGmailとOutlook(2010)の応答が正しく解析されなかったため、次の2つの正規表現を追加しました。問題があれば教えてください。

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

乾杯


誰かがそのphpバージョンを手伝ってもらえますか?
user4271704 2015年

phpバージョンについてはこれを確認してください。 stackoverflow.com/questions/14916618/... github.com/willdurand/EmailReplyParser
FullStackDev

-1

これは古い投稿ですが、githubに応答を抽出するRubylibがあることを知っているかどうかはわかりません。.NETを使用している場合は、https://github.com/EricJWHuang/EmailReplyParserに.NETがあります


1
外部リソースへのリンクをお勧めしますが、リンクの前後にコンテキストを追加して、他のユーザーがそれが何であるか、なぜそこにあるのかを理解できるようにしてください。ターゲットサイトにアクセスできない場合や完全にオフラインになる場合に備えて、重要なリンクの最も関連性の高い部分を常に引用してください。
pableiros 2016年

そのライブラリを最新の状態に保っていますか?C#ライブラリがOffice 365からのOutlookからの単純な電子メールを適切に解析しないため、検索しました。次に、ルビーのソースコードを調べたところ、テストケースに同じテストケースが含まれていたため、解析する必要があると明確に考えていました。それ。
グレッグベレス

-1

SigParser.comのAPIを使用すると、単一の電子メールテキスト文字列からの返信チェーン内のすべての分割された電子メールの配列が提供されます。したがって、10通のメールがある場合は、10通すべてのメールのテキストが表示されます。

ここに画像の説明を入力してください

詳細なAPI仕様はこちらでご覧いただけます。

https://api.sigparser.com/

ここに画像の説明を入力してください

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.