Harambe
Harambe

Reputation: 423

Emails failing to send with .SendAsync but work with SmtpClient_Send

I've been writing an email function in vb.net and had it working fine when my code was Smtp_Server.Send, the emails were sending successfully with no issues.

Then, I had to change it to SmtpServer_SendAsync and I was able to do this using information from this question about how to log any emails.

However, when trying to send email with the following code, it always fails, yet changing it back to just .Send has no issues. Am I missing something else in the email code?

The code for setting up and sending the email is this: (Obviously I've also got code for setting variables but it's not relevant here so I've left it out)

Smtp_Server.UseDefaultCredentials = False
Smtp_Server.Credentials = New Net.NetworkCredential(senderAdd, senderPass)
Smtp_Server.EnableSsl = False
Smtp_Server.Host = SMTPserver

Try
   AddHandler Smtp_Server.SendCompleted, AddressOf sendComplete
Catch ex As Exception
    silentErrorLog(ex)
End Try

e_mail = New MailMessage()
e_mail.From = New MailAddress(senderAdd)
e_mail.DeliveryNotificationOptions = DeliveryNotificationOptions.OnSuccess
e_mail.To.Add(eMail)
e_mail.Subject = subj
e_mail.IsBodyHtml = False
e_mail.Body = bod

Dim userState As Object = e_mail
Smtp_Server.SendAsync(e_mail, userState)

e_mail.Dispose()
e_mail = Nothing

Try
   If bInvoice = True Then
       triggerInvoice()
   End If

 Catch ex As Exception
      silentErrorLog(ex)
 End Try

 Catch ex As Exception
    errorLog(ex)

 End Try
End Sub

The error for this is

Failure sending email

Inner Exception: Cannot access a disposed object

Code for sendComplete

Public Sub sendComplete(ByVal sender As Object, e As AsyncCompletedEventArgs)

 Try
   If e.Error IsNot Nothing Then
     PictureBox1.Visible = False
     MsgBox("Failed to send email!", MessageBoxIcon.Warning + MsgBoxStyle.OkOnly, "Error")
     mailSent = False

It is always using this first part of the If, never going to the Else clause, so something must be wrong?

Upvotes: 1

Views: 1283

Answers (1)

Heinzi
Heinzi

Reputation: 172200

You dispose the e-mail message right after calling SendAsync. At that point, however, the message has not been sent yet, so you dispose an object that SendAsync still needs:

Smtp_Server.SendAsync(e_mail, userState)

e_mail.Dispose()    ' bad timing

The solution is to attach to the SendCompleted event and dispose the message there. You can use a lambda expression to make sure that the e_mail variable is in scope in the event handler:

AddHandler Smtp_Server.SendCompleted, Sub(sender, e) e_mail.Dispose()

Smtp_Server.SendAsync(e_mail, userState)

Alternatively, since you pass the message as a userstate to your async method, you can dispose the message in your existing event handler:

Public Sub sendComplete(ByVal sender As Object, e As AsyncCompletedEventArgs)
    DirectCast(e.UserState, MailMessage).Dispose()
    ...
End Sub

Upvotes: 1

Related Questions