=x= 🌵 CONTACT Page 寄信頁的後端寄信功能及其它注意事項。
📌 如同現實世界,如果要寄出一封信,你會需要郵局的服務,而當你要寄出 email 你就需要一個郵件伺服器來替你服務,會選擇 Google 提供的服務,是因為它簡單、安全且免費,而 SMTP (Simple Mail Transfer Protocol) 可以把它當成傳送 email 的一種共通規定,實際使用上只需要宣告你要用這種方式進行傳送即可,網路上已有相當多介紹寄信作法的文章,本文將簡單介紹實作時的過程,並在文末總結後端製作 CONTACT Page 時的其它注意事項。
👀 設定方式可參考 : 如何使用Google SMTP寄信(兩段式驗證+應用程式密碼)
🌵 產生的16碼應用程式密碼會在稍後用到。
🌵 如果帳戶有忘記密碼重新設定,16碼應用程式密碼會被清掉,需要再生成一次。
👺 原本在建立功能時並沒有啟用兩步驟驗證及設定應用程式密碼,只有依網路的教學在帳號的安全性設定裡,設定啟用"允許安全性較低的應用程式" (開啟兩步驟驗證後即失效)
,一開始都可以正常使用寄信功能,但不久後就出現錯誤,爬文並測試發現如果關閉防毒時寄信功能就正常,依網路建議設定兩步驟驗證及應用程式密碼後就可正常使用,而且無需開啟低安全性也不用關閉防毒。
(未設定應用程式密碼遇到的錯誤)
<head>
及 <body>
中的內容。<form>
標籤,保留新建時的 <form>
標籤,刪除來自 .html 內的 <form>
(複製原設定到保留的標籤內)<form runat="server" method="post" name="aspnetForm" id="aspnetForm">
action="contact.aspx"
需要拿掉,否則只會直接跳轉刷新頁面,無法進入送出信件的按鍵事件。<div>
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKLTM4NzgwOTUzNw8WAh4HQ2FwdGNoYQUEMzc5ORYCZg9kFgICAw9kFgICAQ9kFgYCBw8QDxYCHgtfIURhdGFCb3VuZGdkEBUIA1VTQQRBU0lBBkVVUk9QRQ1OT1JUSCBBTUVSSUNBD0NFTlRSQUwgQU1FUklDQQ1TT1VUSCBBTUVSSUNBBkFGUklDQQdPQ0VBTklBFQgDVVNBBEFTSUEGRVVST1BFDU5PUlRIIEFNRVJJQ0EPQ0VOVFJBTCBBTUVSSUNBDVNPVVRIIEFNRVJJQ0EGQUZSSUNBB09DRUFOSUEUKwMIZ2dnZ2dnZ2dkZAIJDxAPFgIfAWdkEBUHCVRheWFuYSAzNwlUYXlhbmEgNDYJVGF5YW5hIDQ4GlRheWFuYSA1NCAgIChOZXcgQnVpbGRpbmcpCVRheWFuYSA1OAlUYXlhbmEgNjQISVNBUkEgNTAVBwlUYXlhbmEgMzcJVGF5YW5hIDQ2CVRheWFuYSA0OBpUYXlhbmEgNTQgICAoTmV3IEJ1aWxkaW5nKQlUYXlhbmEgNTgJVGF5YW5hIDY0CElTQVJBIDUwFCsDB2dnZ2dnZ2dkZAINDxYCHgNzcmMFDkpwZWdJbWFnZS5hc2h4ZBgBBR5fX0NvbnRyb2xzUmVxdWlyZVBvc3RCYWNrS2V5X18WAQUmY3RsMDAkQ29udGVudFBsYWNlSG9sZGVyMSRJbWFnZUJ1dHRvbjG5FQQyUaUwxwcePcF6X9308WUP8w==" />
</div>
<div>
<input type="hidden" name="__VIEWSTATEGENERATOR" id="__VIEWSTATEGENERATOR" value="CD2448B2" />
<input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="/wEWFgKR7pRKAt6w6N0JArepvugGAuXBvr8EAo2X6PQHAvHN768EAsylpNwNArDts50HAu3a2roPApiq1MAIArWniMcJApDl3ucMAs7G2I0NAs/GtMoIAtnGtMoIAszJo6EGAtnGwO4BAs3GnJwHAvuDy+cMAu3CxJMMAp/KzpkCAr28ifwM0JmHZRHwnNWAdZdFwWYody60nD0=" />
</div>
<!--表單-->
<div class="from01">
<p>
Please Enter your contact information<span class="span01">*Required</span>
</p>
<br />
<table>
<tr>
<td class="from01td01">Name :</td>
<td><span>*</span><asp:TextBox runat="server" name="Name" type="text" ID="Name" class="{validate:{required:true, messages:{required:'Required'}}}" Style="width: 250px;" required="" aria-required="true" oninput="setCustomValidity('');" oninvalid="setCustomValidity('Required!')" MaxLength="50"></asp:TextBox>
</td>
</tr>
<tr>
<td class="from01td01">Email :</td>
<td><span>*</span><asp:TextBox runat="server" name="Email" type="text" ID="Email" class="{validate:{required:true, email:true, messages:{required:'Required', email:'Please check the E-mail format is correct'}}}" Style="width: 250px;" required="" aria-required="true" oninput="setCustomValidity('');" oninvalid="setCustomValidity('Required!')" MaxLength="50"></asp:TextBox>
</td>
</tr>
<tr>
<td class="from01td01">Phone :</td>
<td><span>*</span><asp:TextBox runat="server" name="Phone" type="text" ID="Phone" class="{validate:{required:true, messages:{required:'Required'}}}" Style="width: 250px;" required="" aria-required="true" oninput="setCustomValidity('');" oninvalid="setCustomValidity('Required!')" MaxLength="50"></asp:TextBox>
</td>
</tr>
<tr>
<td class="from01td01">Country :</td>
<td><span>*</span>
<asp:DropDownList name="Country" id="Country" runat="server" DataTextField="countrySort" DataValueField="countrySort" DataSourceID="SqlDataSource1"></asp:DropDownList>
<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$ ConnectionStrings:TayanaYachtConnectionString %>" SelectCommand="SELECT [countrySort] FROM [CountrySort]"></asp:SqlDataSource>
</td>
</tr>
<tr>
<td colspan="2"><span>*</span>Brochure of interest *Which Brochure would you like to view?</td>
</tr>
<tr>
<td class="from01td01"> </td>
<td>
<asp:DropDownList name="Yachts" id="Yachts" runat="server" DataTextField="type" DataValueField="type"></asp:DropDownList>
</td>
</tr>
<tr>
<td class="from01td01">Comments:</td>
<td>
<asp:TextBox runat="server" TextMode="MultiLine" name="Comments" Rows="2" cols="20" ID="Comments" Style="height: 150px; width: 330px;" MaxLength="500"></asp:TextBox>
</td>
</tr>
<tr>
<td class="from01td01"> </td>
<td class="f_right">
<!-- Render recaptcha API script -->
<cc1:RecaptchaApiScript ID="RecaptchaApiScript1" runat="server" />
<!-- Render recaptcha widget -->
<cc1:RecaptchaWidget ID="Recaptcha1" runat="server" />
<asp:Label ID="lblMessage" runat="server" Visible="False" ForeColor="Red"></asp:Label>
</td>
</tr>
<tr>
<td class="from01td01"> </td>
<td class="f_right">
<asp:ImageButton runat="server" type="image" name="ImageButton1" id="ImageButton1" src="images/buttom03.gif" style="border-width: 0px;" Height="25px" OnClick="ImageButton1_Click"/>
</td>
</tr>
</table>
</div>
<!--表單-->
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack) {
loadModelList();
}
}
private void loadModelList()
{
//1.連線資料庫
SqlConnection connection = new SqlConnection(WebConfigurationManager.ConnectionStrings["TayanaYachtConnectionString"].ConnectionString);
//2.sql語法
string sql = "SELECT * FROM Yachts";
//3.創建command物件
SqlCommand command = new SqlCommand(sql, connection);
//取得遊艇型號分類
connection.Open();
SqlDataReader readerType = command.ExecuteReader();
while (readerType.Read()) {
string typeStr = readerType["yachtModel"].ToString();
string isNewDesign = readerType["isNewDesign"].ToString();
string isNewBuilding = readerType["isNewBuilding"].ToString();
//加入遊艇型號下拉選單選項
ListItem listItem = new ListItem();
if (isNewDesign.Equals("True")) {
listItem.Text = $"{typeStr} (New Design)";
listItem.Value = $"{typeStr} (New Design)";
Yachts.Items.Add(listItem);
}
else if (isNewBuilding.Equals("True")) {
listItem.Text = $"{typeStr} (New Building)";
listItem.Value = $"{typeStr} (New Building)";
Yachts.Items.Add(listItem);
}
else {
listItem.Text = typeStr;
listItem.Value = typeStr;
Yachts.Items.Add(listItem);
}
}
connection.Close();
}
🌵 資料庫先簡易設定要取出的資料,介紹後台實作文章時會詳細說明。
👀 SqlDataReader 類別官方參考 : SqlDataReader 類別
👀 .Read() 方法官方參考 : SqlDataReader.Read 方法
<iframe>
的 src 位置。protected void ImageButton1_Click(object sender, ImageClickEventArgs e)
{
if (String.IsNullOrEmpty(Recaptcha1.Response)) {
lblMessage.Visible = true;
lblMessage.Text = "Captcha cannot be empty.";
}
else {
var result = Recaptcha1.Verify();
if (result.Success) {
//驗證成功則寄出信件並送出警告提醒
sendGmail();
Response.Write("<script>alert('Thank you for contacting us!');location.href='contact.aspx';</script>");
}
else {
lblMessage.Text = "Error(s): ";
foreach (var err in result.ErrorCodes) {
lblMessage.Text = lblMessage.Text + err;
}
}
}
}
👀 微軟內建的 System.Net.Mail.SmtpClient 不建議使用,官方說明 : SmtpClient 類別
👀 System.Net.Mail官網 說明 : System.Net.Mail 命名空間
using MailKit.Net.Smtp;
using MimeKit;
public void sendGmail()
{
//宣告使用 MimeMessage
var message = new MimeMessage();
//設定發信地址 ("發信人", "發信 email")
message.From.Add(new MailboxAddress("TayanaYacht", "XXXXXXX@gmail.com"));
//設定收信地址 ("收信人", "收信 email")
message.To.Add(new MailboxAddress(Name.Text.Trim(), Email.Text.Trim()));
//寄件副本email
message.Cc.Add(new MailboxAddress("收信人名稱", "XXXXXXX@gmail.com"));
//設定優先權
//message.Priority = MessagePriority.Normal;
//信件標題
message.Subject = "TayanaYacht Auto Email";
//建立 html 郵件格式
BodyBuilder bodyBuilder = new BodyBuilder();
bodyBuilder.HtmlBody =
"<h1>Thank you for contacting us!</h1>" +
$"<h3>Name : {Name.Text.Trim()}</h3>" +
$"<h3>Email : {Email.Text.Trim()}</h3>" +
$"<h3>Phone : {Phone.Text.Trim()}</h3>" +
$"<h3>Country : {Country.SelectedValue}</h3>" +
$"<h3>Type : {Yachts.SelectedValue}</h3>" +
$"<h3>Comments : </h3>" +
$"<p>{Comments.Text.Trim()}</p>";
//設定郵件內容
message.Body = bodyBuilder.ToMessageBody(); //轉成郵件內容格式
using (var client = new SmtpClient()) {
//有開防毒時需設定 false 關閉檢查
client.CheckCertificateRevocation = false;
//設定連線 gmail ("smtp Server", Port, SSL加密)
client.Connect("smtp.gmail.com", 587, false); // localhost 測試使用加密需先關閉
// Note: only needed if the SMTP server requires authentication
client.Authenticate("XXXXXXX@gmail.com", "16碼應用程式密碼");
//發信
client.Send(message);
//結束連線
client.Disconnect(true);
}
}
👺 如有用using System.Net.Mail
記得刪除,因為 MailKit 也有同名的 SmtpClient 。
👀 MailKit 說明 : GitHub - MailKit
👀 MimeKit 說明 : GitHub - MimeKit
📢 今天實作的下拉選單是自己取資料的作法,裡面的國家分類沒有要做特殊處理,其實可以用頁面設計精靈製作,在 HTML 頁面修改就可以達到相同效果,不用在後置程式碼自己寫,之後的文章會介紹如何使用精靈綁定資料庫資料。