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.

oscilatingcretin
  • 10,457
  • 39
  • 119
  • 206
  • 1
    Depends how thorough you need to be - you might need to look at a third party component like [EmailVerify.NET](http://cobisi.com/email-validation/.net-component). – Bridge Nov 07 '12 at 16:37
  • 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. – randcd Aug 08 '13 at 16:21

2 Answers2

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.

Abhitalks
  • 27,721
  • 5
  • 58
  • 81
  • 1
    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? – oscilatingcretin Aug 09 '13 at 12:56
  • 1
    @oscilatingcretin 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. – Abhitalks Aug 09 '13 at 14:40
  • 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. – Abhitalks Aug 09 '13 at 14:49
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:

Community
  • 1
  • 1
Menelaos
  • 23,508
  • 18
  • 90
  • 155
  • +1 I've never tried that before but it really looks very interesting! – pedrommuller Aug 08 '13 at 05:34
  • 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. – Abhitalks Aug 08 '13 at 13:22
  • thanks @abhitalks so what could be a reliable solution? or at least a workaround? any ideas? – pedrommuller Aug 08 '13 at 14:42
  • 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 :) – Abhitalks Aug 08 '13 at 14:55
  • @abhitalks, if SmtpClient already does this, then why sending to an invalid address doesn't throw an exception? http://stackoverflow.com/questions/5052282/capture-smtp-errors-in-net – Arturo Torres Sánchez Dec 18 '14 at 23:40
  • @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`. – Abhitalks Dec 19 '14 at 04:06
  • @abhitalks, I'm sorry, I still don't follow. I will open a new question. – Arturo Torres Sánchez Dec 19 '14 at 06:12