Isanka Thalagala
Isanka Thalagala

Reputation: 1731

How get email sent status in mailkit with asp.net core

I'm implementing email server in asp.net core 2.0 with mailkit. About my scenario, I have to send email and need to return feedback with the email sent status.I have implemented email send part and it's working fine.

I know try catch is a one option.But it's not enough with my situation. Because exception will be occurred only when network error or authentication failure. But exception won't occur if some receiver email is invalid. enter image description here

I have to return email sent status for each email in List.But If there is invalid email or another error I can't catch it.

I saw a event called MessageSent. But I don't know to implement that event and whether it's match with my condition.

enter image description here

This is my full code.

  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);
            }
        }      

Upvotes: 2

Views: 7314

Answers (3)

KakashiJack
KakashiJack

Reputation: 161

You need override the GetDeliveryStatusNotifications class, something like this:

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;
        }
    }
}

Upvotes: 2

Isanka Thalagala
Isanka Thalagala

Reputation: 1731

We can get MessageSent like this.It's confirm email is send by smtp service.But it's not returning email receive status.

Eg: my smtp server is gmail and i'm sending email to yahoo email address. Using MessageSent we can confirm that email is dispatch from smtp gmail client.But we can't get the received status of yahoo email.

                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!");
          
        }

Upvotes: -2

MWD
MWD

Reputation: 1642

There is a good explanation of MailKit's MessageSent here - https://stackoverflow.com/a/48132905/1105937

TLDR: Use the try/catch as that will tell you if the message was sent or not..

var IsEmailSent = false;

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

}  

You won't be able to tell if the users email address does not exist for privacy issues, but the person who sent the email will get any bounce back messages.

If you send out all the emails using a generic email address like [email protected] then add the app user (the person sending the email) as a "reply to" email so they will recieve a copy of any bounce backs as they occur.

Upvotes: 1

Related Questions