【初码干货】使用阿里云邮件推送服务架设自己邮件验证与推送体系
提示:閱讀本文需提前了解的相關(guān)知識
1、電子郵件協(xié)議(http://baike.baidu.com/view/2367542.htm)
2、阿里云郵件推送(https://www.aliyun.com/product/directmail)
3、EDM(電子郵件營銷)(http://baike.baidu.com/subview/1212416/8602812.htm)
4、SendCloud郵件服務(wù)(http://sendcloud.sohu.com/)
閱讀目錄結(jié)構(gòu)
引:
一、需求分析
二、功能設(shè)計
三、詳細(xì)實(shí)現(xiàn)步驟
四、總結(jié)與思考
引:
我們會發(fā)現(xiàn),越來越多的互聯(lián)網(wǎng)應(yīng)用和企業(yè)級應(yīng)用,開始使用郵件驗(yàn)證碼驗(yàn)證替代郵件鏈接驗(yàn)證,例如下圖:
又例如:
當(dāng)然,也有更多的應(yīng)用使用了漂亮的HTML代碼來裝飾郵件,例如:
又例如:
我想,一個優(yōu)秀的互聯(lián)網(wǎng)應(yīng)用或者個體經(jīng)營的站長站點(diǎn),如果在注冊、身份證驗(yàn)證、信息推送等功能上,加上如上效果的郵件服務(wù),一定能帶來更加優(yōu)質(zhì)的用戶體驗(yàn)
而郵件服務(wù)也不是現(xiàn)在才有,我們可以回顧一下發(fā)展歷史
很多站長應(yīng)該都記得,在例如Discuz、WordPress等CMS中,都可以配置SMTP信息,開通了163等郵箱的SMTP功能就可以填入賬號密碼,從而達(dá)到發(fā)送郵件的功能。
很多企業(yè)在若干年前,也熱衷于使用大型如ExchangeServer,中小型如UMail等軟件搭建自己的企業(yè)郵件服務(wù)系統(tǒng)。
但是隨著互聯(lián)網(wǎng)的發(fā)展,伴隨著QQ等郵件服務(wù)商的走紅,傳統(tǒng)的國外那一套郵件規(guī)則和秩序已經(jīng)發(fā)生了改變,有時候就算你有很多IP,做了反向解析,在Spamhaus白名單,又或者虛擬了不同的helo域,QQ郵箱還是照攔不誤,最終還是得單獨(dú)花錢向國內(nèi)外各大ESP購買獨(dú)立通道
在這種情況下,自建郵局系統(tǒng)或者郵件SMTP服務(wù),就顯得得不償失了,所以一方面各大企業(yè)郵箱服務(wù)越做越好,得到企業(yè)的認(rèn)可,另一方面,國內(nèi)外如SendGrid,SendCloud等第三方郵件PUSH服務(wù)商也逐漸做大,他們用更專業(yè)的手段,去解決通道、白名單、信譽(yù)度等各種郵件服務(wù)問題,而客戶只需要通過SMTP協(xié)議或者封裝的API接口,就可以非常便捷的給用戶發(fā)送郵件
就我所知,目前國內(nèi)做的最好的當(dāng)屬搜狐的SendCloud,但是SendCloud發(fā)展了這么多年,也越來越復(fù)雜和專業(yè),我認(rèn)為更適合有大型EDM需求的應(yīng)用使用,作為中小企業(yè)和創(chuàng)業(yè)者以及站長,首推依然是阿里云的郵件推送服務(wù),一如既往秉持阿里云的特點(diǎn):使用傻瓜,上手快速,文檔俱全,但漏洞和問題多多,不過作為AWS的追趕者,能在短時間內(nèi)快速實(shí)現(xiàn)這些應(yīng)用級功能,也算是值得鼓勵的。因此下面也基于阿里云郵件推送服務(wù),來實(shí)現(xiàn)一個自己的郵件驗(yàn)證與推送體系。
一、需求分析
做任何事情,頂層設(shè)計非常重要,優(yōu)秀的設(shè)計往往讓以后的事情事半功倍,所以在設(shè)計整個郵件驗(yàn)證與推送體系前,我們先看看有哪些功能是希望能夠?qū)崿F(xiàn)的
支持郵件發(fā)送驗(yàn)證碼和郵件營銷推送
能夠通過開發(fā)在程序邏輯或者管理界面中自動觸發(fā)發(fā)送
能夠支持HTML的郵件內(nèi)容,而HTML內(nèi)容能夠隨時隨地進(jìn)行修改,方便美工和開發(fā)去調(diào)整
驗(yàn)證類郵件能夠支持IP統(tǒng)計、次數(shù)統(tǒng)計,能夠進(jìn)行時間限制、防止惡意發(fā)送
推送類郵件能夠支持統(tǒng)計發(fā)送數(shù)量、發(fā)送成功率等反饋數(shù)據(jù)。
推送類郵件,用戶可以退訂。
當(dāng)然,最重要的,驗(yàn)證郵件要能在5-10秒內(nèi)發(fā)送成功,到達(dá)率高
二、功能設(shè)計
經(jīng)過以上需求分析,可以明確出以下一些關(guān)鍵的設(shè)計思路
1、需要設(shè)計模板功能。通過模板功能來支持HTML郵件內(nèi)容以及隨時可更新替換的要求,通過模板里的關(guān)鍵詞參數(shù)設(shè)計,來達(dá)到驗(yàn)證碼、用戶名、營銷內(nèi)容的動態(tài)輸入。
2、需要設(shè)計一個驗(yàn)證碼相關(guān)表。用來支撐郵件驗(yàn)證碼校驗(yàn)、請求限制等功能。
3、需要設(shè)計一個發(fā)送記錄相關(guān)表。記錄所有發(fā)送記錄,用于統(tǒng)計和分析。
4、管理后臺盡量界面化管理。用戶管理、郵件模板配置、發(fā)送記錄查詢等基本支撐功能,在后臺盡量以界面化實(shí)現(xiàn)管理。
5、將企業(yè)郵局和郵件推送服務(wù)分開。以域名XXX.com為例,一般企業(yè)郵局地為zhangsan@XXX.com,郵件服務(wù)不宜以XXX.com為域,會和企業(yè)郵局服務(wù)相互干擾(也不是完全不可能,只是配置起來很麻煩),應(yīng)當(dāng)增加一個二級域名,例如mail.XXX.com,郵件服務(wù)地址就是service@mail.XXX.com。
整體功能架構(gòu)圖如下:
三、詳細(xì)實(shí)現(xiàn)步驟
正好手上有個網(wǎng)站,含有注冊郵件驗(yàn)證功能,那就基于這個網(wǎng)站的開發(fā),一步一步的講解一下詳細(xì)的實(shí)現(xiàn)步驟
最終實(shí)現(xiàn)效果如下:
網(wǎng)站域名是:alphams.cn,地址為 https://www.alphams.cn,用戶注冊地址為https://www.alphams.cn/Register
官方企業(yè)郵箱域是@alphams.cn,客服郵件地址為:kefu@alphams.cn
在阿里云申請的郵件服務(wù)域?yàn)椋篅mail.alphams.cn,服務(wù)郵件地址為:service@mail.alphams.cn
具體的實(shí)現(xiàn)步驟為:
1、注冊阿里云企業(yè)郵箱免費(fèi)版,實(shí)現(xiàn)客服郵件地址
我們的企業(yè)郵局服務(wù)使用了阿里云企業(yè)郵箱免費(fèi)版。(吐槽一下,竟然要轉(zhuǎn)發(fā)微博才能注冊還捆綁消費(fèi)6元郵件推送)
支付成功后,可以在企業(yè)郵箱列表中看到
下面繼續(xù)設(shè)置解析,可以到幫助頁面看到如何設(shè)置解析
前往域名解析處進(jìn)行解析設(shè)置
解析后,企業(yè)郵箱生效,進(jìn)行管理員用戶密碼初始化
使用管理員賬號進(jìn)入 https://qiye.aliyun.com/
繼續(xù)設(shè)置安全問題并綁定手機(jī)號
成功進(jìn)入后繼續(xù)添加客戶賬號
至此,企業(yè)郵局賬號添加成功,到Foxmail中進(jìn)行登錄。
2、配置阿里云郵件服務(wù)
首先要添加一個發(fā)信域名
這里我們也可以注意到,阿里云也提示不要添加企業(yè)郵箱域名,這和我們之前設(shè)計中的思路一致,這里我們添加的域名是 mail.alphams.cn
然后阿里云提示需要配置一些解析信息,從而生效域名
下面前往阿里云的域名解析中進(jìn)行設(shè)置
設(shè)置好了以后回到剛才的頁面進(jìn)行驗(yàn)證
這樣,域名就添加成功了
下面繼續(xù)添加發(fā)信地址
這里我們可以看到,發(fā)信賬號如我們之前所說,是service@mail.alphams.cn
發(fā)信類型選擇了批量郵件(這里有個疑問,在實(shí)測中發(fā)現(xiàn),阿里云這個推送服務(wù)有觸發(fā)郵件和批量郵件,觸發(fā)郵件類型偶爾會發(fā)不出去或者接收不到,不知道原因是什么,有深入研究的人感謝告知我一下)
這時候回信地址還未通過驗(yàn)證,我們點(diǎn)擊驗(yàn)證回信地址,然后前往之前申請的QQ企業(yè)郵箱中,來驗(yàn)證
這樣就進(jìn)行了驗(yàn)證
這時候還需要設(shè)置一下SMTP密碼,我們設(shè)置為XXX
這里特別需要注意的是阿里云的官方說明
發(fā)信域名在創(chuàng)建之前要仔細(xì),因?yàn)椴荒芙o刪除和修改。
這樣,阿里云郵件服務(wù)的配置就完成了。
SMTP服務(wù)地址為:smtpdm.aliyun.com,SMTP賬號就是service@mail.alphams.cn,密碼就是剛才設(shè)置的密碼
到這一步為止,已經(jīng)可以為很多站長網(wǎng)站的郵件服務(wù)提供支撐了,在一些CMS里面直接配置入SMTP信息即可使用。
但是,網(wǎng)站和應(yīng)用大部分都是獨(dú)立開發(fā),我們更需要設(shè)計自己的郵件發(fā)送和功能處理體系,因此下面我們繼續(xù)
3、用戶注冊頁面的準(zhǔn)備工作
具體的頁面編碼和程序邏輯因?yàn)榉墙裉焖v重點(diǎn),所以這里省略若干字以及若干代碼,把主要的步驟列出來,源碼可郵件找我要:
由于要加入郵件地址的驗(yàn)證,所以先對注冊頁面的完整流程進(jìn)行設(shè)計,邏輯圖如下:
其中,為了增強(qiáng)用戶體驗(yàn),先驗(yàn)證郵件地址,再輸入用戶名,而這種里面的關(guān)聯(lián)和強(qiáng)邏輯用一個注冊會話表來進(jìn)行控制
注冊會話表結(jié)構(gòu)如下:
臨時驗(yàn)證成功的郵件地址,存入會話表,并向客戶端反回一個會話編號,最終完成注冊時,需要用戶名密碼連同這個會話編號一起傳入后臺驗(yàn)證注冊
接下來就是郵件驗(yàn)證表的設(shè)計
這個表既要能支持沒有用戶狀態(tài)的驗(yàn)證,例如注冊驗(yàn)證,又要能支持用戶運(yùn)行時的驗(yàn)證,例如修改密碼驗(yàn)證等。
表結(jié)構(gòu)如下:
其中渠道為具體的使用場景,狀態(tài)和過期時間兩個字段用來雙重控制有效性,預(yù)留的兩個參數(shù),用于存儲用戶編號、注冊會話編號等額外的數(shù)據(jù)
當(dāng)然,也少不了用戶表,因?yàn)檫@里并沒有什么特殊的用戶場景,所以用戶表較為簡單,結(jié)構(gòu)如下:
4、郵件模板的設(shè)計
接下來就進(jìn)入具體的開發(fā),在開發(fā)中,肯定會用到對郵件的發(fā)送,在我們這個設(shè)計的體系里面,最上面也說了,需要設(shè)計模板機(jī)制,那么我們就先設(shè)計郵件模板功能
具體的功能架構(gòu)為:
這里設(shè)計了最簡單的模板功能,主要思路即數(shù)據(jù)庫存儲HTML模板內(nèi)容,參數(shù)直接放入HTML代碼中,在開發(fā)時進(jìn)行替換
下面是郵件模板表的設(shè)計,表結(jié)構(gòu)如下:
在后端對模板進(jìn)行增刪改查管理,省略代碼若干,最終效果如下:
先構(gòu)建一個用于新用戶注冊的HTML模板
然后在管理界面添加信息和HTML代碼
然后添加成功
5、郵件發(fā)送的技術(shù)準(zhǔn)備
通過阿里云的技術(shù)文檔可以知道,阿里云郵件服務(wù)的調(diào)用方式有三種
原本準(zhǔn)備使用API接口進(jìn)行封裝,但是最近太忙了,所以先使用STMP接口方式進(jìn)行了一次封裝,主要代碼如下:
實(shí)體:
/// <summary>
/// 郵件直推請求
/// </summary>
public class AliyunEMailDirectPushRequest
{
/// <summary>
/// 目標(biāo)郵件地址列表
/// </summary>
public Dictionary<String, String> AimAddressList { get; set; }
/// <summary>
/// 來源郵件地址
/// </summary>
public KeyValuePair<String, String> FromAddress { get; set; }
/// <summary>
/// 回復(fù)郵件地址列表
/// </summary>
public Dictionary<String, String> ReplyAddressList { get; set; }
/// <summary>
/// 郵件標(biāo)題
/// </summary>
public String Subject { get; set; }
/// <summary>
/// 郵件文本
/// </summary>
public String Text { get; set; }
/// <summary>
/// 郵件HTML
/// </summary>
public String HTML { get; set; }
/// <summary>
/// 類型
/// </summary>
public Int32 Type { get; set; }
/// <summary>
/// SMTP用戶名
/// </summary>
public String SMTPUserName { get; set; }
/// <summary>
/// SMTP密碼
/// </summary>
public String SMTPPassword { get; set; }
}
/// <summary>
/// 郵件直推響應(yīng)
/// </summary>
public class AliyunEMailDirectPushResponse
{
/// <summary>
/// 推送結(jié)果
/// </summary>
public Int32 Result { get; set; }
/// <summary>
/// 推送結(jié)果消息
/// </summary>
public String ResultMessage { get; set; }
}
發(fā)送業(yè)務(wù)代碼:
/// <summary>
/// 郵件直接推送
/// </summary>
/// <param name="String"></param>
/// <returns></returns>
public static AliyunEMailDirectPushResponse EMailDirectPush(AliyunEMailDirectPushRequest _Request)
{
AliyunEMailDirectPushResponse MyReturn = new AliyunEMailDirectPushResponse();
MailMessage MyMailMessage = new MailMessage();
//填充目標(biāo)郵件地址
foreach (var e in _Request.AimAddressList)
{
MyMailMessage.To.Add(new MailAddress(e.Key, e.Value));
}
//填充來源郵件地址
MyMailMessage.From = new MailAddress(_Request.FromAddress.Key, _Request.FromAddress.Value);
//填充回復(fù)郵件地址
foreach (var e in _Request.ReplyAddressList)
{
MyMailMessage.ReplyToList.Add(new MailAddress(e.Key, e.Value));
}
// 郵件主題
MyMailMessage.Subject = _Request.Subject;
// 郵件正文內(nèi)容
String Text = _Request.Text;
String HTML = _Request.HTML;
if (_Request.Type == 1)
{
//文本發(fā)送方式
MyMailMessage.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(Text, null, MediaTypeNames.Text.Plain));
}
if (_Request.Type == 2)
{
//HTML發(fā)送方式
MyMailMessage.AlternateViews.Add(AlternateView.CreateAlternateViewFromString(HTML, null, MediaTypeNames.Text.Html));
}
//郵件推送的SMTP地址和端口
SmtpClient MySmtpClient = new SmtpClient("smtpdm.aliyun.com", 25);
// 使用SMTP用戶名和密碼進(jìn)行驗(yàn)證
System.Net.NetworkCredential MyNetworkCredential = new System.Net.NetworkCredential(_Request.SMTPUserName, _Request.SMTPPassword);
MySmtpClient.Credentials = MyNetworkCredential;
MySmtpClient.Timeout = 5000;//設(shè)置5秒超時
try
{
MySmtpClient.Send(MyMailMessage);
MyReturn.Result = 1;
MyReturn.ResultMessage = "發(fā)送成功";
return MyReturn;
}
catch (Exception e)
{
MyReturn.Result = -1;
MyReturn.ResultMessage = e.Message;
return MyReturn;
}
}
6、郵件驗(yàn)證碼生成與發(fā)送的實(shí)現(xiàn)
主要代碼如下:
/// <summary>
/// 創(chuàng)建注冊郵件驗(yàn)證
/// </summary>
/// <param name="_Request"></param>
/// <returns></returns>
private DWebAccountCreateRegisterEMailVerifyResponse CreateRegisterEMailVerify(DWebAccountCreateRegisterEMailVerifyRequest _Request, HttpRequestMessage _HttpRequest)
{
DWebAccountCreateRegisterEMailVerifyResponse MyResponse = new DWebAccountCreateRegisterEMailVerifyResponse();
DWebMySQLDataContexter CheckQueryDataContexter = CreateNewDataContexter();
//首先檢查是否存在郵件
var UserCheckQuery = CheckQueryDataContexter.ams_user_table.Where(e => e.AUT_EMAILADDRESS == _Request.EMailAddress);
if (UserCheckQuery.Count() > 0)
{
MyResponse.SetResult(-1, "郵件已經(jīng)存在");
return MyResponse;
}
else
{
//再檢查和最近一次的發(fā)送是否已經(jīng)超過1分鐘了
DateTime CheckDateTime = DateTime.Now.AddMinutes(4);//增加4分鐘
var VerifyCreateCheckQuery = CheckQueryDataContexter.ams_email_verify_table.Where(e => e.AEVT_EMAILADDRESS == _Request.EMailAddress && e.AEVT_EXPIRETIME >= CheckDateTime);
if (VerifyCreateCheckQuery.Count() > 0)
{
MyResponse.SetResult(-2, "一分鐘內(nèi)只能發(fā)送一次郵件,請稍后再試!");
return MyResponse;
}
else
{
//將之前發(fā)送的驗(yàn)證碼全部失效
DWebMySQLDataContexter UpdateQueryDataContexter = CreateNewDataContexter();
var EMailVerifyClearUpdateQuery = UpdateQueryDataContexter.ams_email_verify_table.Where(e => e.AEVT_EMAILADDRESS == _Request.EMailAddress);
var RegisterSessionClearUpdateQuery = UpdateQueryDataContexter.ams_register_session_table.Where(e => e.ARST_EMAILADDRESS == _Request.EMailAddress);
foreach (var e in EMailVerifyClearUpdateQuery)
{
e.AEVT_STATE = -1;//表示失效
}
foreach (var e in RegisterSessionClearUpdateQuery)
{
e.ARST_STATE = -1;//表示失效
}
try
{
UpdateQueryDataContexter.SaveChanges();
//下面發(fā)起一個新的驗(yàn)證
DWebMySQLDataContexter NewTableDataContexter = CreateNewDataContexter();
//生成驗(yàn)證碼
Random MyRandom = new Random();
String VerifyCode = MyRandom.Next(1000, 10000).ToString();//獲得一個4位隨機(jī)碼
DateTime NowDateTime = DateTime.Now;
ams_email_verify_table TempEMailVerifyTable = new ams_email_verify_table();
TempEMailVerifyTable.AEVT_ID = BLHelper.NewGuid();
TempEMailVerifyTable.AEVT_CHANNEL = 1;//表示注冊驗(yàn)證
TempEMailVerifyTable.AEVT_CHANNELDESCRIPTION = "注冊驗(yàn)證";
TempEMailVerifyTable.AEVT_CREATETIME = NowDateTime;
TempEMailVerifyTable.AEVT_EXPIRETIME = NowDateTime.AddSeconds(300);//有效期300秒,5分鐘
TempEMailVerifyTable.AEVT_EMAILADDRESS = _Request.EMailAddress;
TempEMailVerifyTable.AEVT_PARAMETER1 = "";//參數(shù)暫時為空
TempEMailVerifyTable.AEVT_PARAMETER2 = "";//參數(shù)暫時為空
TempEMailVerifyTable.AEVT_REQUESTIPNUMBERADDRESS = _HttpRequest.GetClientIPAddress().StringIPToNumberIP();//獲得IP地址
TempEMailVerifyTable.AEVT_STATE = 1;//剛剛創(chuàng)建
TempEMailVerifyTable.AEVT_VERIFYCODE = VerifyCode;
TempEMailVerifyTable.AEVT_VERIFYTYPE = 1;//默認(rèn)類型為1
//插入數(shù)據(jù)庫
NewTableDataContexter.ams_email_verify_table.Add(TempEMailVerifyTable);
try
{
//保存
NewTableDataContexter.SaveChanges();
//下面就開啟一個多線程發(fā)送郵件,然后返回獲取成功,這里這樣寫不妥,但是為了用戶體驗(yàn),立即返回發(fā)送成功,就暫且相信阿里云的到達(dá)率吧
//下面在線程中發(fā)送郵件
Task TempTask;
TempTask = Task.Factory.StartNew(() =>
{
try
{
//下面繼續(xù)用阿里云郵件推送發(fā)送郵件
//先讀取郵件驗(yàn)證模板
String TaskVerifyCode = VerifyCode;
DWebMySQLDataContexter EMailTemplateDataContexter = CreateNewDataContexter();
String EMailTemplateUniqueIdentity = "NewRegisterVerify";
var EMailTemplateQuery = EMailTemplateDataContexter.ams_email_template_table.Where(e => e.AETT_UNIQUEIDENTITY == EMailTemplateUniqueIdentity).ToList();
if (EMailTemplateQuery.Count() > 0)
{
AliyunEMailDirectPushRequest MyRequest = new AliyunEMailDirectPushRequest();
//目標(biāo)地址
MyRequest.AimAddressList = new Dictionary<String, String>();
MyRequest.AimAddressList.Add(_Request.EMailAddress, "AlphaMS門戶注冊郵箱【" + _Request.EMailAddress + "】");
//來源地址
MyRequest.FromAddress = new KeyValuePair<String, String>("service@mail.alphams.cn", "AlphaMS門戶郵件服務(wù)");
//回復(fù)地址
MyRequest.ReplyAddressList = new Dictionary<String, String>();
MyRequest.ReplyAddressList.Add("kefu@alphams.cn", "AlphaMS門戶客服");
String EMailHTML = EMailTemplateQuery.FirstOrDefault().AETT_CONTENT;
EMailHTML = EMailHTML.Replace("##EMailAddress##", _Request.EMailAddress);
EMailHTML = EMailHTML.Replace("##VerifyCode##", TaskVerifyCode);
MyRequest.HTML = EMailHTML;
MyRequest.Subject = "AlphaMS門戶用戶注冊郵件驗(yàn)證";
MyRequest.Type = 2;//HTML方式發(fā)送郵件
MyRequest.SMTPUserName = "service@mail.alphams.cn";
MyRequest.SMTPPassword = "XXXXXX";
//下面發(fā)送
AliyunEMailDirectPushResponse TempAliyunEMailDirectPushResponse = AliyunControl.EMailDirectPush(MyRequest);
}
else
{
//模板不存在,也不報錯
}
}
catch (Exception)
{
//在線程中不報錯
}
});
MyResponse.SetResult(1, "發(fā)送成功");
return MyResponse;
}
catch (Exception NewTableSaveException)
{
return (DWebAccountCreateRegisterEMailVerifyResponse)SetExceptionError(MyResponse, NewTableSaveException, -5, "數(shù)據(jù)庫錯誤");
}
}
catch (Exception UpdateStateSaveException)
{
return (DWebAccountCreateRegisterEMailVerifyResponse)SetExceptionError(MyResponse, UpdateStateSaveException, -5, "數(shù)據(jù)庫錯誤");
}
}
}
}
7、驗(yàn)證碼驗(yàn)證邏輯的實(shí)現(xiàn)
主要代碼如下:
/// <summary>
/// 檢查注冊郵件驗(yàn)證碼
/// </summary>
/// <param name=""></param>
/// <returns></returns>
private DWebAccountCheckRegisterEMailVerifyCodeResponse CheckRegisterEMailVerifyCode(DWebAccountCheckRegisterEMailVerifyCodeRequest _Request, HttpRequestMessage _HttpRequest)
{
DWebAccountCheckRegisterEMailVerifyCodeResponse MyResponse = new DWebAccountCheckRegisterEMailVerifyCodeResponse();
//先檢查是否有驗(yàn)證記錄
DWebMySQLDataContexter CheckQueryDataContexter = CreateNewDataContexter();
DateTime NowDateTime = DateTime.Now;
var CheckQuery = CheckQueryDataContexter.ams_email_verify_table.Where(e => e.AEVT_EMAILADDRESS == _Request.EMailAddress && e.AEVT_STATE == 1 && e.AEVT_EXPIRETIME >= NowDateTime);
if (CheckQuery.Count() > 0)
{
String VerifyCode = CheckQuery.FirstOrDefault().AEVT_VERIFYCODE;
if (VerifyCode == _Request.VerifyCode)
{
//驗(yàn)證成功,設(shè)置這個驗(yàn)證失效
CheckQuery.FirstOrDefault().AEVT_STATE = -1;//設(shè)置失效
//所有的注冊會話先失效
DWebMySQLDataContexter UpdateClearDataContexter = CreateNewDataContexter();
var ClearQuery = UpdateClearDataContexter.ams_register_session_table.Where(e => e.ARST_EMAILADDRESS == _Request.EMailAddress);
foreach (var e in ClearQuery)
{
e.ARST_STATE = -1;//全部失效
}
//下面就要新建一個注冊會話
DWebMySQLDataContexter NewTableDataContexter = CreateNewDataContexter();
ams_register_session_table TempRegisterSessionTable = new ams_register_session_table();
TempRegisterSessionTable.ARST_ID = BLHelper.NewGuid();
CheckQuery.FirstOrDefault().AEVT_PARAMETER1 = TempRegisterSessionTable.ARST_ID;//和郵件驗(yàn)證建立起關(guān)聯(lián)
TempRegisterSessionTable.ARST_CREATETIME = NowDateTime;
TempRegisterSessionTable.ARST_CLIENTIPNUMBERADDRESS = _HttpRequest.GetClientIPAddress().StringIPToNumberIP();
TempRegisterSessionTable.ARST_EMAILADDRESS = _Request.EMailAddress;
TempRegisterSessionTable.ARST_EXPIRETIME = NowDateTime.AddMinutes(10);//這個會話的有效期是10分鐘
TempRegisterSessionTable.ARST_STATE = 1;//剛剛創(chuàng)建
NewTableDataContexter.ams_register_session_table.Add(TempRegisterSessionTable);
try
{
CheckQueryDataContexter.SaveChanges();
NewTableDataContexter.SaveChanges();
UpdateClearDataContexter.SaveChanges();
MyResponse.RegisterSessionID = TempRegisterSessionTable.ARST_ID;
MyResponse.SetResult(1, "驗(yàn)證成功");
return MyResponse;
}
catch (Exception DataSaveException)
{
return (DWebAccountCheckRegisterEMailVerifyCodeResponse)SetExceptionError(MyResponse, DataSaveException, -5, "數(shù)據(jù)庫錯誤");
}
}
else
{
MyResponse.SetResult(-2, "驗(yàn)證碼錯誤");
return MyResponse;
}
}
else
{
MyResponse.SetResult(-1, "已經(jīng)過期,請重新獲取驗(yàn)證碼!");
return MyResponse;
}
}
8、前端注冊頁面的實(shí)現(xiàn)
//頁面控制器
var PageControl = {
//注冊初始化
RegisterInit: function () {
PageControl.NewRegisterSessionID = "";//重新清空會話編號
PageControl.EMailVerifyInit();
},
//郵件驗(yàn)證初始化
EMailVerifyInit: function () {
clearInterval(PageControl.GetVerifyCodeTimeLeft);
$("#AR_Register_EMailVerify_Container").show();
$("#AR_Register_EMailVerify_EMailAddress_TextBox").val("");
$("#AR_Register_EMailVerify_EMailAddress_TextBox").removeAttr("readonly");
$("#AR_Register_EMailVerify_GetVerifyCode_Button").removeAttr("disabled");
$("#AR_Register_EMailVerify_GetVerifyCode_Button").val("獲取驗(yàn)證碼");
$("#AR_Register_EMailVerify_Verify_Container").hide();
$("#AR_Register_EMailVerify_Verify_Code_TextBox").val("");
$("#AR_Register_UserInfo_Container").hide();
},
//獲取驗(yàn)證碼時間結(jié)束
GetVerifyCodeTimeLeft: null,
//創(chuàng)建郵件驗(yàn)證
CreateEMailVerify: function () {
//先隱藏起來
$("#AR_Register_EMailVerify_Verify_Container").hide();
//檢查郵件地址輸入
if ($("#AR_Register_EMailVerify_EMailAddress_TextBox").val() == "") {
AlphaMS.JSToolkit.Dialog.MessageBox("請輸入郵件地址", function () {
$("#AR_Register_EMailVerify_EMailAddress_TextBox").focus();
});
return;
}
//檢查郵件地址輸入
if (!AlphaMS.JSToolkit.Valid.CheckMail($("#AR_Register_EMailVerify_EMailAddress_TextBox").val())) {
AlphaMS.JSToolkit.Dialog.MessageBox("請輸入正確的郵件地址", function () {
$("#AR_Register_EMailVerify_EMailAddress_TextBox").focus();
});
return;
}
//AlphaMS業(yè)務(wù)邏輯請求
AlphaMS.JSToolkit.NET.BLRequest({
Debug: false,
//業(yè)務(wù)邏輯方法路由名稱
FunctionRouteName: "AlphaMS.Portal.DWeb.Account.CreateRegisterEMailVerify",
//業(yè)務(wù)邏輯請求數(shù)據(jù)
BLRequestObject: {
//請求參數(shù)
//郵件地址
EMailAddress: $("#AR_Register_EMailVerify_EMailAddress_TextBox").val()
},
//SBS請求返回
BLResponse: {
//請求成功
Success: function (MyResponseObject) {
switch (MyResponseObject.ResultCode) {
case 1:
//注冊成功
AlphaMS.JSToolkit.Dialog.MessageBox("驗(yàn)證碼獲取成功,有效期5分鐘,請到郵箱中查收驗(yàn)證碼并填入下面框中", function () {
$("#AR_Register_EMailVerify_Verify_Code_TextBox").focus();
});
$("#AR_Register_EMailVerify_EMailAddress_TextBox").attr("readonly", "readonly");
$("#AR_Register_EMailVerify_GetVerifyCode_Button").attr("disabled", "disabled");
$("#AR_Register_EMailVerify_GetVerifyCode_Button").html("重新獲取(剩余60秒)");
var T = 60;//倒計時60秒
PageControl.GetVerifyCodeTimeLeft = setInterval(function () {
T = T - 1;
if (T == 0) {
//結(jié)束倒計時
clearInterval(PageControl.GetVerifyCodeTimeLeft);
$("#AR_Register_EMailVerify_EMailAddress_TextBox").removeAttr("readonly");
$("#AR_Register_EMailVerify_GetVerifyCode_Button").removeAttr("disabled");
$("#AR_Register_EMailVerify_GetVerifyCode_Button").html("獲取驗(yàn)證碼");
} else {
$("#AR_Register_EMailVerify_GetVerifyCode_Button").html("重新獲取(剩余" + T + "秒)");
}
}, 1000);
$("#AR_Register_EMailVerify_Verify_Container").show();
break;
case -1:
AlphaMS.JSToolkit.Dialog.MessageBox("郵件已經(jīng)被其他用戶使用,請換一個", function () {
$("#AR_Register_EMailVerify_EMailAddress_TextBox").focus();
});
break;
default:
AlphaMS.JSToolkit.Dialog.MessageBox(MyResponseObject.ResultMessage);
break;
}
}
}
}, ["Body"]);
},
//新注冊會話編號
NewRegisterSessionID: "",
//檢查郵件驗(yàn)證碼
CheckEMailVerifyCode: function () {
//檢查驗(yàn)證碼輸入
if ($("#AR_Register_EMailVerify_Verify_Code_TextBox").val() == "") {
AlphaMS.JSToolkit.Dialog.MessageBox("請輸入收到的驗(yàn)證碼", function () {
$("#AR_Register_EMailVerify_Verify_Code_TextBox").focus();
});
return;
}
//AlphaMS業(yè)務(wù)邏輯請求
AlphaMS.JSToolkit.NET.BLRequest({
Debug: false,
//業(yè)務(wù)邏輯方法路由名稱
FunctionRouteName: "AlphaMS.Portal.DWeb.Account.CheckRegisterEMailVerifyCode",
//業(yè)務(wù)邏輯請求數(shù)據(jù)
BLRequestObject: {
//請求參數(shù)
//郵件地址
EMailAddress: $("#AR_Register_EMailVerify_EMailAddress_TextBox").val(),
//驗(yàn)證碼
VerifyCode: $("#AR_Register_EMailVerify_Verify_Code_TextBox").val()
},
//SBS請求返回
BLResponse: {
//請求成功
Success: function (MyResponseObject) {
switch (MyResponseObject.ResultCode) {
case 1:
PageControl.NewRegisterSessionID = MyResponseObject.RegisterSessionID;
$("#AR_Register_EMailVerify_Container").hide();
$("#AR_Register_UserInfo_Container").show();
$("#AR_Register_EMail_TextBox").val($("#AR_Register_EMailVerify_EMailAddress_TextBox").val());
break;
case -1:
AlphaMS.JSToolkit.Dialog.MessageBox("驗(yàn)證碼過期,請重新獲取!", function () {
//初始化郵件驗(yàn)證
PageControl.EMailVerifyInit();
});
break;
case -2:
AlphaMS.JSToolkit.Dialog.MessageBox("驗(yàn)證碼錯誤,請重新輸入", function () {
$("#AR_Register_EMailVerify_Verify_Code_TextBox").focus();
});
break;
default:
AlphaMS.JSToolkit.Dialog.MessageBox(MyResponseObject.ResultMessage);
break;
}
}
}
}, ["Body"]);
},
//提交注冊
SubmitRegister: function () {
//檢查用戶名輸入
if ($("#AR_Register_UserName_TextBox").val() == "") {
AlphaMS.JSToolkit.Dialog.MessageBox("請輸入用戶名", function () {
$("#AR_Register_UserName_TextBox").focus();
});
return;
}
//檢查密碼輸入
if ($("#AR_Register_Password_TextBox").val() == "") {
AlphaMS.JSToolkit.Dialog.MessageBox("請輸入密碼", function () {
$("#AR_Register_Password_TextBox").focus();
});
return;
}
var PreRegisterString = "您的注冊信息如下:</br>";
PreRegisterString = PreRegisterString + "郵件地址:" + $("#AR_Register_EMailVerify_EMailAddress_TextBox").val() + "</br>";
PreRegisterString = PreRegisterString + "用戶名:" + $("#AR_Register_UserName_TextBox").val() + "</br>";
PreRegisterString = PreRegisterString + "密碼:" + $("#AR_Register_Password_TextBox").val() + "</br>";
PreRegisterString = PreRegisterString + "確認(rèn)注冊嗎?";
AlphaMS.JSToolkit.Dialog.MessageBox(PreRegisterString, function () {
//AlphaMS業(yè)務(wù)邏輯請求
AlphaMS.JSToolkit.NET.BLRequest({
Debug: false,
//業(yè)務(wù)邏輯方法路由名稱
FunctionRouteName: "AlphaMS.Portal.DWeb.Account.NewRegister",
//業(yè)務(wù)邏輯請求數(shù)據(jù)
BLRequestObject: {
//請求參數(shù)
//用戶名
UserName: $("#AR_Register_UserName_TextBox").val(),
//密碼
Password: $("#AR_Register_Password_TextBox").val(),
//注冊會話編號
RegisterSessionID: PageControl.NewRegisterSessionID
},
//SBS請求返回
BLResponse: {
//請求成功
Success: function (MyResponseObject) {
switch (MyResponseObject.ResultCode) {
case 1:
//注冊成功
AlphaMS.JSToolkit.Dialog.MessageBox("注冊成功,請前往登錄", function () {
AlphaMS.JSToolkit.Action.GoToPage("/Login");
});
break;
case -1:
AlphaMS.JSToolkit.Dialog.MessageBox("注冊已經(jīng)過期,請重新驗(yàn)證郵件地址!", function () {
PageControl.RegisterInit();
});
break;
case -2:
AlphaMS.JSToolkit.Dialog.MessageBox("郵件地址已經(jīng)存在!", function () {
PageControl.RegisterInit();
});
break;
case -3:
AlphaMS.JSToolkit.Dialog.MessageBox("用戶名已經(jīng)存在,請重新輸入!", function () {
$("#AR_Register_UserName_TextBox").focus();
});
break;
default:
AlphaMS.JSToolkit.Dialog.MessageBox(MyResponseObject.ResultMessage);
break;
}
}
}
}, ["Body"]);
}, function () { });
}
}
下面來看一下最終郵件驗(yàn)證的效果
輸入郵件地址
獲取驗(yàn)證碼
收到郵件
驗(yàn)證成功,繼續(xù)填寫用戶信息
注冊成功
四、總結(jié)與思考
就此,我們就使用阿里云郵件推送,完成了完整的郵件驗(yàn)證與推送體系的架設(shè)(主動推送、數(shù)據(jù)統(tǒng)計等沒有寫出來,但是在代碼里面有,有需要代碼的可以郵件向我索要),一句話總結(jié)就是如下:
我想,互聯(lián)網(wǎng)再怎么發(fā)展,QQ號可以沒有,微信也可能衰落,但郵件沒有的可能性很低,作為一種工作方式和服務(wù)方式,在可預(yù)見的未來內(nèi),郵件體系一定會伴隨著信息系統(tǒng)的發(fā)展而發(fā)展,而從技術(shù)的角度出發(fā),對郵件技術(shù)和服務(wù)的深入研究與思考,一定能夠帶來更加優(yōu)秀的軟件系統(tǒng)和應(yīng)用。因此,建議每一個互聯(lián)網(wǎng)創(chuàng)業(yè)者和應(yīng)用,都能夠重視對郵件數(shù)據(jù)的收集和處理,也在郵件服務(wù)上多花點(diǎn)精力和金錢,帶給用戶更好的體驗(yàn)。
作者:張柔,發(fā)布于 博客園 與 初碼博客
轉(zhuǎn)載請注明出處,歡迎郵件交流:zhangrou@printhelloworld.com,或者加QQ群:11444444
總結(jié)
以上是生活随笔為你收集整理的【初码干货】使用阿里云邮件推送服务架设自己邮件验证与推送体系的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: SAP Spartacus 服务器端渲染
- 下一篇: 2022延迟退休时间表女性,延迟退休对照