intTypePromotion=1
zunia.vn Tuyển sinh 2024 dành cho Gen-Z zunia.vn zunia.vn
ADSENSE

Gửi email với SMTP

Chia sẻ: HA KIEN | Ngày: | Loại File: PDF | Số trang:23

258
lượt xem
84
download
 
  Download Vui lòng tải xuống để xem tài liệu đầy đủ

Mỗi lần học được điều mới sẽ cố gắng chia sẻ mọi người ^^ Hồi lâu nghiên cứu về cái SMTP cuối cùng cũng ngộ ra được 1 số thứ Giới thiệu qua chút về SMTP: SMTP là một giao thức dùng nền văn bản và tương đối đơn giản. Trước khi một thông điệp đư ợc gửi, người ta có thể định vị một hoặc nhiều địa chỉ nhận cho thông điệp những địa chỉ này thường được kiểm tra về sự tồn tại trung thực của chúng) ....

Chủ đề:
Lưu

Nội dung Text: Gửi email với SMTP

  1. Mỗi lần học được điều mới sẽ cố gắng chia sẻ mọi người ^^ Hồi lâu nghiên cứu về cái SMTP cuối cùng cũng ngộ ra được 1 số thứ Giới thiệu qua chút về SMTP: SMTP là một giao thức dùng nền văn bản và tương đối đơn giản. Trước khi một thông điệp đư ợc gửi, người ta có thể định vị một hoặc nhiều địa chỉ nhận cho thông điệp - những địa chỉ này thường được kiểm tra về sự tồn tại trung thực của chúng) . Việc kiểm t hử một trình chủ SMTP là một việc tương đối dễ dàng, dùng chương trình ứng dụng "telnet" (xem dưới đây). SMTP dùng cổng 25 của giao thức TCP. Để xác định trình chủ SMTP của một tên miền nào đấy (domain name), người ta dùng một mẫu tin MX (Mail eXchange - Trao đổi thư) của DNS (Domain Name System - Hệ thống tên miền). Các bạn nên đọc thêm tư liệu về SMTP Code: http://tools.ietf.org/html/rfc1123 http://vi.wikipedia.org/wiki/SMTP Một ví dụ truy nhập trực tiếp vào mail server bằng telnet qua port 25: Code: S: 220 www.example.com ESMTP Postfix C: HELO mydomain.com S: 250 Hello mydomain.com C: MAIL FROM: S: 250 Ok C: RCPT TO: S: 250 Ok C: DATA S: 354 End data with . C: Subject: test message C: From: sender@mydomain.com C: To: friend@example.com C: C: Hello, C: This is a test. C: Goodbye. C: . S: 250 Ok: queued as 12345 C: QUIT S: 221 Bye Trích từ wikipedia Tiếng Việt: http://vi.wikipedia.org/wiki/SMTP Mình có làm một cái video bên HCE về cái này Biên tập: thienthanit@yahoo.com Nguồn: Xcross87
  2. Code: http://hcegroup.net/hceteam/showthread.php?t=2497 OK ! Xem thử mô hình nha Biên tập: thienthanit@yahoo.com Nguồn: Xcross87
  3. Mô hình và cách thức như vậy ^^. Giờ ta tạo Class MySMTP để xử lý quy trình: Những thứ cần khởi tạo là gì? Dựa trên cái mô hình ở trên ta có những thứ sau private string Server; private string SenderName; private string SenderAddress; private string RCPName; private string RCPAddress; private string Subject; private string Body; private int TimeOut; private int Port; TcpClient SMTPTCPClient; NetworkStream SMTPNetworkStream; StreamReader SMTPStreamReader; StreamWriter SMTPStreamWriter; DateTime TimeOutCheck; Chú ý: + Để tạo một connection ta cần sử dụng: TcpClient + Để tạo một stream cho Network sử dụng NetworkStream + Xử lý NetworkStream qua 2 cái Base trước đó: StreamReader và StreamWriter. + DateTime: để quản lý connection , trường hợp bị TimeOut + Có các thành phần rồi giờ đơn giản thì ta tạo các Properties trước đi /* * PROPERTIES */ // Property: Server public string SMTPServer { get { return Server; } set { Server = value; } } // Property: SenderName public string SMTPSenderName { get { return SenderName; } set { SenderName = value; } } // Property: SenderAddress public string SMTPSenderAddress { get { return SenderAddress; } set { SenderAddress = value; } } // Property: RCPName public string SMTPRCPName { get { return RCPName; } Biên tập: thienthanit@yahoo.com Nguồn: Xcross87
  4. set { RCPName = value; } } // Property: RCPAddress public string SMTPRCPAddress { get { return RCPAddress; } set { RCPAddress = value; } } // Property: Subject public string SMTPSubject { get { return Subject; } set { Subject = value; } } // Property: Body public string SMTPBody { get { return Body; } set { Body = value; } } // Property: TimeOut public int SMTPTimeOut { get { return TimeOut; } set { TimeOut = value; } } // Property: Port public int SMTPPort { get { return Port; } set { Port = value; } } + Với xử lý việc gửi mail thì có thể chỉ cần sử dụng 1 phương thức: a. Gửi Email đi : OnSendEmail() là đủ Nhưng khi send Email ta cần kiểm tra connection time out vì thế phải xác nhận response từ server thì mới có thể request và biết nên đóng connection cho hợp lý. Vì vậy thêm 1 phương thức nữa xử lý TimeOut b. Xử lý Connection TimeOut: WaitForResponse() + Xử lý gửi thông điệp đi thực sự rất đơn giản và không phức tạp. Dựa vào mô hình ở trên ta thấy vòng lặp quá trình xử lý được làm như sau: 1. Khởi tạo kết nối, thất bại thì đóng 2. Khởi tạo thành công, thu nhận thông điệp vào các stream 3. Chào server, code = 220; đóng nếu thật bại 4. Xử lý sender address: đóng nếu thất bại . code =250 5. Xử lý người nhận : đóng nếu thất bại. code = 250 6. Xử lý data: Thông tin Data của thông điệp gửi đi có 2 phần chính: -- Header Info -- From: To: Subject: -- Message Info -- Body: Biên tập: thienthanit@yahoo.com Nguồn: Xcross87
  5. Ngoài ra còn một số thông tin khác bổ sung cho Header như DateTime, Reply-To.... 7. Gửi thông điệp , đóng nếu thất bại. Code = 354 8. Kiểm tra thông điệp nếu được gửi thành công: code = 250. Đóng nếu thất bại Chú ý: việc xử lý các bước đều thông qua viẹc xử lý connection time out. Vì xử lý thông điệp tới server có 2 kết quả, thành công hoặc thất bại nên 2 phương thức t a viết ở sử dụng kiểu Boolean (bool) Từ bản nháp giấy trên ta tiến hành vào code thực dụng cho 2 phương thức: + public void OnSendEmail() + private void WaitForResponse(string Code) ( sử dụng private vì public thì ai dùng , có mỗi thằng OnSendEmail nó xài. Thêm vào đó Response code thì dùng kiểu String chứ không dùng Int vì tránh phải convert khi kiểm tra và so sánh từ stream. Thông điệp từ stream luôn là kiểu String). Đây là Class được xây dựng hoàn chỉnh: using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Net.Sockets; using System.Text; namespace Network { public class MySMTP { // Mail Properties private string Server; private string SenderName; private string SenderAddress; private string RCPName; private string RCPAddress; private string Subject; private string Body; private int TimeOut; private int Port; // Network Connector Properties TcpClient SMTPTCPClient; NetworkStream SMTPNetworkStream; StreamReader SMTPStreamReader; StreamWriter SMTPStreamWriter; DateTime TimeOutCheck; // Constructor public MySMTP() { TimeOut = 60; // Set Connection Time Out around 1 minute Port = 25; // which is accessed through Telnet } /* Biên tập: thienthanit@yahoo.com Nguồn: Xcross87
  6. * PROPERTIES */ // Property: Server public string SMTPServer { get { return Server; } set { Server = value; } } // Property: SenderName public string SMTPSenderName { get { return SenderName; } set { SenderName = value; } } // Property: SenderAddress public string SMTPSenderAddress { get { return SenderAddress; } set { SenderAddress = value; } } // Property: RCPName public string SMTPRCPName { get { return RCPName; } set { RCPName = value; } } // Property: RCPAddress public string SMTPRCPAddress { get { return RCPAddress; } set { RCPAddress = value; } } // Property: Subject public string SMTPSubject { get { return Subject; } set { Subject = value; } } // Property: Body public string SMTPBody { get { return Body; } set { Body = value; } } // Property: TimeOut public int SMTPTimeOut { get { return TimeOut; } set { TimeOut = value; } } // Property: Port public int SMTPPort { get { return Port; } set { Port = value; } } Biên tập: thienthanit@yahoo.com Nguồn: Xcross87
  7. /* * METHOD */ // Send message through telnet connection public bool OnSendEmail() { // Initialization SMTPTCPClient = new TcpClient(); // Set up the connection try { SMTPTCPClient.Connect(Server, Port); } catch (Exception ex) { // if fail to connect to mail server Console.WriteLine("Error: " + ex.Message); return false; } // If succeed creating the connection // init all the streams SMTPNetworkStream = SMTPTCPClient.GetStream(); SMTPStreamReader = new StreamReader(SMTPNetworkStream); SMTPStreamWriter = new StreamWriter(SMTPNetworkStream); // Need for server's response if (WaitForResponse("220")) { // Greet mail server SMTPStreamWriter.WriteLine("HELO: " + Server); // Clear the rest/garbage SMTPStreamWriter.Flush(); } else // if no response from server { // connection fails SMTPTCPClient.Close(); return false; } // The next response for input sender address if (WaitForResponse("250")) { // write down the sender address SMTPStreamWriter.WriteLine("Mail From:" + SenderAddress); SMTPStreamWriter.Flush(); } else { // connection close otherwise SMTPTCPClient.Close(); return false; } // Response for input RCP Address if (WaitForResponse("250")) Biên tập: thienthanit@yahoo.com Nguồn: Xcross87
  8. { // write down the RCP address SMTPStreamWriter.WriteLine("RCPT TO:" + RCPAddress); SMTPStreamWriter.Flush(); } else { // close the connection otherwise SMTPTCPClient.Close(); return false; } // Response for data / body if (WaitForResponse("250")) { // request data SMTPStreamWriter.WriteLine("Data"); SMTPStreamWriter.Flush(); } else { // close connection otherwise SMTPTCPClient.Close(); return false; } // Send the message if (WaitForResponse("354")) { // Get all message // NOTE: Each section should be ended up with a newline seperately string szData = ""; szData = "From:" + SenderName + Environment.NewLine; szData += "To:" + RCPName + Environment.NewLine; szData += "Subject:" + Subject + Environment.NewLine; szData += Body + Environment.NewLine + "." + Environment.NewLine; // Send the message to network stream through stream writer SMTPStreamWriter.Write(szData); // clear the rest SMTPStreamWriter.Flush(); } else { // close the connection if fails SMTPTCPClient.Close(); return false; } // Wait for the last success if (WaitForResponse("250")) { // close the connection safely SMTPTCPClient.Close(); return true; } else Biên tập: thienthanit@yahoo.com Nguồn: Xcross87
  9. { // close the connection otherwise SMTPTCPClient.Close(); return false; } } // WaitForResponse method manipulates the connection response. private bool WaitForResponse(string Code) { // Get the time at connecting moment TimeOutCheck = DateTime.Now; // Span the timer TimeSpan TimeSpanner = DateTime.Now - TimeOutCheck; // Loop until timeout exceeds while (TimeSpanner.Seconds < TimeOut) { if (SMTPNetworkStream.DataAvailable) { // If catch the incoming data, get it by lines string DataIn = SMTPStreamReader.ReadLine(); // Check for the sufficient response code if (DataIn.Substring(0, Code.Length).Equals(Code)) return true; } // Recalculate timeout TimeSpanner = DateTime.Now - TimeOutCheck; } // Return false if it fails return false; } } public class Network { public static void Main() { // Create a SMTP Object MySMTP smtp = new MySMTP(); smtp.SMTPServer = "gsmtp163.google.com"; smtp.SMTPPort = 25; smtp.SMTPTimeOut = 60; smtp.SMTPSenderName = "Pete Houston"; smtp.SMTPSenderAddress = "xcross87@gmail.com"; smtp.SMTPRCPName = "Pete Houston"; smtp.SMTPRCPAddress = "pete.houston.17187@gmail.com"; smtp.SMTPSubject = "Testing for SMTP Class"; smtp.SMTPBody = "Hello Pete ! Message Sent Successfully !"; Console.WriteLine("Sending ... \n"); // Try to send email if (smtp.OnSendEmail()) { Console.WriteLine("OK !"); } else { Biên tập: thienthanit@yahoo.com Nguồn: Xcross87
  10. Console.WriteLine("Failed !"); } } } } // Ghi chú: có tham khảo và chỉnh sửa từ c-sharpcorner.com Tuy nhiên .NET Framework đã có library hỗ trợ xử lý với các Mail Server thông qua Code: using System.Net.Mail; public class SmtpClient; Để sử dụng ta đơn thuần tạo một Email Object từ class MailMessage trong cùng namespace System.Net.Mail; xử lý 4 properties chính của một Email Message: Code: From To Subject Body Một ví dụ send email qua SMTP như sau using System; using System.Net; using System.Net.Mail; class EmailWithSMTP { // the EP public static void Main() { // server info string szServer = "Dien server vao day"; int iPort = 25; // set up a connection SmtpClient client = new SmtpClient(szServer,iPort); // If you access to a account on mail server to send email // use this: // client.Credentials = new NetworkCredential("user@addr.com","password"); // create message using (MailMessage message = new MailMessage()) { // make up message message.From = new MailAddress("sender@somewhere.com"); message.To.Add("receiver@someplace.com"); Biên tập: thienthanit@yahoo.com Nguồn: Xcross87
  11. message.Subject = "Testing email "; message.Body = "Send successfully !"; // send message client.Send(message); } } } Khi check lại phần code ở trên khi truyền tải socket mình kiểm tra kết nối tới server chờ response, tuy nhiên rất hao tổn tài nguyên và chạy rất là rì rì. Mình sẽ viết lại theo hướng mới tuy nhiên cũng không có sự khác biệt nhiều lắm. 1. Thử viết 1 class nho nhỏ xử lý việc gửi email trên Gmail Server 2. Tạo thêm 1 class để catch Exception. 3. Tạo danh sách CC,BCC để có thể gửi tới nhiều địa chỉ. OK ! Cùng đi vào làm việc nhé I. Đầu tiên cần xem xét một chút về Gmail Server đã. Mở Command Prompt ra (cmd.exe) rồi gõ nslookup set type=mx gmail.com Kết quả sẽ được tạm như thế này C:UsersXcross87>nslookup Default Server: *****.*******.*** Address: ***.***.**.**:** > set type=mx > gmail.com Server: *****.*******.*** Address: ***.***.**.**:** Non-authoritative answer: gmail.com MX preference = 10, mail exchanger = alt1.gmail-smtp-in.l.google .com gmail.com MX preference = 10, mail exchanger = alt2.gmail-smtp-in.l.google .com gmail.com MX preference = 50, mail exchanger = gsmtp163.google.com gmail.com MX preference = 50, mail exchanger = gsmtp183.google.com gmail.com MX preference = 5, mail exchanger = gmail-smtp-in.l.google.com gmail.com nameserver = ns4.google.com gmail.com nameserver = ns1.google.com gmail.com nameserver = ns2.google.com gmail.com nameserver = ns3.google.com gsmtp163.google.com internet address = 64.233.163.27 gsmtp183.google.com internet address = 64.233.183.27 > exit Biên tập: thienthanit@yahoo.com Nguồn: Xcross87
  12. C:UsersXcross87> như vậy là có thể thấy Gmail sử dụng các Email Exchange Server để lưu trữ và gửi mail đi. Tại sao lại sử dụng nhiều server mail như thế? Đơn giản là trong quá trình gửi mail đi nếu có trục trặc bị lỗi ở server này không gửi đi được thì mail sẽ được chuyển tới server khác để gửi. Ta sẽ chọn cái server có MX Preferences cao nhất để sử dụng vào code. II. Thử thí nghiệm 1 server bằng telnet xem server có làm việc hay không Đầu tiên ta chọn 1 server sau đó telnet telnet gsmtp163.google.com 25 và sẽ truy nhập được vào server và ta thử send 1 mail tới 1 Gmail account từ server này theo quy trình dưới đây. 220 mx.google.com ESMTP f7si3180292nfh.26 EHLO 250-mx.google.com at your service, [203.252.117.19] 250-SIZE 28311552 250-8BITMIME 250 ENHANCEDSTATUSCODES MAIL FROM: 250 2.1.0 OK RCPT TO: 250 2.1.5 OK DATA 354 Go ahead Subject: Testing Gmail From: Xcross87 To: Pete Houston Content-Type: text/plain Message: This is the message tesing from Mr.Pete Best Regards, . 250 2.0.0 OK 1201262899 f7si3180292nfh.26 QUIT 221 2.0.0 mx.google.com closing connection f7si3180292nfh.26 Connection to host lost. sau đó check email pete.houston.17187@gmail.com sẽ thấy một mail mới nhận. Các bạn thử thực hành quy trình trên bằng tay xem. Trong quá trình send email đi ta chia nhỏ ra một chút. Ta sẽ chia ra phần gửi thông điệp tới server và sẽ kiểm tra response, nếu k hông hợp lệ thì sẽ throw vào lớp exception. Lý thuyết là thế, giờ bắt tay vào xây dựng cho hợp lý Biên tập: thienthanit@yahoo.com Nguồn: Xcross87
  13. đầu tiên với exception, đơn giản chỉ cần xem server response là được public class SmtpException : System.Exception { private string message; public SmtpException(string str) { message = str; } public string What() { return message; } } Ta tạo một namespace Gmail và tạo các class bên trong. using System; using System.Collections; using System.Net.Sockets; using System.Net.Mail; using System.Text; namespace Gmail { public class Smtp : TcpClient public class SmtpException : Exception } Việc tiếp theo là thiết kế class Smtp Ta cài đặt với các properties như sau : private string _server = null; private int _port = 0; private string _from = null; private ArrayList _to; private ArrayList _cc; private ArrayList _bcc; private string _subject = null; private string _bodyHtml = null; private string _bodyText = null; /// /// Constructor /// public Smtp() { // Init server connection info _server = "gsmtp163.google.com"; _port = 25; Biên tập: thienthanit@yahoo.com Nguồn: Xcross87
  14. // Init ArrayList _to = new ArrayList(); _cc = new ArrayList(); _bcc = new ArrayList(); } /// /// Properties /// public string Server { get { return _server; } set { _server = value; } } public int Port { get { return _port; } set { _port = value; } } public string From { get { return _from; } set { _from = value; } } public ArrayList To { get { return _to; } set { _to = value; } } public ArrayList CC { get { return _cc; } set { _cc = value; } } public ArrayList BCC { get { return _bcc; } set { _bcc = value; } } public string Subject { get { return _subject; } set { _subject = value; } } public string BodyText { get { return _bodyText; } Biên tập: thienthanit@yahoo.com Nguồn: Xcross87
  15. set { _bodyText = value; } } public string BodyHTML { get { return _bodyHtml; } set { _bodyHtml = value; } } Ta viết lại các method cho hoàn chỉnh #region { METHODS } /// /// Methods /// // Write public void Write(string message) { ASCIIEncoding en = new ASCIIEncoding(); byte[] WriteBuffer = new byte[1024]; WriteBuffer = en.GetBytes(message); NetworkStream stream = GetStream(); stream.Write(WriteBuffer, 0, WriteBuffer.Length); } // Response public string Response() { ASCIIEncoding enc = new ASCIIEncoding(); byte[] serverbuff = new Byte[1024]; NetworkStream stream = GetStream(); int count = stream.Read(serverbuff, 0, 1024); if (count == 0) return ""; return enc.GetString(serverbuff, 0, count); } // Send public void Send() { string message; string response; /* * 1. Set up a connection to server and wait for welcome response * Code = 220 */ Connect(server, 25); response = Response(); if (response.Substring(0, 3) != "220") { throw new SmtpException(response); }; Biên tập: thienthanit@yahoo.com Nguồn: Xcross87
  16. /* * 2. Say greeting to server and wait for input * Code = 250 */ message = "HELO me\r\n"; Write(message); response = Response(); if (response.Substring(0, 3) != "250") { throw new SmtpException(response); } /* * 3. Input sender address, just any * Code = 250 */ message = "MAIL FROM:\r\n"; Write(message); response = Response(); if (response.Substring(0, 3) != "250") { throw new SmtpException(response); } /* * 4. Input list of receivers * Code = 250 */ foreach (string address in _to) { try { message = "RCPT TO:\r\n"; Write(message); response = Response(); if (response.Substring(0, 3) != "250") { throw new SmtpException(response); } } catch (SmtpException e) { System.Console.WriteLine("{0}", e.What()); } } /* * 5. Input list of cc * Code = 250 */ foreach (string address in _cc) { try { message = "RCPT TO:\r\n"; Write(message); response = Response(); Biên tập: thienthanit@yahoo.com Nguồn: Xcross87
  17. if (response.Substring(0, 3) != "250") { throw new SmtpException(response); } } catch (SmtpException e) { System.Console.WriteLine("{ 0}", e.What()); } } /* * 6. Input list of bcc * Code = 250 việc cuôi cùng là test lại class cho hoàn chỉnh đây là bộ class hoàn chỉnh Smtp cho Gmail có cả 1 class con để test luôn using System; using System.Collections; using System.Collections.Generic; using System.Net.Sockets; using System.Net.Mail; using System.Text; namespace Gmail { public class Smtp : TcpClient { #region { VARIABLES LIST } private string _server = null; private int _port = 0; private string _from = ""; private ArrayList _to; private ArrayList _cc; private ArrayList _bcc; private string _subject = ""; private string _bodyHtml = ""; private string _bodyText = ""; #endregion #region { CONSTRUCTOR } /// /// Constructor /// public Smtp() { // Init server connection info _server = "gsmtp163.google.com"; _port = 25; Biên tập: thienthanit@yahoo.com Nguồn: Xcross87
  18. // Init ArrayList _to = new ArrayList(); _cc = new ArrayList(); _bcc = new ArrayList(); } #endregion #region { PROPERTIES } /// /// Properties /// public string Server { get { return _server; } set { _server = value; } } public int Port { get { return _port; } set { _port = value; } } public string From { get { return _from; } set { _from = value; } } public ArrayList To { get { return _to; } set { _to = value; } } public ArrayList CC { get { return _cc; } set { _cc = value; } } public ArrayList BCC { get { return _bcc; } set { _bcc = value; } } public string Subject { get { return _subject; } set { _subject = value; } } public string BodyText { get { return _bodyText; } set { _bodyText = value; } } public string BodyHTML { get { return _bodyHtml; } set { _bodyHtml = value; } } Biên tập: thienthanit@yahoo.com Nguồn: Xcross87
  19. #endregion #region { METHODS } /// /// Methods /// // Write public void Write(string message) { ASCIIEncoding en = new ASCIIEncoding(); byte[] WriteBuffer = new byte[1024]; WriteBuffer = en.GetBytes(message); NetworkStream stream = GetStream(); stream.Write(WriteBuffer, 0, WriteBuffer.Length); } // Response public string Response() { ASCIIEncoding enc = new ASCIIEncoding(); byte[] serverbuff = new Byte[1024]; NetworkStream stream = GetStream(); int count = stream.Read(serverbuff, 0, 1024); if (count == 0) return ""; return enc.GetString(serverbuff, 0, count); } // Send public void Send() { string message = ""; string response; /* * 1. Set up a connection to server and wait for welcome response * Code = 220 */ Connect(_server, _port); response = Response(); if (response.Substring(0, 3) != "220") { throw new SmtpException(response); }; /* * 2. Say greeting to server and wait for input * Code = 250 */ message = "HELO me\r\n"; Write(message); response = Response(); if (response.Substring(0, 3) != "250") Biên tập: thienthanit@yahoo.com Nguồn: Xcross87
  20. { throw new SmtpException(response); } /* * 3. Input sender address, just any * Code = 250 */ message = "MAIL FROM:\r\n"; Write(message); response = Response(); if (response.Substring(0, 3) != "250") { throw new SmtpException(response); } /* * 4. Input list of receivers * Code = 250 */ foreach (string address in _to) { try { message = "RCPT TO:\r\n"; Write(message); response = Response(); if (response.Substring(0, 3) != "250") { throw new SmtpException(response); } } catch (SmtpException e) { System.Console.WriteLine("{0}", e.What()); } } /* * 5. Input list of cc * Code = 250 */ foreach (string address in _cc) { try { message = "RCPT TO:\r\n"; Write(message); response = Response(); if (response.Substring(0, 3) != "250") { throw new SmtpException(response); } } catch (SmtpException e) { System.Console.WriteLine("{ 0}", e.What()); Biên tập: thienthanit@yahoo.com Nguồn: Xcross87
ADSENSE

CÓ THỂ BẠN MUỐN DOWNLOAD

 

Đồng bộ tài khoản
2=>2