.NET是否支持通过OAuth协议进行SMTP身份验证?基本上,我想能够使用OAuth访问令牌代表用户发送电子邮件。然而,在.NET框架中,我找不到对此的支持。
Google在其他环境中提供了一些示例,但没有在.NET中提供。
System.Net.Mail不支持OAuth或OAuth2。但是,您可以使用MailKit的(SmtpClient只支持OAuth2) SmtpClient发送邮件,只要您有用户的OAuth访问令牌( MailKit没有代码来获取OAuth令牌,但如果您有它,它可以使用它)。
您需要做的第一件事是按照Google的说明获取OAuth 2.0凭据以用于您的应用程序。
完成后,获取访问令牌最简单的方法是使用Google的Google.Apis.Auth库:
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));
bool result = await credential.RequestAccessTokenAsync (CancellationToken.None);
// Note: result will be true if the access token was received successfully
现在您已经获得了访问令牌 (credential.Token.AccessToken
),您可以像使用密码一样在 MailKit 中使用它:
using (var client = new SmtpClient ()) {
client.Connect ("smtp.gmail.com", 587, SecureSocketOptions.StartTls);
// use the access token
var oauth2 = new SaslMechanismOAuth2 ("username@gmail.com", credential.Token.AccessToken);
client.Authenticate (oauth2);
client.Send (message);
client.Disconnect (true);
}
我通过使用 Microsoft.Identity.Client
和 MailKit.Net.Smtp.SmtpClient
获得了成功,像这样在 Office 365 / Exchange Online 中使用。应用程序注册需要 API 权限 SMTP.Send
。
var options = new PublicClientApplicationOptions
{
ClientId = "00000000-0000-0000-0000-000000000000",
TenantId = " 00000000-0000-0000-0000-000000000000",
RedirectUri = "http://localhost"
};
var publicClientApplication = PublicClientApplicationBuilder
.CreateWithApplicationOptions(options)
.Build();
var scopes = new string[] {
"email",
"offline_access",
"https://outlook.office.com/SMTP.Send" // Only needed for SMTP
};
var authToken = await publicClientApplication.AcquireTokenInteractive(scopes).ExecuteAsync();
//Test refresh token
var newAuthToken = await publicClientApplication.AcquireTokenSilent(scopes, authToken.Account).ExecuteAsync(cancellationToken);
var oauth2 = new SaslMechanismOAuth2(authToken.Account.Username, authToken.AccessToken);
using (var client = new SmtpClient())
{
await client.ConnectAsync("smtp.office365.com", 587, SecureSocketOptions.StartTls);
await client.AuthenticateAsync(oauth2);
var message = new MimeMessage();
message.From.Add(MailboxAddress.Parse(authToken.Account.Username));
message.To.Add(MailboxAddress.Parse("toEmail"));
message.Subject = "Test";
message.Body = new TextPart("plain") { Text = @"Oscar Testar" };
await client.SendAsync(message, cancellationToken);
await client.DisconnectAsync(true);
}
根据这个例子:
https://github.com/jstedfast/MailKit/blob/master/ExchangeOAuth2.md
补充以上答案。我也花了很多时间在使用mailkit在.net中使用gmail oAuth2发送电子邮件的事情上进行研究,因为我正在使用它向我的应用程序用户发送电子邮件。感谢mailkit开发人员。
现在我们需要:
您可以通过创建项目直接从google控制台获取客户端ID和客户端密钥。
接下来,您可以在Google Developers OAuth Playground中使用自己的OAuth凭据启用gmail应用程序,方法是使用左上角设置按钮。
之后选择并授权API https://mail.google.com/
。
现在,您可以通过此http POST请求https://developers.google.com/oauthplayground/refreshAccessToken
直接刷新令牌。您将在其中找到参数。
现在,您可以直接在C#代码中使用MailKit使用此代码:
using (var client = new SmtpClient())
{
client.Connect("smtp.gmail.com", 587, SecureSocketOptions.StartTls);
var oauth2 = new SaslMechanismOAuth2(GMailAccount, token.AccessToken);
client.Authenticate(oauth2);
await client.SendAsync(mailMessage);
client.Disconnect(true);
}
使用其他答案中提到的MailKit时,我遇到了一个需要从Gmail请求更多范围的身份验证问题。对于任何遇到其他答案中的“身份验证失败错误”的人,此答案改用Gmail API以避免请求更多范围。
使用此答案中的一些片段:https://stackoverflow.com/a/35795756/7242722
这是一个完整的示例,对我有效:
var fromAddress = new MailboxAddress(fromName, fromEmail);
var toAddress = new MailboxAddress(toName, toEmail);
List<MailboxAddress> ccMailAddresses = new List<MailboxAddress>();
if (ccEmails != null)
foreach (string ccEmail in ccEmails)
ccMailAddresses.Add(new MailboxAddress(string.Empty, ccEmail));
var message = new MimeMessage();
message.To.Add(toAddress);
message.From.Add(fromAddress);
message.Subject = subject;
var bodyBuilder = new BodyBuilder();
bodyBuilder.HtmlBody = body;
bodyBuilder.TextBody = HtmlUtilities.ConvertToPlainText(body);
message.Body = bodyBuilder.ToMessageBody();
foreach (MailboxAddress ccMailAddress in ccMailAddresses)
message.Cc.Add(ccMailAddress);
GoogleAuthorizationCodeFlow authorizationCodeFlow = new GoogleAuthorizationCodeFlow(new GoogleAuthorizationCodeFlow.Initializer
{
ClientSecrets = new ClientSecrets()
{
ClientId = <ClientId>,
ClientSecret = <ClientSecret>
},
});
TokenResponse tokenResponse = await authorizationCodeFlow.RefreshTokenAsync("id", <RefreshToken>, CancellationToken.None);
UserCredential credential = new UserCredential(authorizationCodeFlow, "id", tokenResponse);
var gmailService = new GmailService(new BaseClientService.Initializer()
{
ApplicationName = <AppName>,
HttpClientInitializer = credential,
});
Google.Apis.Gmail.v1.Data.Message gmailMessage = new Google.Apis.Gmail.v1.Data.Message();
gmailMessage.Raw = Utilities.Base64UrlEncode(message.ToString());
var result = gmailService.Users.Messages.Send(gmailMessage, "me").Execute();
private_key
,然后使用FromPrivateKey
方法而不是FromCertificate
。这为我提供了一个ServiceAccountCredential
,我可以使用它来请求访问令牌,然后进行身份验证(与上面相同)。但是,当使用我的令牌调用Authenticate
方法时,Mailkit会抛出AuthenticationException
。基本上与此答案相同-https://dev59.com/_loT5IYBdhLWcg3wlwaR#38403006。 - Murphybro2