2011年11月26日 星期六

ASP.net 網站對郵件的自動追蹤(C#)

網站對寄出去的郵件是否有被閱讀過的自動追蹤對於一些網站而言,追蹤自己送出的郵件確實被閱讀過會是一種很有幫助的功能‧ 當然,每一個人所需要的理由都會不同,這可能是安全考量、資源、或者只是想要確定對方確實有閱讀你送出的重要郵件‧ 也許您知道有些網站會在您註冊會員後自動送出一封包含確認連結的通知信... 其實這一篇文章也是利用類似這一種辦法來追蹤自己寄出的郵件是否有被閱讀,但這邊我不利用手動的方式讓使用者自己去確認,我們想要用自動的‧ 我在此的編寫的程式碼範例將會是 C# ,但不熟悉這語言的朋友沒關係,我將會盡量詳細說明要寫這一個程式應該要有的步驟來彌補 "語言溝通" 上的問題‧


利用圖片做到自動化效果
我們之所以能做到自動化的原因,就是因為我們要想辦法傳送一個東西給收信者,在他打開這一封信時,這一個東西會自動與某一個遠端程式做連線,然後達到追蹤的效果 :-) 因為我們知道,這個東西一連到對應的程式來,就代表使用者一定是開啟了這封信件‧ 而在這邊,我利用圖片自動遠端要求圖片的特性去連到一個可以去做確認使用者動作的網頁(或程式)... 當然,圖片我將故意調成 width=0, height=0 故意藏起來! 以下是一個圖片自動連線到網頁去的一個例子: <img src="http://127.0.0.1/mailTracker/Verify.aspx">


重點: 做到這種自動追蹤的效果,必須要有一個客戶端,跟一個回應端


如何確認一個使用者
當你看到上面html圖片語法的例子,你也許會問: "我只光連到一個網頁去,那網頁該怎麼判斷我是誰?" 當然,我們要想個辦法去辨認! 在這邊,我們假設在郵件送出前,就先製造了一個 "確認鑰匙" ,然後放在圖片的src (source) attribute 一起送出去,這樣子圖片一連線時,就會同時把我們之前丟過去鑰匙丟回,達到確認的效果‧

這一個鑰匙可以是一個名字,或一個ID等等‧ 當你要選擇要用什麼方法做確認鑰匙時,別忘了這個選擇將會影響到服務的安全性! 因為越簡單,或越容易看懂(看穿)的鑰匙,被惡作劇的可能性就越高‧ 如果你是隨便用一個照順序的ID, 像是 123... 那麼惡作據者就可以稍微寫個小script, 從123一直要求上去擾亂... 那到時就失去確認的效果‧

所以在此,我用MD5編碼output出來做確認鑰匙,這樣被擾亂的機會就很比較小‧送回鑰匙的範例如下: <img src="http://127.0.0.1/mailTracker/Verify.aspx?key=4A53428134783EC9C6935A7C0D4671EB">


從送出郵件到確認的過程
在程式碼範例前,我先說一說整個追蹤過程的步驟‧
1. 先建立收信者資料和確認鑰匙到資料庫裡去
2. 把這個鑰匙也寫在img的src attribute裡面,然後寄給收信者
3. 收信者一打開信,電腦就會開始照著img裡的src去開始要求資料
4. 連線目標,也就是對應的網頁開始拿著接受到的鑰匙去確認使用者
5. 如果接受到的鑰匙跟資料庫的符合,則標名該收信者已被確認,或直接刪除

程式碼範例
依照上面的步驟,我用C#寫出了個簡單的範例‧ 這主要分成兩個檔案,一個是mail.aspx (其實是cs檔),程式碼如下: 可需要增加的namespace:

using System.Web.Mail;
using System.Security.Cryptography;
using System.Web.Mail;


程式碼:

public class mail : System.Web.UI.Page
{
private void Page_Load(object sender, System.EventArgs e)
{
string oriConfirmKey = "thisisaconfirm1234";
string confirmKey = "";

MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
confirmKey = BitConverter.ToString(md5.ComputeHash(Encoding.ASCII.GetBytes(oriConfirmKey)));
confirmKey = confirmKey.Replace("-", "");

MailMessage mail = new MailMessage();
mail.From = "tek@tek";
mail.To = "tek_alpha@hotmail.com";
mail.Subject = "Open this email and get confirmed";
mail.BodyFormat = MailFormat.Html;
mail.Body = "Thank you, you've been confirmed :-) <img src=\"http://127.0.0.1/verify.aspx?key="+ confirmKey +"\" width=\"0\" height=\"0\">";
SmtpMail.SmtpServer = "tek";
SmtpMail.Send(mail);
Response.Write("E-mail has been sent, please confirm");
}
}
以上的method動作有:
1. 建立一個確認鑰匙,並MD5碼化
2. 寄出郵件
3. 寫出信已經被寄出
再來,另一個網頁叫做Verify.aspx (同樣是CS檔) 可能需要另外新增的namespace有:

using System.Data.OleDb;

接下來Verify的程式碼:

public class Verify : System.Web.UI.Page
{
private string dbPath = "C:\\Inetpub\\myTest.mdb";
private string dbProvider = "Microsoft.Jet.OLEDB.4.0";
private string verifyQuery = "Select * From userDB Where confirmKey = @key";
private string confirmQuery = "Update userDB Set isConfirmed = yes Where confirmKey = @key";

private void Page_Load(object sender, System.EventArgs e)
{
string getKey = Request["key"];

if (getKey != null)
{
OleDbConnection conn = new OleDbConnection("Provider="+ dbProvider +";Data Source=" + dbPath);
OleDbCommand comm = new OleDbCommand();
comm.Connection = conn;
comm.Parameters.Add(new OleDbParameter("@key", OleDbType.VarChar));
comm.Parameters["@key"].Value = getKey;

if (isVerified(conn, comm))
{
confirm(conn, comm);
Response.Write("User confirmed");
}
}
}

private bool isVerified(OleDbConnection conn, OleDbCommand comm)
{
bool userExists;
conn.Open();
comm.CommandText = verifyQuery;
OleDbDataReader reader = comm.ExecuteReader();
userExists = reader.Read();
conn.Close();
return userExists;
}

private void confirm(OleDbConnection conn, OleDbCommand comm)
{
conn.Open();
comm.CommandText = confirmQuery;
comm.ExecuteNonQuery();
conn.Close();
}
}
以上程式碼的動作有:
1. 以Query String接收確認鑰匙
2. 把鑰匙拿去資料庫檢查是否有符合的
3. 如果有符合,則在這比資料改成已確認

利用圖片還可做到什麼額外的效果
利用圖片的好處就是在進行確認時可以有互動的效果‧ 例如當使用者把確認鑰匙傳回去時,網頁還可以透過製造圖片的方式告訴使用者確認過程是失敗或者是成功‧ 這其實也是一種挺安全的方式去通知收信者! 當然,網頁自己產生圖片需要多加長點程式碼,但在這邊就先不再講下去,以免太複雜化‧

網路相關參考資源
System.Data.OlEDb:
http://msdn.microsoft.com/library/en-us/cpref/html/frlrfsystemdataoledb.asp?frame=true

System.Web.Mail:
http://msdn.microsoft.com/library/en-us/cpref/html/frlrfSystemWebMail.asp?frame=true

沒有留言:

張貼留言