使用SmtpClient从服务结构actor发送电子邮件失败

时间:2016-12-14 19:37:11

标签: azure-service-fabric smtpclient

我正在尝试从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

2 个答案:

答案 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方法中的代码完美无缺,电子邮件安全可靠地传递。