.NET SmtpClient Send 使用 Port 465 會發生 The operations timed out.

前言

最近測試 Mail Server 走 SSL 時,使用 Port  465 。
所以程式中寄 Mail 的部份調整成啟用 SSL , Port 改成 465 。
但程式一執行下去,就 Hang 一段時間,然後噴「The operations timed out」的錯誤。

研究

上網查了一下,蠻多人遇到這問題的,如果使用 SmtpClient 去送的話,就會 timeout 。
建議改成 587 ,我將它改成了 587 之後,果然就順利送出了。

var server = "yourmailserver";
string to = "s.fer@rm.com.tw";
string from = "rm@rm.com.tw";
var message = new MailMessage(from, to);
message.Subject = "Using the new SMTP client.";
message.Body = @"Using this new feature, you can send an email message from an application very easily.";
SmtpClient client = new SmtpClient(server);
// Credentials are necessary if the server requires the client
// to authenticate before it will send email on the client's behalf.
client.Credentials = new System.Net.NetworkCredential("youraccount", "yourpwd");
// client.Port = 465;
// 改成 587, 465 會噴 The operations timed out
client.Port = 587;
client.EnableSsl = true;
client.Send(message);

那為什麼走 465 不行呢?
似乎是因為 465 是走 Implicit SSL, 而 System.Net.Mail.SmtpClient 並不 Support 它(請參考:You cannot use System.Net.Mail.SmtpClient to send an e-mail message with Implicit SSL)。
但 587 一定需要給帳密,如果在 Domain 內要 Mailrelay 呢?
我們可以參考 How can I send emails through SSL SMTP with the .NET Framework? , 使用 Andrew Siemer 建議的方式,改用舊版的「System.Web.Mail」來寄送就可以了哦! 如下,

System.Web.Mail.MailMessage myMail = new System.Web.Mail.MailMessage();
myMail.Fields.Add
    ("http://schemas.microsoft.com/cdo/configuration/smtpserver",
                  "yourmailserver");
myMail.Fields.Add
    ("http://schemas.microsoft.com/cdo/configuration/smtpserverport",
                  "465");
myMail.Fields.Add
    ("http://schemas.microsoft.com/cdo/configuration/sendusing",
                  "2");
//sendusing: cdoSendUsingPort, value 2, for sending the message using
//the network.

//smtpauthenticate: Specifies the mechanism used when authenticating
//to an SMTP
//service over the network. Possible values are:
//- cdoAnonymous, value 0. Do not authenticate.
//- cdoBasic, value 1. Use basic clear-text authentication.
//When using this option you have to provide the user name and password
//through the sendusername and sendpassword fields.
//- cdoNTLM, value 2. The current process security context is used to
// authenticate with the service.
myMail.Fields.Add
("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate", "1");
//Use 0 for anonymous
myMail.Fields.Add
("http://schemas.microsoft.com/cdo/configuration/sendusername",
    "username");
myMail.Fields.Add
("http://schemas.microsoft.com/cdo/configuration/sendpassword",
      "userpwd");
myMail.Fields.Add
("http://schemas.microsoft.com/cdo/configuration/smtpusessl",
      "true");
myMail.From = "rm@rm.com.tw"
myMail.To = "s.fer@rm.com.tw";
myMail.Subject = "test sub";
myMail.BodyFormat = MailFormat.Html;
myMail.Body = "body";
System.Web.Mail.SmtpMail.SmtpServer = "yourmailserver:465";
System.Web.Mail.SmtpMail.Send(myMail);

結論

當 Mail 啟用 SSL 後,如果要寄送 Mail 時,您可以使用 Port 587 (要給帳密)。
如果要走 Port 465 ,則可以使用舊版的「System.Web.Mail」來寄送。
當然,您也可以選擇有 Support Implicit SSL 的 Mail 元件。

參考資料

You cannot use System.Net.Mail.SmtpClient to send an e-mail message with Implicit SSL
How to send e-mail programmatically by using System.Web.Mail in Visual C# 2005 or in Visual C# .NET
How can I send emails through SSL SMTP with the .NET Framework?
Which SMTP Port Should I Use? Understanding Ports 25, 465, & 587
Solving Timeout Problem When Sending Email via Yandex (C#)

作者: 亂馬客

亂馬客 @叡揚資訊 rainmaker_ho@gss.com.tw https://rainmakerho.github.io/ https://www.slideshare.net/rainmakerho

發表迴響