none
smtpClient and MailMessage classes and error 451 RRS feed

  • Question

  • I have found out how to deal with this problem but am curious as to why.

    I have an application (my own customer tracking system) whereby I periodically send automated emails to my customers and this has been working for years. Recently I came across a situation where trying to send a message to a particular customer the smtpClient.Send(MailMesage) statement is throwing an exception whose message is "Error in processing. The server response was: Temporary local problem - please try later".  Incidentally, manually sending to this recipient with Outlook gets a response which says "Server error: '451 Temporary local problem - please try later'" and I wonder where the '451' came from and whether it is available somewhere in the caught exception.

    At this point in time, any attempt to proceed through the list of emails to send, produces the same exception. That is, all subsequent email address get the same exception. I figured that I could create a new smtpClient and proceed, but the same exception is thrown.  I then discovered that if I generated a new MailMessage object to work with I could proceed through the list.  Is there anything (short of just creating a new one) that I could reset on the MailMessage object that would let me proceed? 

    I really don’t understand why it is the MailMessage object that needs resetting and not the smtpClient object.

    VS2008 and .Net 2.0


    Terry


    • Edited by TerryLa Wednesday, December 21, 2016 7:02 PM
    Wednesday, December 21, 2016 6:55 PM

Answers

  • Well, to get the SMTP status, you can catch SmtpException instead of Exception. That will give you access to the .StatusCode property.

                Try
                    objSMTPClient.Send(objMessage)
                    id = CType(dr(5), Integer)
                    Subscription.EmailDone(id)
                    count += 1
                    ClientMsgCount += 1
                Catch smtpex As SmtpException
                    MessageBox.Show("Error occured sending e-mail. For SubId = " + dr(0).ToString + _
                                    Environment.NewLine + Environment.NewLine + _
                                    smtpex.StatusCode.ToString + ": " + smtpex.Message)
                    objMessage = Nothing
                    Continue For
                Catch ex As Exception
                    MessageBox.Show("Error occured sending e-mail. For SubId =" + dr(0).ToString + _
                                    Environment.NewLine + Environment.NewLine + _
                                    ex.Message)
                    objMessage = Nothing
                    Continue For
                End Try

    As for why objMessage = Nothing is required in your code, it's solely because your code only keep adding address to .To without clearing it first. So when .NET runtime attempt to send email again, the first email address it see is still the address that cannot be sent.

    Calling objMessage.To.Clear() just before objMessage.To.Add() should be enough to fix it.


    • Edited by cheong00Editor Thursday, December 22, 2016 3:21 PM
    • Marked as answer by TerryLa Thursday, December 22, 2016 5:53 PM
    Thursday, December 22, 2016 2:49 PM
    Answerer

All replies

  • Hi Terry,

    >>I then discovered that if I generated a new MailMessage object to work with I could proceed through the list. 

    Do you mean you recreated a new MailMessage object to solve it? If yes,  I am afraid these are the same. It doesn't make sense.

    System.Net.Mail.MailMessage mail = new System.Net.Mail.MailMessage();
                 mail.To.Add("hjuhhh@gmail.com");
                 mail.From = new MailAddress("fdjhdjjj@gmail.com", "Emailhead", System.Text.Encoding.UTF8);
                 mail.Subject = "This mail is send from asp.net application";
                 mail.SubjectEncoding = System.Text.Encoding.UTF8;
                 mail.Body = "This is Email Body Text";
                 mail.BodyEncoding = System.Text.Encoding.UTF8;
                 mail.IsBodyHtml = true;
                 mail.Priority = MailPriority.High;

    Here I also searched a similar thread,

    “Server response: 451 451 Temporary local - please try later” when sending email using Mailgun, Laravel and VirtualBox

    From Poul's reply, Since this error message is so vague, you'll need to get more information from the recipient. I'd suggest waiting a few hours and try to send the email again.

    May be you don't do anything, just because the recipients server being overloaded with messages and you have to wait for a long time, then it works well.

    If I misunderstand you, please feel free to let me know.

    Best regards,

    Kristin


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    • Proposed as answer by cheong00Editor Thursday, December 22, 2016 2:28 AM
    Thursday, December 22, 2016 1:42 AM
  • You can check what the SMTP error code means here.

    Note that error code 4.5.1 can either mean there is problem on your connection to your first relay, or your messages are blocked by antispam filter. Since you've tried switch SMTP server, I suspect the problem is in your mail speed.

    If your original code is sending mail on tight loop, I suggest adding artificial delay between messages - say 5 minutes for every 50 mails be sent to the same domain, note some antispam filters are more sensitive than that especially if the target server is owned by small company with few employee. I've seen mail server that will block email if received more than 5 mails per hour from same host unless the mail server is on whitelist of major mail server provider - and see if it remedies your problem.


    Thursday, December 22, 2016 2:36 AM
    Answerer
  • Hi Kristin,

    I have included a snippet below.  Note that w/o the objMessaage = Nothing statement, any attempt to continue processing more recipients causes the same exception.   So something is being persisted on the MailMessage object. This has nothing to do with a temporary block by my ISP since creating a new MailMessage object to work with, lets me continue.  Also the "451" came from trying to send manually with outlook.  The ex.Message does not reference 451.  Is there some other property in the exception object where I could find the 451?

        Private Function DoEmails() As Integer
            Dim count As Integer = 0
            Dim ClientMsgCount As Integer = 0
            Dim id As Integer = 0
            Dim objSMTPClient As SmtpClient = Nothing
            Dim objMessage As MailMessage = Nothing
    
            For Each dr As DataRow In eNotices.Rows
    
                If objMessage Is Nothing Then
                    objMessage = New MailMessage
                    With objMessage
                        .DeliveryNotificationOptions = DeliveryNotificationOptions.OnFailure
                        .Priority = MailPriority.High
                        .From = New MailAddress("Support@MyDomain.com", "MyDomain Support")
                        .Subject = Me.SubjectTextBox.Text
                        .Body = Me.BodyTextBox.Text
                        .IsBodyHtml = False
                    End With
                End If
    
                If objSMTPClient Is Nothing Then
                    objSMTPClient = New SmtpClient
                    Try
                        objSMTPClient.Host = "smtp.MyDomain.com"
                        objSMTPClient.Credentials = New System.Net.NetworkCredential("Support@MyDomain.com", "MyPassword")
                    Catch ex As Exception
                        MessageBox.Show("Error occured connecting to host." + _
                                        Environment.NewLine + Environment.NewLine + _
                                        ex.Message)
                        Exit Function
                    End Try
                End If
    
                If dr(2).ToString = "" Then
                    MessageBox.Show("No email address for subscription: " & dr(0).ToString)
                    Continue For
                End If
    
                objMessage.To.Add(New MailAddress(dr(2).ToString, dr(1).ToString))
    
                Try
                    objSMTPClient.Send(objMessage)
                    id = CType(dr(5), Integer)
                    Subscription.EmailDone(id)
                    count += 1
                    ClientMsgCount += 1
                Catch ex As Exception
                    MessageBox.Show("Error occured sending e-mail. For SubId =" + dr(0).ToString + _
                                    Environment.NewLine + Environment.NewLine + _
                                    ex.Message)
                    objMessage = Nothing
                    Continue For
                End Try
                If ClientMsgCount >= 50 Then
                    ClientMsgCount = 0
                    objSMTPClient = Nothing
                End If
            Next
            Return count
        End Function
    
    
    
    
    


    Terry

    Thursday, December 22, 2016 1:54 PM
  • Please see my response to Kristin above.

    Terry

    Thursday, December 22, 2016 1:56 PM
  • Well, to get the SMTP status, you can catch SmtpException instead of Exception. That will give you access to the .StatusCode property.

                Try
                    objSMTPClient.Send(objMessage)
                    id = CType(dr(5), Integer)
                    Subscription.EmailDone(id)
                    count += 1
                    ClientMsgCount += 1
                Catch smtpex As SmtpException
                    MessageBox.Show("Error occured sending e-mail. For SubId = " + dr(0).ToString + _
                                    Environment.NewLine + Environment.NewLine + _
                                    smtpex.StatusCode.ToString + ": " + smtpex.Message)
                    objMessage = Nothing
                    Continue For
                Catch ex As Exception
                    MessageBox.Show("Error occured sending e-mail. For SubId =" + dr(0).ToString + _
                                    Environment.NewLine + Environment.NewLine + _
                                    ex.Message)
                    objMessage = Nothing
                    Continue For
                End Try

    As for why objMessage = Nothing is required in your code, it's solely because your code only keep adding address to .To without clearing it first. So when .NET runtime attempt to send email again, the first email address it see is still the address that cannot be sent.

    Calling objMessage.To.Clear() just before objMessage.To.Add() should be enough to fix it.


    • Edited by cheong00Editor Thursday, December 22, 2016 3:21 PM
    • Marked as answer by TerryLa Thursday, December 22, 2016 5:53 PM
    Thursday, December 22, 2016 2:49 PM
    Answerer
  • Thanks so much! 

    There is a objMessage.To.Clear() following the End Try that go lost in the translation so my real problem was the Continue For in the Catch portion.

    A little tricky getting the raw code (451) from the exception, finally ended up with

                    Dim sc As Integer = DirectCast(ex.StatusCode.LocalErrorInProcessing, Integer)

    Thanks again


    Terry

    Thursday, December 22, 2016 5:53 PM