NetTalk is asynchronous, so we don't advise treating it in a synchronous fashion. In the case of email sending, each time the Send() method is called NetTalk buffers the mail, which lets you get away with treating the email send method as if it was synchronous, and doing things such as calling Send() in a tight loop. That said, it is definately not the best approach. NetTalk provides callback methods that allow you to respond to email being sent, errors occurring and so on. This is far more robust and allows you to ensure that mail is send, handle errors correctly and so on.
1) Create a Setup routine that sets everything up, fills in the email server details etc. and does the Set() on the file (this assumes that you are looping through a file and fetching the records to send, but the same approach works regardless of the source of the email):
! "Set up" NetTalk
ThisEmailSend.Server = EmailServer
ThisEmailSend.Port = EmailPort
2) Create a ProcessEmail routine that sends each message:
if Access:EmailFile.Next() ! End of records in the EmailFile table
Message('All Messages have been sent')
else ! Found a record to send
ThisEmailSend.ToList = Clip(efn:f1)
ThisEmailSend.SetRequiredMessageSize (0, len(clip(EmailMessageText)), len(clip(EmailMessageHtml)))
if ThisEmailSend.Error = 0
! This should NEVER happen, it means memory allocation failed
! This is likely to be a fatal error, so you might want to abort the connection
! Memory allocation should not fail in the normal course of things
Message ('An error occurred while trying to send the mail. Could not allocate memory', 'Error', ICON:Exclamation)
3) Now the first message has been sent you wait for one of two NetEmailSend methods to fire:
ErrorTrap() - called if the sending failed or an error occurs
MessageSent() - called when the message is sent successfully
a) Add code in ErrorTrap to handle errors, before the parent call:
! You can handle all error in the same fashion if you prefer, but I try to
! handle message specific errors seperately from errors that will cancel the entire send
if self._ErrorStatus = NET:ERROR_STATUS_SERVER_ERROR
! A server error occured, like the connection was terminate etc. No more mail will be
! sent at this point, although messages that have already been sent are fine
Message('Sorry but sending the batch of mail failed, a server error occured: ' & Clip(errorStr))
! Just this message failed, so we can carry on sending
Message('Sorry but the current email could not be sent: ' & Clip(errorStr))
Do ProcessEmail ! Send the next one
b) Add code in MessageSent() when a message gets sent
! You can delete the entry that was sent here from the Email table or mark it as sent etc.
Do ProcessEmail ! Send the next one.
4) Finally in the Event:Timer embed (add a timer to the window) call:
This will set the EmailSender.Progress1000 properties to the current progress in increments of 1/1000th. The easiest way to have a progress control is in the ThisWindow.Init() method after the Open(window) call set the EmailSender.ProgressControl property to the handle of a progress control on your window.
EmailSender.ProgressControl = ?OurProgress
On first glance it probably looks more complex than it actually is, but it is the best approach to take when working with NetTalk, and also has the advantage that you are never in a tight loop, so your application remains responsive to the user. Basically the code is identical except instead of calling the methods in a loop you wait for NetTalk to inform you that a message has been sent or that an error has occurred. You can display a progress bar easily, track which messages are sent, handle errors well etc.