首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >如何根据新的安全策略在.Net中发送电子邮件?

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

Stack Overflow用户
提问于 2016-01-18 17:40:42
回答 3查看 31.8K关注 0票数 74

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

这意味着System.Net.Mail不再工作,我们需要使用另一个库,如MailKit,这对吗?

总的来说,我想知道如何在不允许“访问安全性较低的应用程序”的情况下发送电子邮件?

因为我在执行smtpClient.Send(message);时使用了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.

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

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

代码语言:javascript
复制
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);
        }
   }
}

它工作得很好,直到new Google security policies

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

经过调查,我了解到我的初始代码没有太多变化,因为(与System.Net.Mail) MailKit's API看起来非常相似。

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

因此,在将来,我将使用以下代码行:

代码语言:javascript
复制
smtpClient.Authenticate (usersLoginName, usersOAuthToken);

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

代码语言:javascript
复制
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一样)

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-01-21 15:07:48

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

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

2)如果关闭了两步验证,并且您希望保持这种方式,这意味着您将需要像您所说的那样实现许多身份验证机制。

解决方案:打开它,然后生成并使用google应用程序密码。它应该是有效的!您不需要使用其他库,如mailkit

票数 34
EN

Stack Overflow用户

发布于 2016-04-26 00:38:20

当从没有实现Google特定安全要求的应用程序使用Gmail smtp服务器时,会发生身份验证错误。在Gmail账户设置中,打开:“登录和安全”>“连接的应用程序和站点”>“允许不太安全的应用程序”>打开

票数 1
EN

Stack Overflow用户

发布于 2021-08-18 21:14:57

代码语言:javascript
复制
using System;
using System.Net;
using System.Net.Mail;
using System.Net.Mime;
using System.Threading;
using System.ComponentModel;
namespace Examples.SmtpExamples.Async
{
public class SimpleAsynchronousExample
{
    static bool mailSent = false;
    private static void SendCompletedCallback(object sender, AsyncCompletedEventArgs e)
    {
        // Get the unique identifier for this asynchronous operation.
         String token = (string) e.UserState;

        if (e.Cancelled)
        {
             Console.WriteLine("[{0}] Send canceled.", token);
        }
        if (e.Error != null)
        {
             Console.WriteLine("[{0}] {1}", token, e.Error.ToString());
        } else
        {
            Console.WriteLine("Message sent.");
        }
        mailSent = true;
    }
    public static void Main(string[] args)
    {
        // Command-line argument must be the SMTP host.
        SmtpClient client = new SmtpClient(args[0]);
        // Specify the email sender.
        // Create a mailing address that includes a UTF8 character
        // in the display name.
        MailAddress from = new MailAddress("jane@contoso.com",
           "Jane " + (char)0xD8+ " Clayton",
        System.Text.Encoding.UTF8);
        // Set destinations for the email message.
        MailAddress to = new MailAddress("ben@contoso.com");
        // Specify the message content.
        MailMessage message = new MailMessage(from, to);
        message.Body = "This is a test email message sent by an application. ";
        // Include some non-ASCII characters in body and subject.
        string someArrows = new string(new char[] {'\u2190', '\u2191', '\u2192', '\u2193'});
        message.Body += Environment.NewLine + someArrows;
        message.BodyEncoding =  System.Text.Encoding.UTF8;
        message.Subject = "test message 1" + someArrows;
        message.SubjectEncoding = System.Text.Encoding.UTF8;
        // Set the method that is called back when the send operation ends.
        client.SendCompleted += new
        SendCompletedEventHandler(SendCompletedCallback);
        // The userState can be any object that allows your callback
        // method to identify this send operation.
        // For this example, the userToken is a string constant.
        string userState = "test message1";
        client.SendAsync(message, userState);
        Console.WriteLine("Sending message... press c to cancel mail. Press any other key to exit.");
        string answer = Console.ReadLine();
        // If the user canceled the send, and mail hasn't been sent yet,
        // then cancel the pending operation.
        if (answer.StartsWith("c") && mailSent == false)
        {
            client.SendAsyncCancel();
        }
        // Clean up.
        message.Dispose();
        Console.WriteLine("Goodbye.");
    }
}
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34851484

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档