To better protect your users, GMail and others mail providers recommends to upgrade all of our applications to OAuth 2.0.
Am I right that this means that System.Net.Mail
don't work anymore and we need to use another library like MailKit
?
In general I'm trying to understand how to send an email without allowing "Access for less secure apps"?
Because I have 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.
When smtpClient.Send(message);
executed.
If the only way to solve this problem is using MailKit
, I think that this question will be a good practical step-by-step switching tutorial from System.Net.Mail
to using MailKit
and Google.Apis.Auth.OAuth2
. I don't know maybe general solution will be using DotNetOpenAuth
?
I have the following class in my application that correspond to send an email to any address(gmail, yandex and others):
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('
', ' ').Replace('
', ' ');
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);
}
}
}
It works fine until the new Google security policies.
I know that System.Net.Mail
does not support OAuth2
. I decided to use MailKit's
SmtpClient
to send messages.
After the investigation I understand that my initial code not change so much, because MailKit's
API looks very similar(with System.Net.Mail
).
Except one detail: I need to have the user's OAuth access token (MailKit does not have code that will fetch the OAuth token, but it can use it if I have it).
So in the future I will have the following line:
smtpClient.Authenticate (usersLoginName, usersOAuthToken);
I have an idea to add GoogleCredentials
as new parameter to the SendEmail
method:
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
}
How to get usersOAuthToken
?
Is it the best practice technique to use Google.Apis.Auth.OAuth2
?
The code I posted above is for GMail ONLY and WILL NOT work for yandex.ru or other mail providers. To work with others, I will probably need to use another OAuth2 librarys. But I don't want to have many authentication mechanisms in my code for many possible mail providers. I would like to have ONE GENERAL SOLUTION for every mail providers. And one library that can send email (like .net smtpclient did)
See Question&Answers more detail:
os