16

在我的 MVC4 应用程序中,我使用通过 Gmail 的SMTP 服务器SmtpClient发送电子邮件。smtp.gmail.com

我已经使用以下设置配置了我的 Web.Config 文件:

<system.net>
 <mailSettings>
  <smtp deliveryMethod="Network">
   <network enableSsl="true" 
   defaultCredentials="false" 
   host="smtp.gmail.com" 
   port="587" 
   userName="xxMyUserNamexx@gmail.com" 
   password="xxMyPasswordxx" />
  </smtp>
 </mailSettings>
</system.net>

使用 SmtpClient 并发送电子邮件的方法如下所示:

public void SendMail(string fromDisplayName, string fromEmailAddress, string toEmailAddress, string subject, string body)
{
    MailAddress from = new MailAddress(fromEmailAddress, fromDisplayName);
    MailAddress to = new MailAddress(toEmailAddress);
    MailMessage mailMessage = new MailMessage(from, to);
    mailMessage.Body = body;
    mailMessage.Subject = subject;

    SmtpClient client = new SmtpClient();
    //client.UseDefaultCredentials = false;
    client.Send(mailMessage);
}

上面的代码按预期工作并且很好。让我感到困惑的是注释行client.UseDefaultCredentials = false;- 如果我取消注释该行,我将收到一条异常消息,指出:

SMTP 服务器需要安全连接或客户端未通过身份验证。服务器响应为:5.5.1 需要身份验证。

更重要的是,无论我将UseDefaultCredentials属性设置为trueor false,我仍然会收到异常消息。我避免异常消息的唯一方法是完全删除该行。

这种行为正常吗?您能解释一下为什么我会收到异常消息吗?

4

4 回答 4

26

那么,为什么我要明确地将属性设置为 false 会引发异常呢?

这样做的原因是,如果您将其设置为 false,则 setterUseDefaultCredentialsCredentials属性设置为 null,或者CredentialCache.DefaultNetworkCredentials如果设置为 true,则将其设置为属性。该DefaultNetworkCredentials属性由 MSDN 定义为

DefaultNetworkCredentials 返回的凭据表示应用程序正在运行的当前安全上下文的身份验证凭据。对于客户端应用程序,这些通常是运行应用程序的用户的 Windows 凭据(用户名、密码和域)。对于 ASP.NET 应用程序,默认网络凭据是登录用户或被模拟用户的用户凭据。

当您设置UseDefaultCredentials为 true 时,它​​正在使用您的 IIS 用户,并且我假设您的 IIS 用户没有与您使用的任何 SMTP 服务器的帐户相同的身份验证凭据。设置UseDefaultCredentials为 false null 会退出已设置的凭据。因此,无论哪种方式,您都会遇到该错误。

下面看一下UseDefaultCredentials使用dotPeek的设置器:

set
{
    if (this.InCall)
    {
        throw new InvalidOperationException(
            SR.GetString("SmtpInvalidOperationDuringSend"));
    }
    this.transport.Credentials = value 
        ? (ICredentialsByHost) CredentialCache.DefaultNetworkCredentials 
        : (ICredentialsByHost) null;
  }
于 2013-01-02T22:29:51.853 回答
16

我收到了同样的信息,这让我发疯了。阅读此线程后,我意识到顺序对设置我的凭据很重要。这有效:

client.UseDefaultCredentials = false;
client.Credentials = new NetworkCredential(smtpSettings.Username, smtpSettings.Password);

虽然这产生了您描述的错误:

client.Credentials = new NetworkCredential(smtpSettings.Username, smtpSettings.Password);
client.UseDefaultCredentials = false;

对于遇到同样问题的其他人,这只是一个仅供参考。

于 2013-03-01T17:10:04.053 回答
0

此选项将设置客户端使用当前登录用户的默认凭据

如果您将其设置为 true,那么它将尝试使用用户的凭据。如果您将其设置为 false,那么它将使用为客户端的 Credentials 属性显式设置的值,如果未显式设置它们,那么它将尝试匿名连接,如您所见。

于 2012-08-28T21:55:27.557 回答
0

这就是我们可以使用或不使用 NetworkCredentials 创建 SMTP 客户端的方式。我正在使用此代码发送电子邮件。仅当我们不传递凭据并默认进行时,我们才应该使用 client.UseDefaultCredentials。

        private SmtpClient InitializeSMTPClient()
        {
            var client = new SmtpClient(_smtpServer, _smtpPort);

            client.UseDefaultCredentials = _useSMTPDefaultCredentials;

            if (_useSMTPDefaultCredentials)
                return client;

            var credentials = new NetworkCredential(_smtpUsername, _smtpPassword);
            client.Credentials = credentials;

            return client;
        }



        SMTPEmailResult SendSMTPEmail(List<string> to_email, List<string> ccEmails, string subject, string message)
        {
            try
            {
                using (var client = InitializeSMTPClient())
                {
                    var mail_message = GetMailMessage(to_email, ccEmails, subject, message);
                    log.Debug("Sending SMTP email.");
                    client.Send(mail_message);
                    log.Debug("SMTP email sent successfully.");
                    return SMTPEmailResult.SendSuccess;
                }
            }
            catch (Exception ex)
            {
                log.Error(ex.Message, ex);
                return SMTPEmailResult.SendFailed;
            }
        }
于 2017-08-08T12:45:04.503 回答