4

I'm experiencing a strange behavior trying to send email using Threading.ThreadPool.

This has worked for over a year now but recently it has stated to intermittently send emails with no content. The addressees and subject are all fine, however, the rest of the email is blank. Nothing has changed code wise (apart from Windows updates to the server it runs on).

Here's the code I'm using - does anyone have a suggestion of how I might narrow down where the problem is occurring? Upon re-sending the email to someone who has claimed of receiving a blank email they get it fine - it uses the exact same code as the first one that was sent.

Sub to generate email:

 Public Sub EmailConfirmation(email As String,
                                 firstname As String,
                                 details As String)

        Try


            Dim embody As String = GlobalHelper.emailBody
            'static class which loads the email text at application load for use later.
            'This is a point of concern because it's obviously where the embody text is
            'is loaded, but the issue is intermittent and if there was a failure here surely
            'it would be caught by the 'try...catch' and a log of the error created (which has
            'never happened). I also ran an experiment for a while where if this string was 
            'empty then create a log entry. After receiving a complaint of a blank email
            'no error log was found.

            embody = Replace(embody, "[FirstName]", firstname)
            embody = Replace(embody, "[DATA]", details)


            'create the mail message
            Dim mail As New MailMessage()

            'set the addresses
            mail.From = New MailAddress("myemail@mydomain.com", "My Display Name")
            mail.To.Add(email)
            mail.IsBodyHtml = True

            'set the content
            mail.Subject = "Email Subject!"
            mail.Body = embody


            AddEmailToThreadPool(mail)

        Catch ex As Exception

        'if there is an error it is logged here. 

        End Try


    End Sub

Sub that adds to ThreadPool:

Private Sub AddEmailToThreadPool(email As MailMessage)
        System.Threading.ThreadPool.QueueUserWorkItem(New System.Threading.WaitCallback(AddressOf sendEmail), email)
    End Sub

Sub that sends email:

Private Sub sendEmail(stateinfo As Object)

        Dim email As MailMessage = CType(stateinfo, MailMessage)


        Try

            'send the message
            Dim smtp As New SmtpClient("mail.mydomain.com")
            smtp.Send(email)
        Catch ex As Exception
            'error is logged here.
        End Try

    End Sub
Adrian Toman
  • 11,316
  • 5
  • 48
  • 62
GJKH
  • 1,715
  • 13
  • 30
  • 1
    Run the HTML returned by `GlobalHelper.emailBody` through a validator. Malformed HTML may not show anything in a browser. – Dour High Arch Apr 11 '13 at 01:55
  • has your mail client changed? could the body not be rendered properly? have you logged the mail.Body property to ensure it's getting set appropriately? – Jason Apr 11 '13 at 01:55
  • 1
    When you say you can resend the message without issue to someone who received a blank email, how exactly do you go about doing that (that is, are you logging the exact info as initially used or manually generating a new message)? Are you validating `firstname` and `details` (ie no unescaped html characters)? What does `GlobalHelper.emailBody` look like in terms of code (ie property vs field) and typical value? Have you ever had someone who received a blank email forward it to you so you could inspect it? – jerry Apr 11 '13 at 02:08
  • @DourHighArch - I believe I validated the HTML when it was created, it's odd how it's only become a problem recently - I'll try this though. At least two of the complaints were from users with a gmail and hotmail account though so I wouldn't have thought this wouldn't be the case. Jason - I tried to log when mail.Body was empty, never fired once even though there were complaints of blank emails. Despite my attempts I've not been able to recreate the issue. – GJKH Apr 11 '13 at 02:08
  • @Jerry Yes, I've inspected several of the emails and they are correct in saying that the body of the email is completely empty. When I resend the email I call the exact same sub to send the mail, it loads the parameters from the same place as before. – GJKH Apr 11 '13 at 02:09
  • What does your `Replace` method look like? I notice that you're not using [`embody.Replace("[FirstName]", firstname)`](http://msdn.microsoft.com/en-us/library/fk49wtc1.aspx?cs-save-lang=1&cs-lang=vb#code-snippet-1). – Simon MᶜKenzie Apr 11 '13 at 02:53
  • Ah! There was a random space in the doctype declaration that stopped it from validating. Could this cause some clients to not display anything at all @DourHighArch? – GJKH Apr 11 '13 at 16:31
  • It is unlikely a space in the doctype would cause the problem; most email clients ignore declarations. – Dour High Arch Apr 11 '13 at 16:38
  • @GJKH I'm assuming you're looking at the actual source of these empty messages, not the rendered output. I think this is a long shot to cause the type of error you're seeing, but is it possible the connection is being reset/timing-out or the parent process is terminating during the `smtp.Send(email)` call? – jerry Apr 11 '13 at 19:50
  • @SimonMcKenzie I believe it's [this built-in VB function](http://msdn.microsoft.com/en-us/library/bt3szac5(v=vs.90).aspx). Since strings are immutable, it should be thread safe. – jerry Apr 11 '13 at 20:14
  • Odd - not had a complaint of a blank email since I last updated the email template to include a properly formed doctype - I'm not convinced this is what has fixed the problem, then again I'm not entirely convinced the problem has been fixed. Not sure what to do with this question - should I keep it open? – GJKH Apr 23 '13 at 12:34

2 Answers2

1

I copied from MSDN MailMessage class

Any public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.

cat916
  • 1,363
  • 10
  • 18
  • I think you're on to something; @GJKH, can `GlobalHelper.emailBody` be called simultaneously by multiple threads? – Dour High Arch Apr 11 '13 at 16:40
  • Just set up a test console app that looped and added a million of these items to the thread pool in the same manner and inside that loop added another 10 items to the pool. My laptop got hot but never dumped out once. I checked to see if the email body was empty, never caught it once. – GJKH Apr 11 '13 at 17:13
  • If you're implying the `MailMessage` object can't be passed to the `QueueUserWorkItem`, that's not correct. The fact that the instance members are not thread safe (a common warning in the .Net framework class library) means you shouldn't access the same MailMessage object from multiple threads simultaneously. The code does not appear to be able to do this as each invocation of `EmailConfirmation` instantiates a new `MailMessage` object, passes it to `AddEmailToThreadPool`, and then does not access it again (possible error logging aside). – jerry Apr 11 '13 at 20:09
  • @DourHighArch I was wondering the same thing, but for it to be a problem `GlobalHelper.emailBody` would have to be a (not trivial) property instead of a plain field. – jerry Apr 11 '13 at 20:17
0

Well, after fixing the incorrect doc type declaration I've not had a single complaint of blank emails in almost a month. I'm going to assume this fixed the problem all though I'm not certain why.

Thanks for all of your input/help.

GJKH
  • 1,715
  • 13
  • 30
  • 1
    Glad you seem to have solved your problem. It's strange that a user would be able to see it one time but not another, however, if it was caused by invalid html. Do you happen to know if that user used different email clients, browsers, or computers to view the two messages? – jerry May 09 '13 at 16:37
  • Possibly, I think it may have been the case that they weren't displaying on there mail client but would display on their mobile for example. But dealing with them via a 3rd party made asking questions/getting answers difficult. The only response I would get is 'it's working now'. To be fair I'm not entirely convinced the issue is resolved, I don't think a malformed doc type would cause this kind of behaviour, will wait and see. – GJKH May 09 '13 at 16:44