我有此代码已成功发送电子邮件-除了前一天没有发送电子邮件。因此,我想检查SMTP响应,但不确定该怎么做。
现在是我的代码:
using (var client = new SmtpClient())
{
client.LocalDomain = "xxxxxxxxxxxx";
await client.ConnectAsync("xxxxxxxxxxxx", xx, SecureSocketOptions.StartTls).ConfigureAwait(false);
await client.AuthenticateAsync( new System.Net.NetworkCredential("xxxxxxxxxxxx", "xxxxxxxxxxxx")).ConfigureAwait(false);
await client.SendAsync(emailMessage).ConfigureAwait(false);
await client.DisconnectAsync(true).ConfigureAwait(false);
}
Run Code Online (Sandbox Code Playgroud)
因此,我在这里阅读了onMessageSent,或者可以使用MessageSent函数来查看是否有响应-我真的很想看一个示例代码,但是如何在代码中使用这些函数来确定消息是否为真的收到了吗?
我确实具有包含作为的异步发送功能的函数public void,并且警告抑制消除了有关未等待呼叫的VisualStudio投诉。
public void SendEmail(string HtmlEmailContents, string SubjectLine, string CustomFromAddress = null, string CustomEmailRecipients = null)
{
string To = getRecipientString(mainRecipients);
string Cc = getRecipientString(ccRecipients);
string Bcc = getRecipientString(bccRecipients);
if(CustomEmailRecipients != null && CustomEmailRecipients != "")
{
To = CustomEmailRecipients;
Cc = "";
Bcc = "";
}
string finalizedFromAddress;
if(CustomFromAddress != null)
{
finalizedFromAddress = CustomFromAddress;
}
else
{
finalizedFromAddress = FromAddress;
}
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
MessageServices.SendEmailAsync(
To,
finalizedFromAddress,
Cc,
Bcc,
SubjectLine,
HtmlEmailContents
);
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
}
Run Code Online (Sandbox Code Playgroud)
[新编辑]:因此,让我们想象一下,我整理了整个异步内容,现在是时候真正捕获那些错误消息了。在这里,我已阅读到MessageSent和OnMessageSent函数可用于查看结果。当然,我无法弄清楚。我在这里寻找一些示例,可以使用MailKit进行镜像。在那里,该行client.SendCompleted += new SendCompletedEventHandler(SendCompletedCallback);似乎抓住了关键,我想知道是否在我的代码中使用client.MessageSent += ???MailKit中的对应项。
@mason似乎已就滥用异步问题回答了原始问题。
因此,现在回答您的新问题。
该MessageSent事件就像是在.NET中的任何其他事件,可以听取了以下方法:
client.MessageSent += OnMessageSent;
Run Code Online (Sandbox Code Playgroud)
该OnMessageSent方法是这样的:
void OnMessageSent (object sender, MessageSentEventArgs e)
{
Console.WriteLine ("The message was sent!");
}
Run Code Online (Sandbox Code Playgroud)
但是,您想收听此事件的原因似乎是对它真正为您提供的信息的误解。
是的,虽然MessageSentEventArgs.Response属性包含服务器发送的实际响应,但是不太可能告诉您收件人电子邮件地址是否实际存在。
如果您正在将邮件发送到不存在的电子邮件地址,SmtpClient.Send()或者SendAsync()没有引发异常,则意味着SMTP服务器在收到RCPT TOMailKit发送的命令时很可能不验证电子邮件地址是否存在,并且会很乐意接受没有错误的消息提交,这意味着MailKit将不会引发任何异常。许多SMTP服务器这样做有两个原因:
VRFYand EXPN命令的相同原因)。例如,如果您连接到smtp.gmail.com以向另一域上的用户发送消息,则smtp.gmail.com无法知道user@another-domain.com在实际存在之前不存在尝试将邮件转发到例如smtp.another-domain.com。
如果您实际上想获得有关电子邮件地址是否实际存在的反馈,则此过程将需要您付出更多的努力,并需要一些运气。
首先,您需要希望并祈祷您的SMTP服务器支持DSN(传递状态通知)扩展。
要检查服务器是否支持此功能,可以检查SmtpClient.Capabilities:
if (client.Capabilities.HasFlag (SmtpCapability.Dsn)) {
...
}
Run Code Online (Sandbox Code Playgroud)
假设你的服务器支持DSN扩展,接下来你需要继承SmtpClient,这样就可以覆盖,以提供MailKit的SmtpClient一些必要的信息/选项的一些方法。
这些方法是:
这两种方法的文档已经提供了以下代码片段,但为了后代,我将其粘贴在此处:
public class DSNSmtpClient : SmtpClient
{
public DSNSmtpClient ()
{
}
/// <summary>
/// Get the envelope identifier to be used with delivery status notifications.
/// </summary>
/// <remarks>
/// <para>The envelope identifier, if non-empty, is useful in determining which message
/// a delivery status notification was issued for.</para>
/// <para>The envelope identifier should be unique and may be up to 100 characters in
/// length, but must consist only of printable ASCII characters and no white space.</para>
/// <para>For more information, see rfc3461, section 4.4.</para>
/// </remarks>
/// <returns>The envelope identifier.</returns>
/// <param name="message">The message.</param>
protected override string GetEnvelopeId (MimeMessage message)
{
// Since you will want to be able to map whatever identifier you return here to the
// message, the obvious identifier to use is probably the Message-Id value.
return message.MessageId;
}
/// <summary>
/// Get the types of delivery status notification desired for the specified recipient mailbox.
/// </summary>
/// <remarks>
/// Gets the types of delivery status notification desired for the specified recipient mailbox.
/// </remarks>
/// <returns>The desired delivery status notification type.</returns>
/// <param name="message">The message being sent.</param>
/// <param name="mailbox">The mailbox.</param>
protected override DeliveryStatusNotification? GetDeliveryStatusNotifications (MimeMessage message, MailboxAddress mailbox)
{
// In this example, we only want to be notified of failures to deliver to a mailbox.
// If you also want to be notified of delays or successful deliveries, simply bitwise-or
// whatever combination of flags you want to be notified about.
return DeliveryStatusNotification.Failure;
}
}
Run Code Online (Sandbox Code Playgroud)
好的,既然您已完成上述操作,这将要求SMTP服务器在服务器无法将邮件传递给任何收件人时/向其发送电子邮件。
现在您可以处理收到的电子邮件了...
当你收到这些消息之一,它将有一个顶级Content-Type的multipart/report; report-type="delivery-status"将由一个代表MultipartReport
检测这种情况的方法是:
var report = message.Body as MultipartReport;
if (report != null && report.ReportType != null && report.ReportType.Equals ("delivery-status", StringComparison.OrdinalIgnoreCase)) {
...
}
Run Code Online (Sandbox Code Playgroud)
那么你需要做的是一个定位的MIME部(S)Content-Type的message/delivery-status属于儿童multipart/report(每将由表示MessageDeliveryStatus):
foreach (var mds in report.OfType<MessageDeliveryStatus> ()) {
...
}
Run Code Online (Sandbox Code Playgroud)
然后,您需要检查StatusGroups以提取所需的信息。该StatusGroups属性HeaderListCollection本质上是a键值对列表的列表。
要弄清楚什么键可用,你需要在阅读第2.2和第2.3节的rfc3464。
至少,您需要"Original-Envelope-Id"在第一个StatusGroup中检查,才能弄清楚该报告所针对的消息(此信封ID字符串将与您返回的字符串匹配GetEnvelopeId)。
var envelopeId = mds.StatusGroups[0]["Original-Envelope-Id"];
Run Code Online (Sandbox Code Playgroud)
在以下每个StatusGroups中,您需要获取的值"Original-Recipient"(如果已设置,否则我想您可以检查"Final-Recipient")。这将是形式rfc822;user@domain.com-因此只需将';'字符拆分并使用第二个字符串即可。
最后,您将需要检查该"Action"值以了解所述接收者的状态。在您的情况下,如果值为"failed",则表示传送失败。
for (int i = 1; i < mds.StatusGroups.Length; i++) {
var recipient = mds.StatusGroups[i]["Original-Recipient"];
var action = mds.StatusGroups[i]["Action"];
if (recipient == null)
recipient = mds.StatusGroups[i]["Final-Recipient"];
var values = recipient.Split (';');
var emailAddress = values[1];
...
}
Run Code Online (Sandbox Code Playgroud)
如果将所有内容放在一起,则会得到以下内容:
public void ProcessDeliveryStatusNotification (MimeMessage message)
{
var report = message.Body as MultipartReport;
if (report == null || report.ReportType == null || !report.ReportType.Equals ("delivery-status", StringComparison.OrdinalIgnoreCase)) {
// this is not a delivery status notification message...
return;
}
// process the report
foreach (var mds in report.OfType<MessageDeliveryStatus> ()) {
// process the status groups - each status group represents a different recipient
// The first status group contains information about the message
var envelopeId = mds.StatusGroups[0]["Original-Envelope-Id"];
// all of the other status groups contain per-recipient information
for (int i = 1; i < mds.StatusGroups.Length; i++) {
var recipient = mds.StatusGroups[i]["Original-Recipient"];
var action = mds.StatusGroups[i]["Action"];
if (recipient == null)
recipient = mds.StatusGroups[i]["Final-Recipient"];
// the recipient string should be in the form: "rfc822;user@domain.com"
var index = recipient.IndexOf (';');
var address = recipient.Substring (index + 1);
switch (action) {
case "failed":
Console.WriteLine ("Delivery of message {0} failed for {1}", envelopeId, address);
break;
case "delayed":
Console.WriteLine ("Delivery of message {0} has been delayed for {1}", envelopeId, address);
break;
case "delivered":
Console.WriteLine ("Delivery of message {0} has been delivered to {1}", envelopeId, address);
break;
case "relayed":
Console.WriteLine ("Delivery of message {0} has been relayed for {1}", envelopeId, address);
break;
case "expanded":
Console.WriteLine ("Delivery of message {0} has been delivered to {1} and relayed to the the expanded recipients", envelopeId, address);
break;
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
1453 次 |
| 最近记录: |