【问题标题】:Sending mail using MailKit with Gmail OAuth使用带有 Gmail OAuth 的 MailKit 发送邮件
【发布时间】:2018-12-07 10:49:22
【问题描述】:

我正在尝试创建一个应用程序,该应用程序将在客户购买时向他们发送电子邮件。我们有自己的 GMail 帐户,我将使用它来发送电子邮件。

我已经在 Google API 控制台中设置了我的应用程序并创建了凭据。我在 MailKit 的 GitHub 上找到了this question,这看起来是一种很简单的方法,但它似乎对我不起作用。

这是我的代码:

var secrets = new ClientSecrets
{
    ClientId = [CLIENTID]
    ClientSecret = [SECRET]
};

var googleCredentials = await GoogleWebAuthorizationBroker.AuthorizeAsync(secrets, new[] { GmailService.Scope.MailGoogleCom }, email, CancellationToken.None);
await googleCredentials.RefreshTokenAsync(CancellationToken.None);

using (var client = new SmtpClient())
{
    client.Connect("smtp.gmail.com", 587);

    var credentials = new NetworkCredential(googleCredentials.UserId, googleCredentials.Token.AccessToken);
    client.Authenticate(credentials);

    await client.SendAsync(message);
    client.Disconnect(true);
}

Authenticate 的调用会出现以下错误:

MailKit.Security.AuthenticationException : AuthenticationInvalidCredentials:5.7.8 用户名和密码不是 公认。了解更多信息 5.7.8https://support.google.com/mail/?p=BadCredentialsm3-v6sm3447324wrs.39-gsmtp

例外中的 Google 支持页面基本上只是说要么使用两步验证 + 应用密码,要么启用不太安全的应用。这两个我都不想要。为什么在 .NET 中做到这一点如此困难?我以前用 node 做过这个,非常简单:

var smtp = mailer.createTransport({
    service: "Gmail",
    auth: {
        type: "OAuth2",
        user: process.env.EMAIL,
        clientId: process.env.CLIENT_ID,
        clientSecret: process.env.CLIENT_SECRET,
        refreshToken: process.env.REFRESH_TOKEN
    }
});

请注意,我已经看过this answer,但我真的不明白如何获得 Google 信任的 X509 证书。据我所知,Google 的文档中没有任何与此相关的内容。

【问题讨论】:

    标签: c# email asp.net-core oauth-2.0 google-oauth


    【解决方案1】:

    通过刷新令牌在 Gmail Mailkit 中发送电子邮件

        // https://console.developers.google.com
    var secrets = new ClientSecrets
    {
        ClientId = "",
        ClientSecret = ""
    };
    // Generating a refresh token - https://www.youtube.com/watch?v=hfWe1gPCnzc
    var token = new TokenResponse { RefreshToken = "YourRefreshToken" };
    var googleCredentials = new UserCredential(new GoogleAuthorizationCodeFlow(
        new GoogleAuthorizationCodeFlow.Initializer
        {
            ClientSecrets = secrets
        }), username, token);
    
    emailClient.Connect("smtp.gmail.com", 587, SecureSocketOptions.StartTls);   
    await googleCredentials.GetAccessTokenForRequestAsync();
    var oauth2 = new SaslMechanismOAuth2(googleCredentials.UserId, googleCredentials.Token.AccessToken);
    emailClient.Authenticate(oauth2);
    
    await emailClient.SendAsync(message); // MimeMessage
    emailClient.Disconnect(true);
    

    【讨论】:

      【解决方案2】:

      解决方案是使用SaslMechanismOAuth2 而不是NetworkCredential 进行身份验证。我现在有以下工作:

      var secrets = new ClientSecrets
      {
          ClientId = Environment.GetEnvironmentVariable("GMailClientId"),
          ClientSecret = Environment.GetEnvironmentVariable("GMailClientSecret")
      };
      
      var googleCredentials = await GoogleWebAuthorizationBroker.AuthorizeAsync(secrets, new[] { GmailService.Scope.MailGoogleCom }, email, CancellationToken.None);
      if (googleCredentials.Token.IsExpired(SystemClock.Default))
      {
          await googleCredentials.RefreshTokenAsync(CancellationToken.None);
      }
      
      using (var client = new SmtpClient())
      {
          client.Connect("smtp.gmail.com", 587, SecureSocketOptions.StartTls);
      
          var oauth2 = new SaslMechanismOAuth2(googleCredentials.UserId, googleCredentials.Token.AccessToken);
          client.Authenticate(oauth2);
      
          await client.SendAsync(message);
          client.Disconnect(true);
      }
      

      【讨论】:

      • 工作,干得好!
      • 对于以后尝试使用此功能的任何人 - 这是涉及用户在浏览器中进行身份验证的三足流程,而不是服务帐户流程。
      • 正在寻找服务帐户流程。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-11-20
      • 2018-11-11
      • 2011-03-15
      • 1970-01-01
      • 2012-01-01
      • 2020-04-19
      相关资源
      最近更新 更多