1

目前我正在通过 SMTP 发送邮件 代码如下

SmtpClient client = new SmtpClient();
client.DeliveryMethod = SmtpDeliveryMethod.Network;
//client.EnableSsl = true;
client.Send(msg);

我必须使用代码检查邮件已投递或未使用 smtp 异常的投递状态

4

2 回答 2

3

虽然@Chase 在技术上是正确的,但如果沿途的 SMTP 服务器支持此扩展,则可以获得传递状态通知

我不知道使用 System.Net.Mail 执行此操作的方法,但使用MailKit,您实际上可以为您的收件人请求传递状态通知。

在 MailKit 中,您需要做的第一件事(直到我为此找到更好的 API)是设置您自己的 SmtpClient 类,如下所示:

class MySmtpClient : SmtpClient
{
    public MySmtpClient ()
    {
    }

    /// <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)
    {
        // The Message-Id header is probably the easiest way to go...
        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)
    {
        // Since you want to know whether the message got delivered or not,
        // you'll probably want to get notifications for Success and Failure.
        return DeliveryStatusNotification.Success | DeliveryStatusNotification.Failure;
    }
}

然后,一旦你有了它,你会像这样使用它:

using (var client = new MySmtpClient ()) {
    client.Connect ("smtp.gmail.com", 465, true);
    client.Authenticate ("username", "password");
    client.Send (message);
    client.Disconnect (true);
}

现在发生的情况是,每当有成功或失败通知时,您都会收到一封电子邮件发送到您帐户的收件箱(POP3 或 IMAP,具体取决于您使用的内容),其中包含一个multipart/reportMIME 部分,该部分通常包含 3 个其他 MIME 部分: 一个人类可读的解释,一个message/delivery-statusMIME 部分,它有一个包含一些键/值对的主体和一个包含原始消息(或有时只是标题)的第三部分。

目前,MailKit 没有用于处理message/delivery-statusMIME 部分的特殊 MIME 类,但您可以通过解析如下内容来解决此问题:

var mds = message.BodyParts.OfType<MimePart>.Where (x => x.ContentType.Matches ("message", "delivery-status")).FirstOrDefault ();
if (mds != null) {
    using (var memory = new MemoryStream ()) {
        mds.ContentObject.DecodeTo (memory);
        memory.Position = 0;

        // the content of a message/delivery-status MIME part is a
        // collection of header groups. The first group of headers
        // will contain the per-message status headers while each
        // group after that will contain status headers for a
        // particular recipient.
        var groups = new List<HeaderList> ();
        while (memory.Position < memory.Length)
            groups.Add (HeaderList.Load (memory));

        // TODO: take a look at the specific "headers" to get the info we 
        // care about. For more info on what these header field names and
        // values are, take a look at https://tools.ietf.org/html/rfc3464
    }
}

更新:我已经向 MimeKit 添加了一个 MessageDeliveryStatus 类,它为您处理解析 MIME 部分的内容,但由于我2 天前刚刚message/delivery-status发布了一个版本,因此我可能需要长达 2 周的时间才能发布另一个版本。当我发布它时,期望在 MimeKit 1.2.8 中找到这个新类。

于 2015-07-06T13:13:09.037 回答
1

你不能检查它。因为您使用SMTP,所以无法判断传递是否成功。邮件在传递时被路由。一些有用的技巧是在发送之前验证电子邮件地址是否有效,并将单个无回复地址设置为实际收件箱,然后使用POP3进入电子邮件帐户并查找退回邮件。 详细说明 SMTP 的工作原理

于 2015-07-04T12:38:08.527 回答