【问题标题】:How get email sent status in mailkit with asp.net core如何使用 asp.net core 在 mailkit 中获取电子邮件发送状态
【发布时间】:2019-02-12 10:37:03
【问题描述】:

我正在使用 mailkit 在 asp.net core 2.0 中实现电子邮件服务器。关于我的场景,我必须发送电子邮件并且需要返回带有电子邮件发送状态的反馈。我已经实现了电子邮件发送部分并且工作正常。

我知道 try catch 是一种选择。但我的情况还不够。因为只有在网络错误或认证失败时才会发生异常。但是,如果某些接收方电子邮件无效,则不会发生异常。

我必须返回列表中每封电子邮件的电子邮件发送状态。但是如果有无效的电子邮件或其他错误,我无法捕捉到它。

我看到了一个名为 MessageSent 的事件。但我不知道要实现那个事件,也不知道它是否符合我的条件。

这是我的完整代码。

  public void SendEmail(List<EmailMessage> emailMessages)
        {
            List<MimeMessage> emailQueue = new List<MimeMessage>();
            foreach (EmailMessage emailMessage in emailMessages)
            {
                var message = new MimeMessage();
                message.MessageId = emailMessage.MessageId;
                message.To.AddRange(emailMessage.ToAddresses.Select(x => new MailboxAddress(x.Name, x.Address)));
                message.From.AddRange(emailMessage.FromAddresses.Select(x => new MailboxAddress(x.Name, x.Address)));

                message.Subject = emailMessage.Subject;
               
                message.Body = new TextPart(TextFormat.Html)
                {
                    Text = emailMessage.Content
                };

                emailQueue.Add(message);
            }
           
            using (var emailClient = new SmtpClient())
            {                   
                emailClient.Connect(_emailConfiguration.SmtpServer, _emailConfiguration.SmtpPort, _emailConfiguration.EnableSSL);
               
                emailClient.AuthenticationMechanisms.Remove("XOAUTH2");

                emailClient.Authenticate(_emailConfiguration.SmtpUsername, _emailConfiguration.SmtpPassword);
                foreach (MimeMessage email in emailQueue)
                {
                    try
                    {
                         emailClient.Send(email);
                       
                    }
                    catch (Exception ex)
                    {
                        
                    }                       
                }
                emailClient.Disconnect(true);
            }
        }      

【问题讨论】:

  • 我认为 foreach 循环内的 try-catch 块只会增加不必要的开销。 “找不到地址”错误很可能是因为您发送到了错误的地址,而不是没有发送
  • @JohanHerstad 有什么方法可以获取电子邮件接收状态..?因为我必须返回每封电子邮件的状态。

标签: asp.net-core smtpclient mailkit


【解决方案1】:

您需要重写 GetDeliveryStatusNotifications 类,如下所示:

using MailKit;
using MailKit.Net.Smtp;
using MimeKit;
using System;
using System.Collections.Generic;

namespace YourProject    
{
    public class CustomSmtpClient : SmtpClient
    {
        protected override DeliveryStatusNotification? GetDeliveryStatusNotifications(MimeMessage message, MailboxAddress mailbox)
        {
            if (!(message.Body is MultipartReport report) || report.ReportType == null || !report.ReportType.Equals("delivery-status", StringComparison.OrdinalIgnoreCase))
                return default;
            report.OfType<MessageDeliveryStatus>().ToList().ForEach(x => {
                x.StatusGroups.Where(y => y.Contains("Action") && y.Contains("Final-Recipient")).ToList().ForEach(z => {
                    switch (z["Action"])
                    {
                        case "failed":
                            Console.WriteLine("Delivery of message {0} failed for {1}", z["Action"], z["Final-Recipient"]);
                            break;
                        case "delayed":
                            Console.WriteLine("Delivery of message {0} has been delayed for {1}", z["Action"], z["Final-Recipient"]);
                            break;
                        case "delivered":
                            Console.WriteLine("Delivery of message {0} has been delivered to {1}", z["Action"], z["Final-Recipient"]);
                            break;
                        case "relayed":
                            Console.WriteLine("Delivery of message {0} has been relayed for {1}", z["Action"], z["Final-Recipient"]);
                            break;
                        case "expanded":
                            Console.WriteLine("Delivery of message {0} has been delivered to {1} and relayed to the the expanded recipients", z["Action"], z["Final-Recipient"]);
                            break;
                    }
                });
            });
            return default;
        }
    }
}

【讨论】:

    【解决方案2】:

    这里对MailKit的MessageSent有很好的解释-https://stackoverflow.com/a/48132905/1105937

    TLDR:使用 try/catch,因为它会告诉您消息是否已发送..

    var IsEmailSent = false;
    
    try
    {
        emailClient.Send(email);
        IsEmailSent = true;
    }
    catch (Exception ex)
    {
    
    }  
    

    由于隐私问题,您无法判断用户的电子邮件地址是否不存在,但发送电子邮件的人会收到任何退回邮件。

    如果您使用通用电子邮件地址(如 do-not-reply@my-cool-app.com)发送所有电子邮件,则将应用用户(发送电子邮件的人)添加为“回复”电子邮件,以便他们将收到任何反弹的副本。

    【讨论】:

    • 其他链接的答案根本没有解释如何获取消息的发送状态。
    • @cdonner "虽然,是的,MessageSentEventArgs.Response 属性包含服务器发送的实际响应,但它不太可能告诉您收件人电子邮件地址是否实际存在。 "
    【解决方案3】:

    我们可以像这样得到MessageSent。它确认电子邮件是通过smtp服务发送的。但它没有返回电子邮件接收状态。

    例如:我的 smtp 服务器是 gmail,我正在向 yahoo 电子邮件地址发送电子邮件。使用 MessageSent 我们可以确认电子邮件是从 smtp gmail 客户端发送的。但是我们无法获取 yahoo 电子邮件的接收状态。

                    foreach (MimeMessage email in emailQueue)
                    {
                        try
                        {                      
                            emailClient.MessageSent += OnMessageSent;   
                            emailClient.Send(email);                    
                        }
                        catch (Exception ex)
                        {
                        }
        }
    ------------------------------------------------------------------------------     
            void OnMessageSent(object sender, MessageSentEventArgs e)
            {
                Console.WriteLine("The message was sent!");
              
            }

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-12-15
      • 1970-01-01
      • 2023-03-18
      • 1970-01-01
      • 1970-01-01
      • 2019-11-23
      • 2019-10-14
      • 2021-01-30
      相关资源
      最近更新 更多