我正在尝试从Service Fabric actor方法发送电子邮件。代码非常简单,在控制台应用程序中没有问题,但是actor方法中的相同代码会生成异常:
"根据验证程序"
我不知道为什么会这样,我应该添加到我的代码中以使其工作(我不想绕过证书验证或禁用加密),所以我在这个论坛上寻求帮助。
谢谢
这是我的代码(只是用虚拟名称替换了凭据和域名)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Mail;
using System.Text;
using System.Threading.Tasks;
namespace testsmtp {
class Program {
static void Main(string[] args) {
SendEmailAlert("myuserid", "mypassword", "recipient@mydomain.com", "test subject", "test body");
}
private static bool SendEmailAlert(string uid, string pwd, string recipient_list, string subject, string body) {
MailMessage msg = new MailMessage();
msg.To.Add(recipient_list);
msg.From = new MailAddress("sender@mydomain.com");
msg.Subject = subject;
msg.Body = body;
msg.IsBodyHtml = false;
SmtpClient client = new SmtpClient();
client.Host = "smtp.mydomain.com";
client.Port = 587;
client.EnableSsl = true;
client.UseDefaultCredentials = false;
client.Credentials = new NetworkCredential(uid, pwd);
try {
client.Send(msg);
return true;
}
catch (Exception e) {
string emsg = e.Source + "\n" + e.Message;
return false;
}
}
}
}
这是异常数据
Message "The remote certificate is invalid according to the validation procedure." string
StackTrace " at System.Net.Security.SslState.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, Exception exception)\r\n at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)\r\n at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)\r\n at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)\r\n at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)\r\n at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)\r\n at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)\r\n at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)\r\n at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)\r\n at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)\r\n at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)\r\n at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)\r\n at System.Net.Security.SslState.StartReceiveBlob(Byte[] buffer, AsyncProtocolRequest asyncRequest)\r\n at System.Net.Security.SslState.ForceAuthentication(Boolean receiveFirst, Byte[] buffer, AsyncProtocolRequest asyncRequest)\r\n at System.Net.Security.SslState.ProcessAuthentication(LazyAsyncResult lazyResult)\r\n at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)\r\n at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)\r\n at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)\r\n at System.Net.TlsStream.ProcessAuthentication(LazyAsyncResult result)\r\n at System.Net.TlsStream.Write(Byte[] buffer, Int32 offset, Int32 size)\r\n at System.Net.Mail.SmtpConnection.Flush()\r\n at System.Net.Mail.ReadLinesCommand.Send(SmtpConnection conn)\r\n at System.Net.Mail.EHelloCommand.Send(SmtpConnection conn, String domain)\r\n at System.Net.Mail.SmtpConnection.GetConnection(ServicePoint servicePoint)\r\n at System.Net.Mail.SmtpClient.GetConnection()\r\n at System.Net.Mail.SmtpClient.Send(MailMessage message)\r\n at UserActor.UserActor.DeliverFeedbackMessage(String cur_msg, String remote_ip, String usr_agent) in C:\\testsrc\\DigitalRadar\\UserActor\\UserActor.cs:line 621" string
答案 0 :(得分:0)
您正在使用SSL连接到邮件服务器(smtp.mydomain.com)。检查邮件服务器上的证书是否具有有效(CA签名)证书。也许它是自签名的,或过期的,或者有一个弱的密码。
答案 1 :(得分:0)
好吧,我发现了一个很好的解决方法(不会影响安全性)以避免这个问题,我正在回答我自己的问题,以帮助任何可能遇到同样问题并最终在这里的人。
我应该提到我的SF版本是5.0.217,演员版本是2.0.217,也许更新版本。可能没有问题,因为SF团队正在不断改进框架。当我有一些时间我将检查新版本并更新此帖子以防万一。
回过头来看,当从SF actor方法中调用SmtpClient.Send时,默认的证书验证似乎失败了。从C#控制台应用程序进行的同一调用很有效。原因是我的理解,也许是一些SF故障,无论如何.NET允许编写和注册自定义验证程序来替换默认程序,使用这种方法我解决了问题,但重要的是不要盲目地说& #34;有效"对于任何证书,正如我在SO的许多上述帖子中所建议的那样,我建议实际检查证书以确定它是否良好,否则你搞砸了安全性,那么就没有必要使用SSL或证书了所有。说完这里是我的验证码(根据你自己的情况调整)
private bool MyValidateSmtpServerCertificate(object sender, X509Certificate certificate,
X509Chain chain, SslPolicyErrors sslPolicyErrors) {
if (sslPolicyErrors != SslPolicyErrors.None)
return false;
string[] subj_params = certificate.Subject.Split(',');
string common_name = string.Empty;
foreach (string param in subj_params) {
string[] sub_params = param.Split('=');
if (sub_params[0].Trim() == "CN")
common_name = sub_params[1].Trim();
}
string[] valid_names = {
common_const.smtpServer,
"*." + common_const.smtpServer,
};
if (!valid_names.Contains(common_name))
return false;
return true;
}
在使用以下行调用SmtpClient.Send之前注册此函数:
ServicePointManager.ServerCertificateValidationCallback = MyValidateSmtpServerCertificate;
总而言之,现在我在actor方法中的代码完美无缺,电子邮件安全可靠地传递。