I’m using a SMTPSecureSocket sending mails. Between each message, a delay should be added to wait before processing the next message in queue. In the SMTPSecureSocket.MessageSent event I added an empty while-wend-loop performing this task.
In addition, there runs a timer that updates some statistics and a countdown clock in a window, also checking for buttons pressed in that window.
While executing the while-wend-loop, the timer is not being executed at all (guess the SMTPSecureSocket.MessageSent takes all time), so buttons and countdown clock are unresponsive during the waiting period.
I want to solve this issue by adding a call of App.DoEvents() inside the while-wend-loop. My tests came up that this is working (OS X 10.8.x) well, but I’m unsure if it is an allowed use of App.DoEvents() working on earlier/later versions of OS X and Windows (XP and higher) without issues or inconsistencies ? I’m aware that App.DoEvents() outside a console app could be problematic, but I really see no other way to solve this issue.
What I would do is to send each email separately, by keeping a copy of the EmailMessage and a list of recipients.
Then use a Timer and at each Action time modify the EmailMessage.ToAddress Properties (with the next recipient), then SMTPSecureSocket.SendMail() again.
This way your emails will be sent one by one and you would be more in control for using delays and updating the UI.
Guy’s solution is good - here it is, a little more fleshed out.
You start with a single message. You start sending it. In the socket’s MessageSent event, you set up a timer that fires once in, say, 2 seconds that sets up the next message and sends it. Keep doing this until you are out of messages to send.
While all this is going on, you don’t spend any time in any loops, and this is what frees up your app to continue being responsive to the user.
You could have another timer that updates status, and that would be one way of doing it. However, may I suggest that you only update status when something actually changes? For example, if your statistics track how many messages have been sent, that should only need to be updated whenever a message is actually sent. You could update the statistics in the MessageSent event of your socket, instead of polling for that information from a timer. Of course, if your stats show time elapsed, you will also need another timer that forces a status update every ‘n’ seconds.
[quote=80148:@Tobias Eichner]
I want to solve this issue by adding a call of App.DoEvents() inside the while-wend-loop. [/quote]
It won’t “solve” it and may cause you more grief
What about moving your mail sending loop into a separated thread letting your main thread free to do it’s UI job? Dispatch update events from there. Thread.Sleep for the pause between sends?
Thank you very much for your replies. I read them carefully. Unfortunately, it isn’t as easy as that to find a rewrite, because I have to keep the way mails are processed there:
All messages have been created and added to the socket using SocketSendMailing.Messages.Append in advance and then are sent using SocketSendMailing.SendMail. Therefore, the only way I can get influence is somewhere from within the socket object.
Mails’ contents are totally different, so I can’t just use one as a template and go through a recipients array.
[quote=80148:@Tobias Eichner]I’m using a SMTPSecureSocket sending mails. Between each message, a delay should be added to wait before processing the next message in queue. In the SMTPSecureSocket.MessageSent event I added an empty while-wend-loop performing this task.
In addition, there runs a timer that updates some statistics and a countdown clock in a window, also checking for buttons pressed in that window.
[/quote]
Why not simply update a flag in the SMTPSecureSocket.MessageSent event and use a if flag = true in the timer action ? That would not freeze everything.
@Thom: It’s a server issue… the mail server has a built-in security mechanism that prevents sending more than fifty mails within a given time period. Although known by the hosting provider, they cannot turn this off. Alternative for the client would be to switch to a managed server, but I’m looking for a way to save them some money.
@Michel: The timer does not run overall, because the event has priority.
[quote=80247:@Tobias Eichner]…/…Unfortunately, it isn’t as easy as that to find a rewrite, because I have to keep the way mails are processed there:
All messages have been created and added to the socket using SocketSendMailing.Messages.Append in advance and then are sent using SocketSendMailing.SendMail. Therefore, the only way I can get influence is somewhere from within the socket object.
Mails’ contents are totally different, so I can’t just use one as a template and go through a recipients array.[/quote]
You have chosen a way to create your emails/recipients and now you are confronted to the delay/update issue.
This should signal you that the chosen way was not the right one. So instead of trying to find a messy solution to an issue you created yourself, why not step back and make another choice ?:
Instead of creating your messages and adding them right away to the socket, why not stock them in an array ? Then you will be able to send them one by one as explained above - and instead of using a template you modify, you then just use the ready to send emails, that’s even easier.
First, in my opinion, if you are sending that many messages, it is time to find an SMTP service designed for such a thing. SMTP2Go comes to mind, but there are tons of others.
If that isn’t an option, I’d go with Guy’s suggestion. Store all the messages in your own array. Then use a timer to move messages from your array to the socket’s array as appropriate.
Change this one line of code to append to an array and move SocketSendMailing.SendMail into a timer. That is practically all it would take to adjust your code to avoid DoEvents.
If it were me, I would send them in batches of 49 at a time and set the timer period to just greater than the amount of time the server complains about. That way, if you have fewer than 50 to send, they all go immediately.
It is normal that the event has priority. What I am suggesting is to remove the while/wend from there and do that :
In SMTPSecureSocket.MessageSent you set say a module msgSent flag to True
Now in the timer, pseudo code
[code]'Use static that keeps the state of msgSent at the previous tick in PreviousMsgSent
If PreviousMessageSent was False and msgSent is True, means SMTPSecureSocket.MessageSent just fired then
set module boolean variable wait to True. This flag will be used in your send code to wait until it turns False
set static hold integer variable to as many ticks as needed to obtain your delay
end if
if hold is >0 then
hold = hold-1
else
wait = False
end if
PreviousMsgSent = msgSent
[/code]
The idea is to move the ‘while delay is not over’ to the timer, so at every tick you ask ‘are we there yet’ and Shrek replies ‘Not yet’ while counting down to zero. When the countdown is over, Shrek says ‘We are there’, the delay is over, the while has ended, and a new message can be sent.
Instead of staying stuck in the event, you simply manage the delay and the state of it tick by tick in the timer… The interval between ticks depending on what is appropriate not to create a bottleneck.
The issue you reported comes all from the freeze created in the SMTPSecureSocket.MessageSent event. So if you manage the delay in the timer, you keep your app responsive without app.doevents and without a thread.