如何使用MailKit发送电子邮件?

33
根据谷歌的新政策https://googleonlinesecurity.blogspot.de/2014/04/new-security-measures-will-affect-older.html,我无法发送电子邮件。对于谷歌而言,“不安全的应用程序”指的是不使用OAuth 2.0的应用程序。
我希望使用MailKit来解决这个问题。
var message = new MimeMessage();

message.From.Add(new MailboxAddress("Joey Tribbiani", "noreply@localhost.com"));
message.To.Add(new MailboxAddress("Mrs. Chanandler Bong", "mymail@gmail.com"));
message.Subject = "How you doin'?";
message.Body = new TextPart("plain"){ Text = @"Hey" };

using (var client = new SmtpClient())
{
   client.Connect("smtp.gmail.com", 587);

   ////Note: only needed if the SMTP server requires authentication
   client.Authenticate("mymail@gmail.com", "mypassword");

   client.Send(message);
   client.Disconnect(true);
}

但我遇到了一个异常:MailKit.Security.AuthenticationException,它出现在 MailKit.dll 中,但是没有被用户代码处理。附加信息:认证失败。

我不想改变我的安全设置,因为我希望一切都是安全的。这就是为什么我开始使用 MailKit 而不是 System.Net.Mail 的原因。

我该如何解决这个问题?


1
这与Mailkit或C#无关,而是与Google有关。你要么输入了错误的密码,要么需要更改帐户的安全设置如此处所示 - Panagiotis Kanavos
1
我认为这是因为您需要设置与Oauth 2.0的连接 https://github.com/jstedfast/MailKit/blob/df7b0f5b9522ed355aa49cfbe56892031d65047f/FAQ.md#how-can-i-log-in-to-a-gmail-account-using-oauth-20 - LUIS PEREIRA
实际上,即使密码看起来正确,GMail 可能会返回身份验证错误的多种原因 - 一次性密码、双重身份验证(如此处所述)。 - Panagiotis Kanavos
2个回答

31

首先,您需要按照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));

//You can also use FromPrivateKey(privateKey) where privateKey
// is the value of the field 'private_key' in your serviceName.json file

bool result = await credential.RequestAccessTokenAsync (cancel.Token);

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

   // use the OAuth2.0 access token obtained above
   var oauth2 = new SaslMechanismOAuth2 ("mymail@gmail.com", credential.Token.AccessToken);
   client.Authenticate (oauth2);

   client.Send (message);
   client.Disconnect (true);
}

更新:

以上解决方案是针对Google所称的“服务账户”,用于服务器之间的通信,但如果您想要标准手机或桌面应用程序的OAuth2支持,您需要按照我在这里编写的说明操作:https://github.com/jstedfast/MailKit/blob/master/GMailOAuth2.md


我能发送邮件到“非Gmail”账户吗? - Anatoly
你不能使用谷歌的OAuth2令牌与非Gmail服务器。这是你所问的吗? - jstedfast
请使用常规的用户名和密码。 - jstedfast
如果我使用System.Net.Mail,但是带有X509Certificate2,那么我会在新的Google安全策略下遇到问题吗? - Anatoly
我在调用RequestAccessTokenAsync方法时遇到了以下异常:TokenResponseException: 错误:"unauthorized_client",描述:"Client is unauthorized to retrieve access tokens using this method."。 - Sivanantham Padikkasu
显示剩余10条评论

28

我测试了以下代码,对我而言可行:

        // STEP 1: Navigate to this page https://www.google.com/settings/security/lesssecureapps & set to "Turn On"

        var message = new MimeMessage();
        message.From.Add(new MailboxAddress("Joey Tribbiani", "YOU_FROM_ADDRESS@gmail.com"));
        message.To.Add(new MailboxAddress("Mrs. Chanandler Bong", "YOU_TO_ADDRESS@gmail.com"));
        message.Subject = "How you doin'?";

        message.Body = new TextPart("plain")
        {
            Text = @"Hey Chandler,I just wanted to let you know that Monica and I were going to go play some paintball, you in?-- Joey"
        };

        using (var client = new SmtpClient())
        {
            client.Connect("smtp.gmail.com", 587);


            // Note: since we don't have an OAuth2 token, disable
            // the XOAUTH2 authentication mechanism.
            client.AuthenticationMechanisms.Remove("XOAUTH2");

            // Note: only needed if the SMTP server requires authentication
            client.Authenticate("YOUR_GMAIL_NAME", "YOUR_PASSWORD");

            client.Send(message);
            client.Disconnect(true);
        }

3
我尝试了这个方法,但仍然收到证书错误,是否有其他人也遇到此问题? - Carlos Jimenez Bermudez
2
非常适合我使用。非常适合学生项目!在尝试此代码之前,请不要忘记访问此链接!:https://www.google.com/settings/security/lesssecureapps - Christopher J.
那么,任何黑客都会看到你的Google邮箱密码?对我来说似乎不是个好主意! - Tim Makins
对我来说是有效的。我在我的测试应用程序中使用了它 - 使用我的测试gmail帐户。 在生产环境中,我使用了客户电子邮件的SMTP服务器。因此,其他程序员(或更糟的黑客)看到我的“应用程序密码”没有问题 - 这只是一个gmail测试帐户,我随时可以撤销这个应用程序密码。 - Fadz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接