.NET SmtpClient: Is there a way to make sure that all emails resolve prior to sending MailMessage?
Asked Answered
I

2

6

I am using SmtpClient to send an email to multiple recipients. As employees leave the company, their email addresses become invalid. Since their email addresses remain in our database until deleted manually, trying to send an email to them causes our application to throw an exception during SmtpClient.Send(MailMessage). However, in spite of the exception being thrown, it still sends the email. This is a problem because we want to handle this error by blocking the user's attempt to save the record and display a friendly message advising to delete any invalid associates from the database.

If there were a way to iterate through all the recipeients to make sure they're all valid, we can keep all emails from being sent until the user satisifes a set of conditions.

Imhoff answered 7/11, 2012 at 16:31 Comment(2)
Depends how thorough you need to be - you might need to look at a third party component like EmailVerify.NET.Lecturer
You mentioned that these are employees. Do you use an Exchange Server for your email or Active Directory for Identity? Are all emails to be checked those of employees? One option would be to iterate through the addesses prior to sending and checking for account status in AD or pass validation through EWS.Mcgovern
C
7

Its a very old question, I don't know if you have got it solved.

As per MSDN: http://msdn.microsoft.com/en-us/library/swas0fwc(v=vs.100).aspx

When sending e-mail using Send to multiple recipients and the SMTP server accepts some recipients as valid and rejects others, Send sends e-mail to the accepted recipients and then a SmtpFailedRecipientsException is thrown. The exception will contain a listing of the recipients that were rejected.

This is an example of catching this exception taken from MSDN:

try {
    client.Send(message);
}
catch (SmtpFailedRecipientsException ex) {
    for (int i = 0; i < ex.InnerExceptions.Length; i++) {
        SmtpStatusCode status = ex.InnerExceptions[i].StatusCode;
        if (status == SmtpStatusCode.MailboxBusy || status == SmtpStatusCode.MailboxUnavailable) {
            Console.WriteLine("Delivery failed - retrying in 5 seconds.");
            System.Threading.Thread.Sleep(5000);
            client.Send(message);
        } 
        else {
            Console.WriteLine("Failed to deliver message to {0}", ex.InnerExceptions[i].FailedRecipient);
        }
    }
}

Complete example here: http://msdn.microsoft.com/en-us/library/system.net.mail.smtpfailedrecipientsexception.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-2

Internally the Send uses the statuscode returned from RCPT TO command to raise the appropriate exception.

Check the implementation for PrepareCommand in the RecipientCommand.Send method of smtpTransport.SendMail (This method is called internally by SmtpClient.Send). It uses RCPT TO to get the StatusCode which is then parsed in the CheckResponse method and accordingly the SmtpFailedRecipientsException is raised. However, VRFY and RCPT both are not very reliable because the mail servers tend to delay (throttle NDR) or swallow the response as an anti-spam measure.

Cattery answered 1/8, 2013 at 20:1 Comment(3)
I am stymied here. All of a sudden, an exception is no longer being thrown. Back when I originally wrote this question, exceptions were being thrown, but now Exchange Server just sends out an email stating that it couldn't deliver to specific recipients. Do you know what could have possibly changed?Imhoff
@Imhoff I just tested it against my Server, and it works just fine. Am able to catch the SmtpFailedRecipientsException. Please check your Exchange environment if recipient filtering settings have been changed. There are two settings to look for: (1) SMTP Tarpitting: Tarpitting will delay the "5.1.1 User Unkown" response. It is possible that tarpitting is causing a timeout to send in your code. (2) Recipient Filtering: if RecipientValidationEnabled is set to false then the server will respond "2.1.5 Recipient OK" but will still generate NDR. Exception not raised.Cattery
If all you want is to check the existence of a recipient to block the user immediately, you may want to first check against the AD. If the user is available in AD, then only proceed with your mailing code. UserPrincipal.FindByIdentity will be your friend here.Cattery
D
2

Have a look at the following: How to check if an email address exists without sending an email?

What you want to do is check that the e-mails exist before continuing to send.

Therefore, as is stated in the linked answer, try to see if VRFY or RCPT are supported by your company mail server.

Quoting:

You can connect to the server, and issue a VRFY command. Very few servers support this command, but it is intended for exactly this. If the server responds with a 2.0.0 DSN, the user exists.

VRFY user

You can issue a RCPT, and see if the mail is rejected.

MAIL FROM:<>

RCPT TO:

Determined answered 5/8, 2013 at 23:8 Comment(7)
+1 I've never tried that before but it really looks very interesting!Meso
This is exactly what SmtpClient.Send does internally. Check the implementation for PrepareCommand in the RecipientCommand.Send method of smtpTransport.SendMail (This method is called internally by SmtpClient.Send). It uses RCPT TO to get the StatusCode which is then parsed in the CheckResponse method and accordingly the SmtpFailedRecipientsException is raised. However, VRFY and RCPT both are not very reliable because the mail servers tend to delay (throttle NDR) or swallow the response as an anti-spam measure.Cattery
thanks @abhitalks so what could be a reliable solution? or at least a workaround? any ideas?Meso
Sadly there is none. The closest is catching the exception in Send. We cannot force any mail server to respond immediately (or even respond). Anti-spam measures are a necessary inconvenience :)Cattery
@abhitalks, if SmtpClient already does this, then why sending to an invalid address doesn't throw an exception? https://mcmap.net/q/1774328/-capture-smtp-errors-in-netOrderly
@ArturoTorresSánchez: The accepted answer on the question you linked to, and my answer and comments below already answer this question of yours! "Store and forward" is one reason. More importantly in modern times nearly all mail servers employ tarpitting and delayed NDR, and always immediately respond ok.Cattery
@abhitalks, I'm sorry, I still don't follow. I will open a new question.Orderly

© 2022 - 2024 — McMap. All rights reserved.