c# - MailKit - SmtpClient Connect 方法冻结
问题描述
我正在开发一个 Xamarin android 应用程序,在某些时候(成功交易后)该应用程序必须向客户发送信息电子邮件。创建 MimeMessage 实例以及实际发送它的整个过程是通过一个任务完成的。消息(大多数情况下包含链接图像)是完美创建的,但是一旦我调用一个方法来实际发送它,执行就会在那个调用处冻结,整个任务仍然处于活动状态,但在那个时候被冻结。
这是我的SendMail
方法,除了MimeMessage
参数之外,它还接收一个 MailAccount 类,其中包含有关 smtp 机器、端口和发件人帐户的信息。一旦调用Connect
MailKitSmtpClient
实例的方法,我就会遇到我描述的“冻结”行为。我尝试了很多次——甚至没有一次代码超出了那条线。
private static int SendMail(MailAccount account, MimeMessage message)
{
using (var client = new SmtpClient())
{
try
{
client.Connect(account.Server, account.Port, false);
}
catch (SmtpCommandException)
{
return -1;
}
catch (SmtpProtocolException)
{
return -2;
}
client.AuthenticationMechanisms.Remove("XOAUTH2");
if (client.Capabilities.HasFlag(SmtpCapabilities.Authentication))
{
try
{
client.Authenticate(account.User, Decrypt(account.Pass));
}
catch (AuthenticationException)
{
return -3;
}
catch (SmtpCommandException)
{
return -1;
}
catch (SmtpProtocolException)
{
return -2;
}
}
int status = 1; //assume success
try
{
client.Send(message);
}
catch (SmtpCommandException ex)
{
switch (ex.ErrorCode)
{
case SmtpErrorCode.MessageNotAccepted:
status = -6;
break;
case SmtpErrorCode.SenderNotAccepted:
status = -5;
break;
case SmtpErrorCode.RecipientNotAccepted:
status = -4;
break;
default:
status = -7;
break;
}
}
client.Disconnect(true);
return status;
}
}
解决方案
通常,呼叫挂起client.Connect
表明您尝试连接的主机或端口不可用。检查主机和端口是否正确。
如果它们是正确的,请确保您使用的是 MailKit 的最新版本,因为Socket.BeginConnect (string, int ...)
在支持 IPv6 的操作系统上,这些旧版本有时会尝试在 IPv6 上使用 IPv4 并在某些情况下挂起(例如当病毒扫描程序像使用了 Avast)。
MailKit 的较新版本(>= 2.1.4 和 2.0 之前的版本)对远程主机进行 DNS 查找,并在实例化 Socket(IPv4 与 IPv6)时手动指定要使用的正确地址族,以避免此问题。
挂起也可能是由 SSL/TLS 证书吊销检查与无响应的证书颁发机构进行的。您可以使用以下代码段禁用证书吊销检查:
client.CheckCertificateRevocation = false;
只需确保在调用Connect
.
通过在 Visual Studio 中创建一个新的控制台应用程序并粘贴以下代码并检查它是否有效,可能值得测试对 SMTP 服务器的访问:
using System;
using System.Threading;
using System.Threading.Tasks;
using MailKit;
using MailKit.Net.Smtp;
namespace ConsoleApp {
public class Program
{
static void Main (string[] args)
{
using (var client = new SmtpClient (new ProtocolLogger ("smtp.log"))) {
using (var cts = new CancellationTokenSource (60000)) {
try {
client.Connect ("your-host.com", 25, false, cts.Token);
client.Disconnect (true);
} catch (Exception ex) {
Console.WriteLine ("Error connecting: {0}", ex.Message);
Console.WriteLine (ex.StackTrace);
}
}
}
}
}
}
smtp.gmail.com
了解您的 Android 应用程序是否在连接到端口465
( useSsl = true
)时遇到问题也会很有趣。
推荐阅读
- python - 导入模块所需的模块
- jquery - 菜单项和内容问题
- css - 日期的宽度不一样,因为数字 1 和 2 的宽度不同?
- android - 使用 FirebaseJobDispatcher
- javascript - 从由 javascript 函数创建的表单提交 FormData 到 php
- elasticsearch - Elasticsearch 查询错误 - [或] 查询格式错误,查询名称后没有 start_object
- math - 飞镖乘法
- vb.net - 如果父列或子列不在数据集中,则无法创建 DataRelation
- python - Python-Tkinter:TypeError:“NoneType”对象不可下标
- python - 在 MACOS 上安装 NLTK