使用 .NET core 2.2 中的 MailKit SMTP 客户端通过 Gmail SMTP 发送邮件对我不起作用
Posted
技术标签:
【中文标题】使用 .NET core 2.2 中的 MailKit SMTP 客户端通过 Gmail SMTP 发送邮件对我不起作用【英文标题】:Send mail with Gmail SMTP using MailKit SMTP Client in .NET core 2.2 is not working for me 【发布时间】:2019-08-18 07:39:30 【问题描述】:我正在使用 NLog 目标通过 smtp.google.com:587 SMTP 服务器将日志发送到一些电子邮件。当我使用标准 System.Net.Mail.SmtpClient 库时,它可以正常工作,但是在使用 MailKit 时会抛出错误:
发送邮件时出错。异常:>System.Net.Internals.SocketExceptionFactory+ExtendedSocketException (10061): 无法建立连接,因为目标机器主动拒绝它。>[::ffff:173.194.76.108]:587
我添加了一个带有两个控制台项目的解决方案。一个使用 MailKit 和其他 System.Net.Mail。所有设置参数看起来都一样,但在 MailKit 中不起作用:
using System;
using System.Diagnostics;
using MailKit.Net.Smtp;
using MailKit;
using MailKit.Security;
using MimeKit;
namespace SendMailKit
class Program
public static void Main(string[] args)
Console.WriteLine("Create message");
var message = new MimeMessage();
message.From.Add(new MailboxAddress("GTS", "tfs.gettaxsolutions@gmail.com"));
message.To.Add(new MailboxAddress("Me", "info@gettaxsolutions.com"));
message.Subject = "Test mail";
message.Body = new TextPart("plain")
Text = @"Hello, This is the test"
;
Console.WriteLine("Create SMTP client");
using (var client = new SmtpClient())
// For demo-purposes, accept all SSL certificates (in case the server supports STARTTLS)
client.ServerCertificateValidationCallback = (s, c, h, e) => true;
Console.WriteLine("Connect");
**client.Connect("smtp.gmail.com", 587, true);**
Console.WriteLine("Authenticate");
client.Authenticate("tfs.gettaxsolutions", "*********");
client.Connected += Client_Connected;
client.Disconnected += Client_Disconnected;
client.Authenticated += Client_Authenticated;
client.MessageSent += Client_MessageSent;
Console.WriteLine("Send Message");
client.Send(message);
Console.WriteLine("Disconnect");
client.Disconnect(true);
Console.ReadLine();
private static void Client_MessageSent(object sender, MessageSentEventArgs e)
Console.WriteLine("MessageSent");
private static void Client_Authenticated(object sender, AuthenticatedEventArgs e)
Console.WriteLine("Authenticated");
private static void Client_Disconnected(object sender, DisconnectedEventArgs e)
Console.WriteLine("Disconnected");
private static void Client_Connected(object sender, ConnectedEventArgs e)
Console.WriteLine("Connected");
这会在 NLog 中引发与此相同的异常。例外是在 client.Connect("smtp.gmail.com", 587, true);所以问题出在 MailKit 连接中。在使用 System.Net.Mail 的其他项目中,一切正常,邮件发送成功。我在同一台机器上启动它们,相同的环境只是改变控制台应用程序的启动点来测试(所以连接不是问题):
using System;
using System.Net;
using System.Net.Mail;
using System.Net.Mime;
using System.Threading;
using System.ComponentModel;
namespace SendSimpleMail
public class Program
static bool mailSent = false;
private static void SendCompletedCallback(object sender, AsyncCompletedEventArgs e)
// Get the unique identifier for this asynchronous operation.
String token = (string)e.UserState;
if (e.Cancelled)
Console.WriteLine("[0] Send canceled.", token);
if (e.Error != null)
Console.WriteLine("[0] 1", token, e.Error.ToString());
else
Console.WriteLine("Message sent.");
mailSent = true;
public static void Main()
// Command-line argument must be the SMTP host.
SmtpClient client = new SmtpClient("smtp.gmail.com", 587);
client.EnableSsl = true;
client.UseDefaultCredentials = false;
client.Credentials = new NetworkCredential("tfs.gettaxsolutions", "***********");
// Specify the email sender.
// Create a mailing address that includes a UTF8 character
// in the display name.
MailAddress from = new MailAddress("tfs.gettaxsolutions@gmail.com", "GTS");
// Set destinations for the email message.
MailAddress to = new MailAddress("info@gettaxsolutions.com", "Me");
// Specify the message content.
MailMessage message = new MailMessage(from, to);
message.Body = "This is a test email message sent by an application. ";
// Include some non-ASCII characters in body and subject.
string someArrows = new string(new char[] '\u2190', '\u2191', '\u2192', '\u2193' );
message.Body += Environment.NewLine + someArrows;
message.BodyEncoding = System.Text.Encoding.UTF8;
message.Subject = "test message 1" + someArrows;
message.SubjectEncoding = System.Text.Encoding.UTF8;
// Set the method that is called back when the send operation ends.
client.SendCompleted += new
SendCompletedEventHandler(SendCompletedCallback);
// The userState can be any object that allows your callback
// method to identify this send operation.
// For this example, the userToken is a string constant.
string userState = "test message1";
client.SendAsync(message, userState);
Console.WriteLine("Sending message... press c to cancel mail. Press any other key to exit.");
string answer = Console.ReadLine();
// If the user canceled the send, and mail hasn't been sent yet,
// then cancel the pending operation.
if (answer.StartsWith("c") && mailSent == false)
client.SendAsyncCancel();
// Clean up.
message.Dispose();
Console.WriteLine("Goodbye.");
我找不到 MailKit 的问题所在。设置看起来相同。你知道什么可能是一个问题吗?是错误还是我的设置有问题?
MailKit 必须发送电子邮件成功
ASP.NET Core 2.2、MailKit 2.1.3
【问题讨论】:
在此处查看已接受的类似问题的答案:***.com/questions/9695224/… 【参考方案1】:几分钟前我刚刚部分解决了一个非常相似的问题;我学到的可能会对你有所帮助。
在我的情况下,MailKit 有可靠的工作代码从目标为 NET Core 2.1 的应用程序发送。
最近我更新了所有的 Nuget 包,认为这样做是个好习惯。后来我发现我的工作 SMTP 发送代码突然停止工作,它报告的错误与您遇到的相同。
在这种情况下,我检查了 smtp 服务器、防火墙等的各种问题,直到我想起了 Nuget 更新,开始试验并最终将 MailKit 降级到 2.0.0。 MailKit 版本降级后,发送代码再次开始工作。
我还没有确定故障的确切位置和机制,但我确信(在我一直在研究的情况下)使用的 MailKit 版本直接涉及。今天,它已恢复为 MailKit 2.0.0 降级工作,还有更多的研究要做,以使其超越该状态。
【讨论】:
尝试将client.Timeout设置为-1,看看问题是否可能是连接超时?这是 2.0 和 2.1 之间的主要变化(连接变得可以通过超时值取消)。 会检查的。失败是针对两个完全不同的 smtp 服务器的一致连接。 (回到 2.0 时两台服务器都成功了。)没有代码更改,所以可能采用的默认值不好。 嗯,我只记得我从执行 Dns.GetHostAddresses() 然后循环每个 IP 地址返回到只有Socket.Connect (string hostname, int port)
。也许问题在于 Socket.Connect() 在给定主机名时没有使用正确的 IP?
您使用的是 WIndows 系统还是 Linux/MacOS 等基于 Unix 的系统?当通过主机名而不是 IPAddress 连接时,.NET 的 SOcket 逻辑中似乎存在/曾经(?)一个错误,因为 Linux/MacOS 不能重用套接字。
尝试转到myget.org/feed/mimekit/package/nuget/MailKit 并安装最新的 MailKit 版本 (>= 2.1.3.15)。我对 Connect 逻辑进行了一些更改,可以解决这个问题?【参考方案2】:
我把connect的代码改成了这个:
client.ServerCertificateValidationCallback = (s, c, h, e) => true; client.Connect("smtp.gmail.com", 587, SecureSocketOptions.StartTlsWhenAvailable);
所以在可用时使用 Tls 是很干净的。证书验证已关闭。它在 MailKit 2.0.7 中完美运行,但 2.1.3 中的相同代码继续在问题描述中抛出错误。不知道为什么。在所有最新版本(2.1.x)中可能有一些错误?
【讨论】:
从 MailKit 2.1.0 开始,MailKit 使用 SmtpClient.Timeout 值在超时期限到期后中止 Connect。默认情况下,此超时为2 * 60 * 1000
- 也许尝试将其设置为更大的值?或者尝试将其设置为-1
。【参考方案3】:
部分问题在于 SMTP 端口 587 不支持 SSL。您需要将false
作为useSsl
参数传递。
端口 587 使用 STARTTLS(如果可以,MailKit 会自动使用它)。
如果您想要更多控制,请使用采用SecureSocketOptions 枚举值的 Connect[Async] 方法。
使用带有布尔参数的 Connect[Async] 方法时,true
等效于 SecureSocketOptions.SslOnCOnnect
,false
等效于 SecureSOcketOptions.StartTlsWhenAvailable
。
不过,问题的主要部分似乎是 MailKit 较新的 Socket
连接代码中的错误。从 MailKit 2.1.x 开始,MailKit 开始使用 Socket.BeginConnect (string host, int port, ...)
而不是 Socket.Connect (IPAddress address, int port)
,从而允许底层 .NET 实现将主机名解析为适当的 IPAddress
本身并允许取消。不幸的是,这似乎对某些人造成了破坏(为什么?)。
我再次更新了 MailKit 以返回将主机名解析为 IP 地址列表(使用 Dns.GetHostAddresses[Async]
)并循环遍历每个 IPAddress
,直到它能够成功连接。此修复将在 MailKit >= 2.1.4 中可用。在那之前,您可以通过https://www.myget.org/feed/mimekit/package/nuget/MailKit的myget feed 安装
【讨论】:
实际上我尝试将其设置为false,但错误是相同的。尝试使用不同的 SecureSocketOptions 均未成功 你能写一个简单的程序,使用套接字连接到那个主机/端口吗?它有效吗?也许你有某种防火墙。该错误表明主机拒绝了您的连接。 尝试超时 -1。同样的错误。在问题的描述中,我描述了有 2 个项目并在同一台机器上启动它们 - 一个使用直接套接字连接到该主机/端口,另一个使用 MailKit。第一个工作没有任何问题,但 Mailkt v.2.1.x 没有。较低版本的 MailKit 也可以在不更改代码的情况下工作。所以连接性很好。 尝试转到myget.org/feed/mimekit/package/nuget/MailKit 并安装最新的 MailKit 版本 (>= 2.1.3.15)。我对 Connect 逻辑进行了一些更改,可能会解决这个问题? 请尝试 myget 构建,以便我知道是否可以为您解决问题。如果是这样,我将发布一个新版本,以便您可以升级到最新版本。如果没有人测试我的修复,我怎么知道它有效?【参考方案4】:我在 .NET 5.0 上使用 api 并且遇到了同样的问题。
Mailkit 版本:2.15.0
我测试了几个选项,下一个代码适合我:
public async Task SendEmailAsync(MailStructure mailStructure)
var email = new MimeMessage();
email.Sender = MailboxAddress.Parse(mailStructure.CorreoSMTP);
email.To.Add(MailboxAddress.Parse(mailStructure.Para));
email.Subject = "Notificación de pago Sireves";
var builder = new BodyBuilder();
email.Body = new TextPart(TextFormat.html)
Text = "prueba de correo mailkit"
;
using var smtp = new SmtpClient();
smtp.ServerCertificateValidationCallback = (s, c, h, e) => true;
smtp.Connect("smtp.gmail.com", 587, SecureSocketOptions.StartTlsWhenAvailable);
smtp.Authenticate(mailStructure.CorreoSMTP, mailStructure.PassSMTP);
await smtp.SendAsync(email);
smtp.Disconnect(true);
【讨论】:
【参考方案5】:Google 电子邮件帐户中有一项设置允许“不太安全”的应用程序登录并从 gmail 帐户发送 smtp,如果此设置不在应用程序上或尝试发送的计算机将被 google 阻止。
【讨论】:
以上是关于使用 .NET core 2.2 中的 MailKit SMTP 客户端通过 Gmail SMTP 发送邮件对我不起作用的主要内容,如果未能解决你的问题,请参考以下文章
ASP.NET Core 2.2 Razor 页面中的自定义路由
从 ASP.NET Core 2.2 更新 SQL Server 中的上下文
使用Http-Repl工具测试ASP.NET Core 2.2中的Web Api项目
使用 .NET core 2.2 中的 MailKit SMTP 客户端通过 Gmail SMTP 发送邮件对我不起作用