zipnotic
asked on
ASYNC Email callback progress check
Helllo,
I'm using the following code to send an email asynchronously. It's usually through gmail. It works fine but occasionally there is a collision with an IMAP check of the email account or a follow up SMTP async send. The attacments can get to 10-25 mbs which takes a minute or two to upload. I'm trying to prevent those collisions by incorporating a global variable 'MailSendInProgress' It gets set to TRUE just before the asyncsend and to FALSE in the callback from the async. I also use it as a check during some IMAP operations elsewhere in the application as this is what seemed to interfere and cause an error in the async email sending process. My question is whether there is a better way to accomplish this. This process seems to work OK but it feels hokey and maybe will cause problems in the future? Thanks for any thoughts you might have!
Check to prevent collisions from IMAP or other SMTP send operations:
If MailSendInprogress Then Exit Sub
I'm using the following code to send an email asynchronously. It's usually through gmail. It works fine but occasionally there is a collision with an IMAP check of the email account or a follow up SMTP async send. The attacments can get to 10-25 mbs which takes a minute or two to upload. I'm trying to prevent those collisions by incorporating a global variable 'MailSendInProgress' It gets set to TRUE just before the asyncsend and to FALSE in the callback from the async. I also use it as a check during some IMAP operations elsewhere in the application as this is what seemed to interfere and cause an error in the async email sending process. My question is whether there is a better way to accomplish this. This process seems to work OK but it feels hokey and maybe will cause problems in the future? Thanks for any thoughts you might have!
Check to prevent collisions from IMAP or other SMTP send operations:
If MailSendInprogress Then Exit Sub
Public MailSendInprogress As Boolean = False
public sub SendMail()
Try
Dim SmtpServer As New SmtpClient()
AddHandler SmtpServer.SendCompleted, AddressOf SendCompletedCallback
Dim mail As New MailMessage()
SmtpServer.Credentials = New Net.NetworkCredential(strMailLogin, strMailPassword)
SmtpServer.Port = 587
SmtpServer.EnableSsl = True
SmtpServer.Host = strSMTPServer
mail = New MailMessage()
mail.From = New MailAddress(strMailLogin)
If strAttachments = "YES" Then
Dim attachment As System.Net.Mail.Attachment
Using attachment
attachment = New System.Net.Mail.Attachment(Application.StartupPath & "\")
mail.Attachments.Add(attachment)
attachment = New System.Net.Mail.Attachment(Application.StartupPath & "\")
mail.Attachments.Add(attachment)
attachment = New System.Net.Mail.Attachment(Application.StartupPath & "\")
mail.Attachments.Add(attachment)
attachment = New System.Net.Mail.Attachment(Application.StartupPath & "\")
mail.Attachments.Add(attachment)
End Using
End If
mail.To.Add(strTo)
mail.Subject = strSubject
mail.Body = strBody
If IsHTML Then mail.IsBodyHtml = True
Do Until MailSendInprogress = False
Thread.Sleep(1000)
Loop
MailSendInprogress = True
SmtpServer.SendAsync(mail, Nothing)
LogIt("**** MAIL SENT *****")
Catch ex As Exception
LogIt("ERROR Sending email!" & ex.StackTrace)
End Try
Private Sub SendCompletedCallback(sender As Object, e As AsyncCompletedEventArgs)
' Throw New NotImplementedException
Try
If e.Error IsNot Nothing Then
LogIt("ERROR SENDING ASYNC EMAIL: " & e.Error.ToString)
Else
LogIt("ASYNC EMAIL SEND COMPLETED.")
End If
Catch ex As Exception
LogIt("ERROR " & ex.ToString)
End Try
MailSendInprogress = False
End Sub
ASKER
Hi,
Thanks for your comment. I spent some time checking out synclock and it doesn't seem like it's going to be appropriate for my code. What I would like to do is the prototypical long email send process in the background while the GUI remains responsive. I thought the asyncsend would be the answer but it isn't reliable. I thought it was due to collisions of checking the same email account with IMAP in one code block and sending an email with SMTP using the same email account. Now I'm not so sure. On my development computer the below code worked flawlessly for several days. When I installed it on a test computer it only works intermittently. It will send a few emails then putter out after an hour or two at the most. SOME emails will send after that but the majority result in an sendasync error captured in the callback. Both computers have .Net 4, WIndows 7. One is on a wireless network the other is cat6. The test computer has several other network processes running that are reliable using a synchronous mail send process. COuld that be the interference? The error information returned on the call back of sendasync is limited:
System.Net.Mail.SmtpExcept ion: Failure sending mail. ---> System.Net.Sockets.SocketE xception: An invalid argument was supplied
at System.Net.Mail.SmtpConnec tion.Conne ctAndHands hakeAsyncR esult.End( IAsyncResu lt result)
at System.Net.Mail.SmtpClient .ConnectCa llback(IAs yncResult result)
--- End of inner exception stack trace ---INNER EXCEPTION: System.Net.Sockets.SocketE xception (0x80004005): An invalid argument was supplied
at System.Net.Mail.SmtpConnec tion.Conne ctAndHands hakeAsyncR esult.End( IAsyncResu lt result)
at System.Net.Mail.SmtpClient .ConnectCa llback(IAs yncResult result)
Here's the code I'm currently using:
Thanks for your comment. I spent some time checking out synclock and it doesn't seem like it's going to be appropriate for my code. What I would like to do is the prototypical long email send process in the background while the GUI remains responsive. I thought the asyncsend would be the answer but it isn't reliable. I thought it was due to collisions of checking the same email account with IMAP in one code block and sending an email with SMTP using the same email account. Now I'm not so sure. On my development computer the below code worked flawlessly for several days. When I installed it on a test computer it only works intermittently. It will send a few emails then putter out after an hour or two at the most. SOME emails will send after that but the majority result in an sendasync error captured in the callback. Both computers have .Net 4, WIndows 7. One is on a wireless network the other is cat6. The test computer has several other network processes running that are reliable using a synchronous mail send process. COuld that be the interference? The error information returned on the call back of sendasync is limited:
System.Net.Mail.SmtpExcept
at System.Net.Mail.SmtpConnec
at System.Net.Mail.SmtpClient
--- End of inner exception stack trace ---INNER EXCEPTION: System.Net.Sockets.SocketE
at System.Net.Mail.SmtpConnec
at System.Net.Mail.SmtpClient
Here's the code I'm currently using:
Public MailSendInprogress As Boolean = False
Dim mail As New MailMessage()
Dim SmtpServer As New SmtpClient()
Public Sub SendMail(ByVal strFrom As String, ByVal strTo As String, _
ByVal strCC As String, ByVal strSubject As String, ByVal strBody As String, ByVal strAttachments As String, ByVal strSMTPServer As String, _
ByVal strMailLogin As String, ByVal strMailPassword As String, IsHTML As Boolean)
Try
SmtpServer = New SmtpClient()
AddHandler SmtpServer.SendCompleted, AddressOf SendCompletedCallback
SmtpServer.Credentials = New Net.NetworkCredential(strMailLogin, strMailPassword)
SmtpServer.Port = 587
SmtpServer.EnableSsl = True
SmtpServer.Host = strSMTPServer
mail = New MailMessage()
mail.From = New MailAddress(strMailLogin)
If strAttachments = "YES" Then
Dim attachment As System.Net.Mail.Attachment
Using attachment
attachment = New System.Net.Mail.Attachment(Application.StartupPath & "\")
mail.Attachments.Add(attachment)
attachment = New System.Net.Mail.Attachment(Application.StartupPath & "\")
mail.Attachments.Add(attachment)
attachment = New System.Net.Mail.Attachment(Application.StartupPath & "\")
mail.Attachments.Add(attachment)
attachment = New System.Net.Mail.Attachment(Application.StartupPath & "\")
mail.Attachments.Add(attachment)
End Using
End If
mail.To.Add(strTo)
mail.Subject = strSubject
mail.Body = strBody
If IsHTML Then mail.IsBodyHtml = True
MailSendInprogress = True
SmtpServer.SendAsync(mail, Nothing)
LogIt("**** ATTEMPTING TO SEND MAIL *****")
Catch ex As Exception
SmtpServer.Dispose()
mail.Dispose()
LogIt("ERROR Sending email!" & ex.StackTrace)
End Try
End Sub
Private Sub SendCompletedCallback(sender As Object, e As AsyncCompletedEventArgs)
' Throw New NotImplementedException
Try
If e.Error IsNot Nothing Then
LogIt("ERROR SENDING ASYNC EMAIL: " & e.Error.ToString & "INNER EXCEPTION: " & e.Error.InnerException.ToString())
Else
LogIt("ASYNC EMAIL SEND COMPLETED.")
End If
Catch ex As Exception
LogIt("ERROR " & ex.ToString)
End Try
MailSendInprogress = False
SmtpServer.Dispose()
mail.Dispose()
End Sub
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
Avoiding asynch was best solution
If you are concerned about multiple hits to same process or method, then you can use lock statement. It is reffered as SyncLock in VB.net. Furthermore you may not need MailSendInprogress to track status of SendMail.
You may find following articles helpful:
https://msdn.microsoft.com/en-us/library/3a86s51t.aspx
http://www.dotnetperls.com/synclock
Open in new window