Saturday, June 29, 2013

Checking whether emails have actually been sent to Gmail

In the management program which I wrote for the Occupational Psychologist, emails are sent to customers and contacts via Gmail. Normally this works very well, but every now and then the program sends an email which does not arrive at Gmail, hence does not arrive at the customer. These missing emails cause no small amount of frustration. We were discussing this problem yesterday and I came up with a theoretical solution: for every email which the program sends, check after a minute or two whether the email is in the 'sent items' folder of the Gmail account. If it isn't, send it again. A very simple solution but very hard to implement.

First of all, I had to learn how to access the 'sent items' folder of the account. It turns out that this is done with the IdIMAP4 component - see my question on Stack Exchange. The name of the folder is actually language dependent, so I had to change it to Hebrew. The code given uses the UIDRetrieveAllEnvelopes method, which downloads all of the messages in the folder. As no one is actively deleting messages in the folder, this means that every message which the program has sent is in this folder, some 650 messages. Obviously, a method of downloading only the most recent messages must be found.

After fiddling around for a bit, I hit on the following method

today:= datetostr (date);
 with imap do
  begin
   Username:= 'whatever@gmail.com';
   Password:= ....;
   Connect;
   if SelectMailBox('[Gmail]/sent items') then
    begin
     i:= MailBox.TotalMsgs;
     retrieve (i, email);
     while datetostr (email.date) = today do
      begin
       lb.items.add (email.subject + ' ' + datetostr (email.date));
       dec (i);
       retrieve (i, email)
      end 
    end;
   Disconnect;
  end; 

At the moment the above works, but I don't know whether the number of messages (ie mailbox.TotalMsgs) will always refer me to the most recent message. Now that I have the most recent messages, I have to check whether a specific message is to be found. In order to do this, I am using the references field in the email; I didn't know that such a field exists but it seems to be perfect for my needs. To quote some documentation, References is a String property that contains a list of message identifiers for which the message is a reply. References contains the value for the RFC message header 'References'. References is used by NNTP newsreader applications to create a threaded article display.

As the actual email is sent via a thread, I will check it with another thread whose execution will be delayed by two minutes. This second thread will receive the reference number; it will access the sent items folder and check that there is an email which has been sent today with the given reference number. If there is such an email, then first the thread will update the email log table to show that the email has been checked and then it will delete the actual data of the email which is sitting in a file on the hard disk. If no email is found, then the send an email thread will be called again to resend the email. I may have to revise my logging strategy.

No comments: