¿Cómo enviar un correo electrónico en .Net de acuerdo con las nuevas políticas de seguridad?

Para proteger mejor a sus usuarios, GMail y otros proveedores de correo recomiendan actualizar todas nuestras aplicaciones a OAuth 2.0.

¿Tengo razón en que esto significa que System.Net.Mail ya no funciona y necesitamos usar otra biblioteca como MailKit ?

En general, trato de entender cómo enviar un correo electrónico sin permitir el “Acceso para aplicaciones menos seguras”.

Porque tengo 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. Cuando smtpClient.Send(message); ejecutado.

Si la única forma de resolver este problema es usar MailKit , creo que esta pregunta será un buen tutorial de cambio paso a paso práctico de System.Net.Mail a usar MailKit y MailKit . No sé, ¿tal vez la solución general usará DotNetOpenAuth ?

Tengo la siguiente clase en mi aplicación que corresponde a enviar un correo electrónico a cualquier dirección (gmail, yandex y otros):

 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); } } } 

Funciona bien hasta las nuevas políticas de seguridad de Google .

Sé que System.Net.Mail no es compatible con OAuth2 . Decidí usar MailKit's SmtpClient para enviar mensajes.

Después de la investigación entiendo que mi código inicial no cambia tanto, porque MailKit's API MailKit's ve muy similar (con System.Net.Mail ).

Excepto un detalle: necesito tener el token de acceso OAuth del usuario (MailKit no tiene código que obtenga el token OAuth, pero puede usarlo si lo tengo).

Entonces en el futuro tendré la siguiente línea:

 smtpClient.Authenticate (usersLoginName, usersOAuthToken); 

Tengo una idea para agregar GoogleCredentials como nuevo parámetro al método 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 } 

Cómo obtener los usersOAuthToken ? ¿Es la mejor técnica de práctica usar Google.Apis.Auth.OAuth2 ?

El código que publiqué arriba es solo para GMail y NO funcionará para yandex.ru u otros proveedores de correo. Para trabajar con otros, probablemente necesite usar otras bibliotecas de OAuth2. Pero no quiero tener muchos mecanismos de autenticación en mi código para muchos posibles proveedores de correo. Me gustaría tener UNA SOLUCIÓN GENERAL para cada proveedor de correo. Y una biblioteca que puede enviar correos electrónicos (como .net smtpclient)

La solución general es https://galleryserverpro.com/use-gmail-as-your-smtp-server-even-when-using-2-factor-authentication-2-step-verification/

1) Use un navegador para iniciar sesión en su cuenta de Google y vaya a su inicio de sesión y configuración de seguridad. Busque la configuración de verificación de 2 pasos.

2) Si la verificación en 2 pasos está desactivada y desea mantenerla de esa manera, eso significa que tendrá que implementar muchos mecanismos de autenticación como dijo.

Solución: enciéndalo y luego genere y use la contraseña de la aplicación google. ¡Deberia de funcionar! No necesita usar otras bibliotecas como mailkit .

Cómo obtener los usuarios deOAuthToken?

Lo primero que debe hacer es seguir las instrucciones de Google para obtener las credenciales de OAuth 2.0 para su aplicación.

Una vez que haya hecho eso, la forma más fácil de obtener un token de acceso es usar la biblioteca Google.Apis.Auth de Google :

 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:\path\to\certificate.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:\path\to\attachment"); 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); } } } } 

¿Es la mejor técnica de práctica usar Google.Apis.Auth.OAuth2?

¿Por qué no usarías su API para obtener un token de autenticación? Parece que es la mejor manera de dármelo …

¿Puedo enviar un correo electrónico a otras cuentas que no sean de Gmail?

Sí, cualquier correo electrónico que envíe a través de GMail se puede enviar a cualquier otra dirección de correo electrónico; no tiene que ser solo para otras direcciones de GMail.

Se producen errores de autenticación cuando se utiliza el servidor smtp de Gmail desde aplicaciones que no implementan los requisitos de seguridad específicos de Google. En la configuración de la cuenta de Gmail, active: “Inicio de sesión y seguridad”> “Aplicaciones y sitios conectados”> “Permitir aplicaciones menos seguras”> Activado