根据新的安全策略如何在.Net中发送电子邮件?

为了更好地保护用户,GMail和其他邮件提供商建议将我们的所有应用程序升级到OAuth 2.0。

我是对的,这意味着System.Net.Mail不再工作,我们需要使用MailKit类的其他库吗?

一般来说,我试图了解如何发送电子邮件而不允许“访问不太安全的应用程序”?

因为我有System.Net.Mail.SmtpException: The SMTP server requires a secure connection or the client was not authenticated. The server response was: 5.5.1 Authentication Required. System.Net.Mail.SmtpException: The SMTP server requires a secure connection or the client was not authenticated. The server response was: 5.5.1 Authentication Required.smtpClient.Send(message); 执行。

如果解决这个问题的唯一方法是使用MailKit ,我认为这个问题将是一个很好的切实可行的从System.Net.Mail切换到使用MailKitGoogle.Apis.Auth.OAuth2 。 我不知道可能一般的解决方案将使用DotNetOpenAuth

我的应用程序中有以下类,它们对应于发送电子邮件到任何地址(gmail,yandex和其他):

public class EmailSender
{
    public void SendEmail(SmtpServerSettings serverSettings, SendEmailRequest emailRequest)
    {
        // Usually I have 587 port, SmtpServerName = smtp.gmail.com 
        _logger.Trace("Sending message with subject '{0}' using SMTP server {1}:{2}",
                      emailRequest.Subject,
                      serverSettings.SmtpServerName,
                      serverSettings.SmtpPort);

        try
        {
            using (var smtpClient = new SmtpClient(serverSettings.SmtpServerName, (int)serverSettings.SmtpPort))
            {
                smtpClient.EnableSsl = serverSettings.SmtpUseSsl; // true
                if (!string.IsNullOrEmpty(serverSettings.UserName) || !string.IsNullOrEmpty(serverSettings.EncryptedPassword))
                {
                    smtpClient.Credentials = new NetworkCredential(serverSettings.UserName, serverSettings.EncryptedPassword);
                }

                smtpClient.DeliveryMethod = SmtpDeliveryMethod.Network;
                smtpClient.Timeout = (int)serverSettings.SmtpTimeout.TotalMilliseconds;

                using (var message = new MailMessage())
                {
                    message.From = new MailAddress(serverSettings.FromAddress);

                    emailRequest.To.ForEach(message.To.Add);
                    emailRequest.CC.ForEach(message.CC.Add);
                    emailRequest.Bcc.ForEach(message.Bcc.Add);

                    message.Subject = emailRequest.Subject.Replace('r', ' ').Replace('n', ' ');
                    message.Body = emailRequest.Body;
                    message.BodyEncoding = Encoding.UTF8;
                    message.IsBodyHtml = false;

                    smtpClient.Send(message);
                }
            }

            _logger.Trace("Sent message with subject '{0}' using SMTP server {1}:{2}",
                          emailRequest.Subject,
                          serverSettings.SmtpServerName,
                          serverSettings.SmtpPort);
        }
        catch (SmtpFailedRecipientsException e)
        {
            var failedRecipients = e.InnerExceptions.Select(x => x.FailedRecipient);
            LogAndReThrowWithValidMessage(e, EmailsLocalization.EmailDeliveryFailed, failedRecipients);
        }
   }
}

直到新的Google安全政策,它才能正常工作。

我知道System.Net.Mail不支持OAuth2 。 我决定使用MailKit's SmtpClient发送消息。

调查后,我明白我的初始代码没有太大变化,因为MailKit's API看起来非常相似(使用System.Net.Mail )。

除了一个细节外:我需要拥有用户的OAuth访问令牌(MailKit没有可以获取OAuth令牌的代码,但是如果拥有它,它可以使用它)。

所以在未来我会有以下线路:

smtpClient.Authenticate (usersLoginName, usersOAuthToken);

我有一个想法将GoogleCredentials作为新参数添加到SendEmail方法中:

public void SendEmail(SmtpServerSettings serverSettings, SendEmailRequest emailRequest, 
                      GoogleCredentials credentials)
{
    var certificate = new X509Certificate2(credentials.CertificateFilePath,
                                           credentials.PrivateKey,
                                           X509KeyStorageFlags.Exportable);

     var credential = new ServiceAccountCredential(
                      new ServiceAccountCredential.Initializer(credentials.ServiceAccountEmail)
                             {
                                 Scopes = new[] { "https://mail.google.com/" },
                                 User = serverSettings.UserName
                             }.FromCertificate(certificate));

    ....
    //my previous code but with MailKit API
}

如何获取用户usersOAuthToken ? 使用Google.Apis.Auth.OAuth2是否是最佳实践技巧?

我上面发布的代码仅适用于GMail,不适用于yandex.ru或其他邮件提供商。 要与他人合作,我可能需要使用另一个OAuth2库。 但我不想在我的代码中为许多可能的邮件提供商提供许多身份验证机制。 我希望为每个邮件提供商提供一个通用解决方案。 还有一个可以发送电子邮件的库(例如.net smtpclient)


一般的解决方案是https://galleryserverpro.com/use-gmail-as-your-smtp-server-even-when-using-2-factor-authentication-2-step-verification/

1)使用浏览器登录到您的Google帐户,然后转到登录和安全设置。 查找两步验证设置。

2)如果两步验证已关闭,并且您希望保持这种方式,那就意味着您需要按照您的说法实施多种验证机制。

解决方案:将其打开,然后生成并使用Google应用密码。 它应该工作! 您不需要使用其他类似于mailkit库。


如何获取用户OAuthToken?

您需要做的第一件事是按照Google的说明为您的应用程序获取OAuth 2.0凭据。

完成之后,获取访问令牌的最简单方法是使用Google的Google.Apis.Auth库:

using System;
using System.Threading;
using System.Security.Cryptography.X509Certificates;

using Google.Apis.Auth.OAuth2;

using MimeKit;
using MailKit.Net.Smtp;
using MailKit.Security;

namespace Example {
    class Program
    {
        public static async void Main (string[] args)
        {
            var certificate = new X509Certificate2 (@"C:pathtocertificate.p12", "password", X509KeyStorageFlags.Exportable);
            var credential = new ServiceAccountCredential (new ServiceAccountCredential
                .Initializer ("your-developer-id@developer.gserviceaccount.com") {
                    // Note: other scopes can be found here: https://developers.google.com/gmail/api/auth/scopes
                    Scopes = new[] { "https://mail.google.com/" },
                    User = "username@gmail.com"
                }.FromCertificate (certificate));

            // Note: result will be true if the access token was received successfully
            bool result = await credential.RequestAccessTokenAsync (CancellationToken.None);

            if (!result) {
                Console.WriteLine ("Error fetching access token!");
                return;
            }

            var message = new MimeMessage ();
            message.From.Add (new MailboxAddress ("Your Name", "username@gmail.com"));
            message.To.Add (new MailboxAddress ("Recipient's Name", "recipient@yahoo.com"));
            message.Subject = "This is a test message";

            var builder = new BodyBuilder ();
            builder.TextBody = "This is the body of the message.";
            builder.Attachments.Add (@"C:pathtoattachment");

            message.Body = builder.ToMessageBody ();

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

                // use the access token as the password string
                client.Authenticate ("username@gmail.com", credential.Token.AccessToken);

                client.Send (message);

                client.Disconnect (true);
            }
        }
    }
}

使用Google.Apis.Auth.OAuth2是否是最佳实践技巧?

你为什么不使用他们的API获取认证令牌? 这似乎是最好的方式让我...

我可以发送电子邮件给其他非Gmail账户吗?

是的,您通过GMail发送的任何电子邮件都可以发送到任何其他电子邮件地址 - 它不必仅限于其他GMail地址。


从未实施Google特定安全要求的应用程序使用Gmail smtp服务器时发生身份验证错误。 在Gmail帐户设置中,启用:“登录与安全”>“关联的应用和网站”>“允许安全性较低的应用”>开启

链接地址: http://www.djcxy.com/p/50527.html

上一篇: How to send an email in .Net according to new security policies?

下一篇: Sending email through Gmail SMTP server with C#