Parse konten email dari balasan yang dikutip

88

Saya mencoba mencari cara untuk mengurai teks email dari teks balasan kutipan yang mungkin disertakan. Saya perhatikan bahwa biasanya klien email akan meletakkan "Pada tanggal ini dan itu menulis ini dan itu" atau mengawali baris dengan tanda kurung siku. Sayangnya, tidak semua orang melakukan ini. Adakah yang tahu tentang cara mendeteksi teks balasan secara terprogram? Saya menggunakan C # untuk menulis parser ini.

VanOrman
sumber
2
Apakah Anda beruntung dengan ini? Saya ingin melakukan hal yang persis sama.
steve_c
solusi akhir apa saja dengan contoh kode sumber lengkap yang mengerjakannya?
Kiquenet
Quotequail melakukan ini dengan Python
philfreo
Adakah yang bisa membantu untuk versi php-nya?
pengguna4271704

Jawaban:

60

Saya melakukan lebih banyak pencarian tentang ini dan inilah yang saya temukan. Pada dasarnya ada dua situasi saat Anda melakukan ini: saat Anda memiliki seluruh utas dan saat tidak. Saya akan memecahnya menjadi dua kategori itu:

Jika Anda memiliki utas:

Jika Anda memiliki seluruh rangkaian email, Anda dapat mencapai tingkat jaminan yang sangat tinggi bahwa apa yang Anda hapus sebenarnya adalah teks kutipan. Ada dua cara untuk melakukannya. Pertama, Anda dapat menggunakan Message-ID, In-Reply-To ID, dan Thread-Index untuk menentukan pesan individual, induknya, dan utasnya. Untuk informasi lebih lanjut tentang ini, lihat RFC822 , RFC2822 , artikel menarik tentang threading ini , atau artikel tentang threading ini . Setelah Anda memasang kembali utas, Anda dapat menghapus teks eksternal (seperti baris Kepada, Dari, CC, dll ...) dan selesai.

Jika pesan yang Anda kerjakan tidak memiliki header, Anda juga dapat menggunakan pencocokan kesamaan untuk menentukan bagian email mana yang merupakan teks balasan. Dalam hal ini Anda terjebak dengan melakukan pencocokan kesamaan untuk menentukan teks yang diulang. Dalam hal ini Anda mungkin ingin melihat algoritma Jarak Levenshtein seperti ini di Proyek Kode atau yang satu ini .

Apa pun yang terjadi, jika Anda tertarik dengan proses threading, lihat PDF hebat ini tentang memasang kembali utas email .

Jika Anda tidak memiliki utas:

Jika Anda terjebak dengan hanya satu pesan dari utas, Anda harus mencoba menebak apa kutipannya. Dalam hal ini, berikut adalah metode kutipan berbeda yang telah saya lihat:

  1. garis (seperti yang terlihat di outlook).
  2. Kurung Sudut
  3. "---Pesan asli---"
  4. "Pada hari ini dan itu, si ini dan itu menulis:"

Hapus teks dari sana ke bawah dan Anda selesai. Kelemahan dari semua ini adalah bahwa mereka semua berasumsi bahwa pengirim meletakkan balasan mereka di atas teks kutipan dan tidak menyisipkannya (seperti gaya lama di internet). Jika itu terjadi, semoga berhasil. Saya harap ini membantu beberapa dari Anda di luar sana!

VanOrman
sumber
32

Pertama-tama, ini adalah tugas yang sulit.

Anda harus mengumpulkan tanggapan umum dari klien email yang berbeda dan menyiapkan ekspresi reguler yang benar (atau apa pun) untuk menguraikannya. Saya telah mengumpulkan tanggapan dari outlook, thunderbird, gmail, apple mail dan mail.ru.

Saya menggunakan ekspresi reguler untuk mengurai respons dengan cara berikut: jika ekspresi tidak cocok, saya mencoba menggunakan yang berikutnya.

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

Untuk menghapus kutipan pada akhirnya:

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

Berikut adalah kumpulan kecil tanggapan pengujian saya (sampel dibagi dengan --- ):

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

Salam Hormat, Oleg Yaroshevych

Oleg Yaroshevych
sumber
Bagaimana jika saya tidak tahu alamat emailnya?
harsimranb
@ Shyamal-Parikh ini tidak akan berfungsi untuk email html, tetapi biasanya pesan teks biasa juga disertakan dengan pesan email
maembe
26

Terima kasih, Goleg, untuk regexnya! Sangat membantu. Ini bukan C #, tapi untuk googler di luar sana, inilah skrip parsing Ruby saya:

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

Sejauh ini, ini bekerja dengan cukup baik.

hurshagrawal
sumber
1
Anda harus membuat pertanyaan ruby ​​dan menjawabnya dengan kode ini daripada mempostingnya di pertanyaan ac #.
Matthieu
6
@ Matthieu, ini bukan hanya pertanyaan C #, tetapi pertanyaan email dan penguraian email. sangat relevan menurut saya.
Trent
@Trent: tag C # harus dibuang kemudian.
Matthieu
7
Lucunya saya menemukan pertanyaan ini dengan Googling untuk topiknya (bukan bahasanya), dan saya sebenarnya perlu mengimplementasikan sesuatu di Ruby. Jadi, bersulang!
bratsche
2
Ini adalah respon terbaik sejauh ini. Regex adalah bahasa yang cukup agnostik. Terima kasih telah memposting
superluminary
11

Sejauh ini, cara termudah untuk melakukannya adalah dengan menempatkan penanda di konten Anda, seperti:

--- Harap balas di atas baris ini ---

Seperti yang sudah Anda ketahui, mengurai kutipan teks bukanlah tugas yang mudah karena klien email yang berbeda mengutip teks dengan cara yang berbeda. Untuk mengatasi masalah ini dengan benar, Anda perlu memperhitungkan dan menguji di setiap klien email.

Facebook dapat melakukan ini, tetapi jika proyek Anda memiliki anggaran yang besar, Anda mungkin tidak dapat melakukannya.

Oleg telah memecahkan masalah menggunakan regex untuk menemukan teks "Pada 13 Jul 2012, pada 13:09, xxx menulis:". Namun, jika pengguna menghapus teks ini, atau membalas di bagian bawah email, seperti yang dilakukan banyak orang, solusi ini tidak akan berfungsi.

Begitu juga jika klien email menggunakan string tanggal yang berbeda, atau tidak menyertakan string tanggal, regex akan gagal.

superluminer
sumber
Pendekatan ini gagal dengan balasan untuk balasan kecuali Anda meletakkan baris itu setiap kali Anda membalas.
jpw
1
Ya, ada kekurangannya. Jika pengguna menghapus balasan di atas string baris maka balasan Anda akan gagal. Saya menangkap kasus ini dan mengirimi pengguna pesan langsung yang memberi tahu mereka bahwa pesan mereka gagal, dengan tautan untuk membalas melalui aplikasi web. Sebagian besar pengguna tampaknya dapat menggunakannya tanpa terlalu banyak kesulitan.
superluminary
Ini harus menjadi jawaban yang diterima. Namun, saya akan menambahkan informasi bahwa jawabannya tidak akan berhasil jika garis tersebut dihapus.
Benni
@Benni - ya, itu akan gagal jika garis dihapus. Sayangnya, tidak ada satu cara standar untuk mengutip teks di seluruh klien email. Jika baris tersebut dihapus, Anda dapat memperlakukan semua teks sebagai balasan. Saya tidak berpikir solusi sempurna mungkin dalam kasus ini.
superluminary
@superluminary Maksud saya, saya akan menambahkannya ke baris. Jadi seperti itu -- Please reply above this line. DO NOT REMOVE IT! --. Juga, Apa yang saya alami adalah bahwa itu tidak selalu berhasil karena beberapa klien email menambahkan xxx wrote on <datetime>:baris sebelum seluruh kutipan dan sebelum baris itu. Baris ini dapat diurai dengan ekspresi reguler, namun mungkin dalam bahasa yang berbeda dan dalam format yang berbeda karena klien email berbeda.
Benni
7

Tidak ada indikator universal balasan dalam email. Hal terbaik yang dapat Anda lakukan adalah mencoba menangkap pola paling umum dan mengurai baru saat Anda menemukannya.

Ingatlah bahwa beberapa orang memasukkan balasan ke dalam teks kutipan (Bos saya misalnya menjawab pertanyaan pada baris yang sama seperti yang saya tanyakan) jadi apa pun yang Anda lakukan, Anda mungkin kehilangan beberapa informasi yang ingin Anda simpan.

Doubloons
sumber
gmail melakukannya ... setidaknya tampaknya melakukannya. Dari yang saya ingat ada beberapa id utas yang tidak berubah antara yang asli dan balasan ...
kenny
gmail mungkin menambahkan '> seperti yang dilakukan klien email lainnya, tetapi ini bukan standar email dan bukan sesuatu yang dapat Anda andalkan
3Doubloons
6

Ini adalah kode Ruby versi C # saya dari @ hurshagrawal. Saya tidak terlalu mengenal Ruby sehingga bisa saja tidak aktif, tapi saya pikir saya sudah benar.

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
sumber
3

Jika Anda mengontrol pesan asli (mis. Pemberitahuan dari aplikasi web), Anda dapat menempatkan header yang berbeda dan dapat diidentifikasi, dan menggunakannya sebagai pembatas untuk posting asli.

Eric R. Rath
sumber
0

Ini adalah solusi yang bagus. Menemukannya setelah lama mencari.

Satu tambahan, seperti yang disebutkan di atas, ini adalah kasus bijaksana, jadi ekspresi di atas tidak mengurai dengan benar tanggapan gmail dan pandangan (2010) saya, yang saya tambahkan dua Regex berikut (s). Beri tahu saya jika ada masalah.

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

Bersulang

Amit M
sumber
Adakah yang bisa membantu untuk versi php-nya?
pengguna4271704
-1

Ini adalah posting lama, namun, tidak yakin apakah Anda tahu github memiliki lib Ruby yang mengekstrak balasannya. Jika Anda menggunakan .NET, saya memiliki .NET di https://github.com/EricJWHuang/EmailReplyParser

Eric Huang
sumber
1
Tautan ke sumber daya eksternal dianjurkan, tetapi harap tambahkan konteks di sekitar tautan sehingga sesama pengguna Anda tahu apa itu dan mengapa itu ada. Selalu kutip bagian paling relevan dari tautan penting, jika situs target tidak dapat dijangkau atau offline secara permanen.
pableiros
apakah Anda terus memperbarui perpustakaan itu? Saya datang mencari karena pustaka C # tidak mengurai email sederhana dari Outlook dari Office 365 dengan benar. Kemudian saya melihat kode sumber ruby ​​dan menemukan bahwa ada kasus uji yang identik dalam kasus uji mereka sehingga jelas mereka pikir mereka harus mengurai Itu.
Greg Veres
-2

Jika Anda menggunakan API SigParser.com , ini akan memberi Anda array dari semua email yang dipecah dalam rantai balasan dari satu string teks email. Jadi jika ada 10 email, Anda akan mendapatkan teks untuk 10 email tersebut.

masukkan deskripsi gambar di sini

Anda dapat melihat spesifikasi API mendetail di sini.

https://api.sigparser.com/

masukkan deskripsi gambar di sini

Paul Mendoza
sumber