1. ホーム
  2. c#

新しいセキュリティポリシーに従って、.Netで電子メールを送信するにはどうすればよいですか?

2023-10-24 20:53:03

質問

ユーザーをより良く保護するために、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. いつ 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 ).

ただし、1つだけ細かい点があります。ユーザーの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ライブラリを使用する必要があります。しかし、私は多くの可能なメールプロバイダに対応するために、多くの認証メカニズムを私のコードに持ちたくはありません。私は、すべてのメールプロバイダに対応する1つの一般的なソリューションを持っていたいのです。そして、メールを送信することができる1つのライブラリ(.net smtpclientがそうであったように)。

どのように解決するのですか?

一般的な解決方法は https://galleryserverpro.com/use-gmail-as-your-smtp-server-even-when-using-2-factor-authentication-2-step-verification/

1) ブラウザーを使ってGoogleアカウントにログインし、サインインとセキュリティの設定に進みます。2段階認証の設定を探します。

2) 2段階認証がオフで、その状態を維持したい場合、あなたが言ったように、多くの認証メカニズムを実装する必要があることを意味します。

解決策 それをオンにして、Google アプリのパスワードを生成して使用します。これでうまくいくはずです。のような他のライブラリを使用する必要はありません。 mailkit .