Reputation: 423
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
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