1. 程式人生 > >C#利用Lumisoft元件實現收郵解析郵件功能

C#利用Lumisoft元件實現收郵解析郵件功能

一、 POP3協議簡介

1、什麼是POP3協議:
郵局協議(Post Office Protocol,簡稱POP)是TCP/IP協議族中的一員,由RFC 1939 定義。本協議主要用於支援使用客戶端遠端管理在伺服器上的電子郵件。最新版本為POP3,全名“Post Office Protocol - Version 3”,而提供了SSL加密的POP3協議被稱為POP3S。
2、POP3協議具體過程:
POP 協議支援“離線”郵件處理。其具體過程是:郵件傳送到伺服器上,電子郵件客戶端呼叫郵件客戶機程式以連線伺服器,並下載所有未閱讀的電子郵件。這種離線訪問模式是一種儲存轉發服務,將郵件從郵件伺服器端送到個人終端機器上,一般是PC機或 MAC。一旦郵件傳送到 PC 機或MAC上,郵件伺服器上的郵件將會被刪除。但目前的POP3郵件伺服器大都可以“只下載郵件,伺服器端並不刪除”,也就是改進的POP3協議。
3、電子郵件系統的基本網路結構


在這裡插入圖片描述

二、 運用C#實現POP3接收郵件的三種方法

1、 利用Socket元件
socket本質是程式設計介面,是對TCP/IP的封裝。TCP/IP是傳輸層的協議。POP3是應用層的協議,是基於TCP/IP協議的。所以,使用socket實現上述幾種協議的客戶端,其實是對藉助socket對TCP/IP資料傳輸的封裝基礎,再往上封裝一層的。
POP3只需要建立一個連線,客戶端向伺服器發命令,伺服器向客戶端返回資料就行了。具體就是通過socket發命令,再通過socket接資料 。
具體實現如下圖(實現程式碼不再詳細闡述):
在這裡插入圖片描述
該POP3客戶端主要實現的就是接收郵件功能了,然而並沒有實現郵件內容解析功能。
並且在連線過程中,163、126、sina等郵箱均可以登入至相應的pop伺服器,唯獨QQ郵箱受阻,提示資訊為:-err login fail a secure connection is required(such as ssl),所以需要建立ssl的相關安全連線才可以登入至pop伺服器,因此放棄該方法,所以選擇方法三


2、 利用OpenPop元件
這是一款可以支援 SSL 收發郵件的控制元件,和LumiSoft元件類似,自己在使用LumiSoft之前對OpenPop元件進行了測試,其中郵件解析的各項資料較全。但是OpenSmtp元件連線不了ssl,這個只對pop協議適用,而LumiSoft對所有的郵件傳輸協議均適用,所以選擇了方法三。
執行效果如下圖:
在這裡插入圖片描述
3、 利用LumiSoft元件
LumiSoft.Net是非常強大的開源元件,不僅僅傳送郵件,同樣也可用於接收郵件,在這周的學習時間裡是個人找到的最好的開源元件了。閱讀LumiSoft.Net的原始碼,可以看到LumiSoft.Net程式設計嚴格遵循了RFC(Request For Comments)定義的協議規範。通過閱讀這些原始碼對於瞭解RFC和其中關於郵件網路協議規範也是非常有幫助的。
如果要查閱RFC文件可以通過
LumiSoft元件連結
網站查詢。
執行效果如下圖:
主介面:
在這裡插入圖片描述
解析:
在這裡插入圖片描述

三、 運用LumiSoft元件實現接收郵件

1、 運用的名稱空間

using System
using System.Windows.Forms;
using System.IO;
using LumiSoft.Net;
using LumiSoft.Net.Mail;
using LumiSoft.Net.POP3.Client;
using LumiSoft.Net.MIME;

2、 連線並獲取資訊部分
(1)、連線到POP3伺服器
POP3_Client.Connect函式主要是連線pop伺服器,埠,是否用ssl
POP3_Client.Authenticate函式主要驗證郵箱和郵箱授權碼(通常為16位)

private void btn_connect_Click(object sender, EventArgs e)
        {
            if (txt_username.Text == "")
            {
                MessageBox.Show(this, "Please fill user name !", "Error:", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return;
            }

            POP3_Client pop3 = new POP3_Client();
            try
            {
                pop3.Connect(txt_server.Text, (int)number_port.Value, cb_isSSL.Checked);
                
                pop3.Authenticate(txt_username.Text, txt_password.Text, true);

                m_pPop3 = pop3;
                this.DialogResult = DialogResult.OK;

                FillMessagesList();
            }
            catch (Exception x)
            {
                MessageBox.Show(this, "POP3 server returned: " + x.Message + " !", "Error:", MessageBoxButtons.OK, MessageBoxIcon.Error);
                pop3.Dispose();
            }
        }

(2)、獲取郵件頭資訊函式FillMessagesList()
通過POP3_ClientMessage、Mail_Message獲取資訊,並寫進ListViewItem的項內,然後傳遞給lst_message的Item,以達到在窗體中顯示的目的。

private void FillMessagesList()
        {
            this.Cursor = Cursors.WaitCursor;
            try
            {
                foreach (POP3_ClientMessage message in m_pPop3.Messages)
                {
                    Mail_Message mime = Mail_Message.ParseFromByte(message.HeaderToByte());
                    Mail_Message mime2 = Mail_Message.ParseFromByte(message.MessageToByte());
                    ListViewItem item = new ListViewItem();
                    if (mime.From != null)
                    {
                        item.Text = mime.From.ToString();
                       
                    }
                    else
                    {
                        item.Text = "<none>";
                    }
                    
                    if (string.IsNullOrEmpty(mime.Subject))
                    {
                        item.SubItems.Add("<none>");
                    }
                    else
                    {
                        item.SubItems.Add(mime.Subject);
                    }
                    item.SubItems.Add(mime.Date.ToString());
                    item.SubItems.Add(((decimal)(message.Size / (decimal)1000)).ToString("f2") + " kb");
                    
                    if (mime.Cc != null)
                    {
                        item.SubItems.Add(Convert.ToString(mime.Cc));
                    }
                    else
                    {
                        item.SubItems.Add("<none>");
                    }
                    if (mime.Bcc != null)
                    {
                        item.SubItems.Add(Convert.ToString(mime.Bcc));
                    }
                    else
                    {
                        item.SubItems.Add("<none>");
                    }
                    item.SubItems.Add(mime.ContentTransferEncoding);
                    item.SubItems.Add(mime.MessageID);
                    item.SubItems.Add(mime.MimeVersion);
                    item.SubItems.Add(Convert.ToString(mime.Received));
                    item.SubItems.Add(mime2.BodyHtmlText);
                    item.SubItems.Add(Convert.ToString(mime.ContentType));
                   
                    item.SubItems.Add(Convert.ToString(mime.IsDisposed));
                    item.SubItems.Add(Convert.ToString(mime.IsModified));
                    

                    item.Tag = message;
                    lst_messages.Items.Add(item);
                }
            }
            catch (Exception x)
            {
                MessageBox.Show(this, "Error: " + x.Message, "Error:", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            this.Cursor = Cursors.Default;
        }

(3)、SSL判斷函式
通過WellKnownPorts方法自動獲取各個郵件伺服器所在ssl或者非ssl狀態下對應的埠。

private void cb_isSSL_CheckedChanged_1(object sender, EventArgs e)
        {
            if (cb_isSSL.Checked)
            {
                number_port.Value = WellKnownPorts.POP3_SSL;
            }
            else
            {
                number_port.Value = WellKnownPorts.POP3;
            }
        }

3、 通過窗體獲取具體解析的資訊部分
(1)、郵件列表內點選行為
通過點選郵件列表內的郵件項這一選擇行為,會相應地在下面附件欄和正文欄顯示出對應的資訊,並把郵件頭解析資訊返回至txt_Header,其中用到了POP3_ClientMessage、Mail_Message、MIME_Entity方法。

private void lst_messages_SelectedIndexChanged(object sender, EventArgs e)
        {
            this.Cursor = Cursors.WaitCursor;
            try
            {
                toolStrip1.Items["save"].Enabled = false;
                toolStrip1.Items["delete"].Enabled = false;
                if (lst_messages.SelectedItems.Count > 0)
                {
                    lst_attachment.Items.Clear();
                    txt_Body.Text = "";

                    POP3_ClientMessage message = (POP3_ClientMessage)lst_messages.SelectedItems[0].Tag;
                    Mail_Message mime = Mail_Message.ParseFromByte(message.MessageToByte());

                    string Sender = mime.From == null ? "Sender is null" : mime.From[0].DisplayName;
                    string senderAddress = mime.From == null ? "senderAddress is null" : mime.From[0].Address;
                    string subject = mime.Subject ?? "subject is null";
                    string recDate = mime.Date == DateTime.MinValue ? "date not specified" : mime.Date.ToString();
                    string content = mime.BodyText ?? "content is null";

                    

                    foreach (MIME_Entity entity in mime.Attachments)
                    {
                        ListViewItem item = new ListViewItem();
                        if (entity.ContentDisposition != null && entity.ContentDisposition.Param_FileName != null)
                        {
                            item.Text = entity.ContentDisposition.Param_FileName;
                        }
                        else
                        {
                            item.Text = "untitled";
                        }
                        item.Tag = entity;
                        lst_attachment.Items.Add(item);
                    }

                    if (mime.BodyText != null)
                    {
                        txt_Body.Text = mime.BodyText;
                    }
                    if (mime.Header != null)
                    {
                    txt_Header.Text = Convert.ToString(mime.Header);
                    }
                    toolStrip1.Items["save"].Enabled = true;
                    toolStrip1.Items["delete"].Enabled = true;
                }
            }
            catch (Exception x)
            {
                MessageBox.Show(this, "Error: " + x.Message, "Error:", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            this.Cursor = Cursors.Default;
        }

(2)、郵件列表內儲存及刪除行為
在toolStrip上生成兩個button,分別對應儲存及刪除。

private void toolStrip1_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            if (string.Equals(e.ClickedItem.Name, "save"))
            {
                SaveFileDialog dlg = new SaveFileDialog();
                dlg.FileName = "message.eml";
                if (dlg.ShowDialog() == DialogResult.OK)
                {
                    this.Cursor = Cursors.WaitCursor;
                    POP3_ClientMessage message = (POP3_ClientMessage)lst_messages.SelectedItems[0].Tag;
                    File.WriteAllBytes(dlg.FileName, message.MessageToByte());
                    this.Cursor = Cursors.Default;
                }
            }
            else if (string.Equals(e.ClickedItem.Name, "delete"))
            {
                if (MessageBox.Show(this, "Do you want to delete selected message ?", "Confirm Delete:", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
                {
                    POP3_ClientMessage message = (POP3_ClientMessage)lst_messages.SelectedItems[0].Tag;
                    message.MarkForDeletion();
                    lst_messages.SelectedItems[0].Remove();
                }
            }
        }

(3)、附件列表內點選行為
通過滑鼠右鍵點選“Save”可以把附件下載至本地
1、右鍵點選生成選單函式:

private void lst_attachment_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right && lst_attachment.SelectedItems.Count > 0)
            {
                ContextMenuStrip menu = new ContextMenuStrip();
                menu.Items.Add("Save");
                menu.ItemClicked += new ToolStripItemClickedEventHandler(menu_ItemClicked);
                menu.Show(Control.MousePosition);
            }
        }

2、點選“Save”儲存函式:

private void menu_ItemClicked(object sender, ToolStripItemClickedEventArgs e)
        {
            MIME_Entity entity = (MIME_Entity)lst_attachment.SelectedItems[0].Tag;
            SaveFileDialog dlg = new SaveFileDialog();
            dlg.FileName = lst_attachment.SelectedItems[0].Text;
            if (dlg.ShowDialog(this) == DialogResult.OK)
            {
                File.WriteAllBytes(dlg.FileName, ((MIME_b_SinglepartBase)entity.Body).Data);
            }
        }

總結

1、QQ、163、sina等主流郵箱均可以登入。
2、通過解析可以獲取郵件的基本資訊,比如發件人、郵件正文編碼方式、抄送人、主題、大小、時間、ip地址等等。
3、可以執行郵件的刪除和下載行為,並可以下載附件,附件的格式沒有影響,exe,jpg,pdf均可下載。