Strange issue with inaccurate time in TIdMessage headers and message - delphi

Using Indy 10.1.5 (the version shipped with D2007), I'm composing and sending an email message as part of an automated internal process.
The email is sent fine, but when the recipient receives the message the time appears incorrectly in the email client, causing the message to incorrectly sort in the inbox. This has caused the recipient to overlook the message (because it wasn't in the inbox in the proper sequence and scrolled off the bottom), causing minor processing delays.
Both the sender and recipient in the US Eastern time zone (UTC -0400). The message header is correctly showing the message date, but without including a time zone:
Date: Mon, 3 Aug 2015 11:12:21 +0000
When the email is received and viewed in Outlook, the message is being shown with the UTC offset:
Mon 08/03/2015 7:12 AM
The code that creates the message is pretty simple (copied/pasted and then anonymized and simplified). It creates a relatively short message body (providing info about the file attached), creates the attachment, and sends the message. (try..except and try..finally removed for brevity - they exist in the actual code.)
Msg := TIdMessage.Create;
// Also tried using False and setting Date property manually
Msg.UseNowForDate := True;
for i := 0 to NumAddr do // Number of recipients
begin
Msg.Recipients.Add;
Msg.Recipients[Msg.Recipients.Count - 1] := RecipAddr[i];
end;
Msg.FromList.Add;
Msg.FromList[0].Name := Sender Name;
Msg.FromList[0].Address := SenderAddress;
Msg.Subject := 'Some text';
Msg.Body.Add('A few lines of text providing summary info.');
TIdAttachmentFile.Create(Msg.MessageParts, FileToAttach);
Mail := TIdSMTP.Create;
Mail.Host := PrimaryMailServer;
Mail.Connect;
Mail.Send(Msg);
Mail.Disconnect;
I've read through the Indy documentation and examined all of the properties I can find for both TIdSMTP and TIdMessage, and can't find anything else that would correct this time zone mismatch.
Can anyone see what it is I'm missing here?

10.1.5 is an outdated version of Indy 10. The current version is 10.6.2.
There were some UTC related bugs in earlier versions of Indy 10. In this case, there was a bug in Indy's OffsetFromUTC() function, which retrieves the local machine's UTC offset and is used when calculating the timestamp for outgoing emails. You should upgrade to a modern version of Indy 10, so you have the latest fixes, features, architectural changes, etc.
If you cannot upgrade, you will have to set the TIdMessage.UseNowForDate property to false and provide your own timezone-adjusted TDateTime value in the TIdMessage.Date property to account for Indy's faulty offset, so a proper timestamp value is sent.

Related

Wrong timestamp in Codesite logging

I am using Raize CodeSite to write log lines to from a Delphi desktop application to a separate log file.
All components are running on a single PC (application + Codesite)
The logging works fine, except for the date/time. The date/time which is shown in the Codesite Log viewer is sometimes EARLIER than the time the log message was sent!
TS := FormatDateTime('YYYY-MM-DD HH:NN:SS.ZZZ', NOW()); // 2019-08-20 14:22:15.780
CodeSite.Send('Log Message at ' + TS );
Which results into a log line with a (codesite-) date/time which is EARLIER than the timestamp generated in the application:
"Log message at 2019-08-20 14:22:15.780" Code site date
time: 2019/08/20 14:22:15.333

Imap4 client command LSUB

I have a problem with function TIdIMAP4.ListSubscribedMailBoxes(AMailBoxList: TStrings): Boolean; with this implementation :
function TIdIMAP4.ListSubscribedMailBoxes(AMailBoxList: TStrings): Boolean;
begin
{CC2: This is one of the few cases where the server can return only "OK completed"
meaning that the user has no subscribed mailboxes.}
Result := False;
CheckConnectionState([csAuthenticated, csSelected]);
SendCmd(NewCmdCounter, IMAP4Commands[cmdLSub] + ' "" *',
[IMAP4Commands[cmdList], IMAP4Commands[cmdLSub]]); {Do not Localize}
if LastCmdResult.Code = IMAP_OK then begin
// ds - fixed bug # 506026
ParseLSubResult(AMailBoxList, LastCmdResult.Text);
Result := True;
end;
end;
When I debug I see that the LastCmdResult.Text stringlist is empty, but the LastCmdResult.FormattedReply stringlist has all folders on my email server (Inbox, Sent, Trash, ...). When I tried to use LastCmdResult.FormattedReply count or text, it had immediately lost its data and gave LastCmdResult.FormattedReply.Count=0 and LastCmdResult.FormattedReply.Text=''. So I'd like to know if there is a way to enter the data inside LastCmdResult.FormattedReply and get my email server folders or there is another way to solve my problem ?
I have a problem with function TIdIMAP4.ListSubscribedMailBoxes(AMailBoxList: TStrings): Boolean; with this implementation :
Works fine for me when I try it using the latest SVN version of Indy.
When I debug I see that the LastCmdResult.Text stringlist is empty, but the LastCmdResult.FormattedReply stringlist has all folders on my email server (Inbox, Sent, Trash, ...).
When I run it, the opposite happens. LastCmdResult.Text contains the expected text, and LastCmdResult.FFormattedReply is empty (notice I mention the FFormattedReply data member directly, see below).
When I tried to use LastCmdResult.FormattedReply count or text, it had immediately lost its data and gave LastCmdResult.FormattedReply.Count=0 and LastCmdResult.FormattedReply.Text=''.
That is by design. The FormattedReply property is intended to be used by a client to parse a server reply so it can populate TIdReply's property values, and to be used by a server to generate a new reply using TIdReply's property values. So, you cannot read from the FormattedReply property on the client side.
So I'd like to know if there is a way to enter the data inside LastCmdResult.FormattedReply and get my email server folders or there is another way to solve my problem ?
The whole purpose of ListSubscribedMailBoxes() is to return the folder names in the AMailBoxList parameter. If that is not working for you, then either
you are using a older/buggy version of Indy.
your server is sending the data in a format that TIdIMAP4 is not able to parse.
Without knowing which version of Indy you are actually using, or what the server's reply data actually looks like, there is no way to diagnose your issue one way or the other.

TIdMessageParts.CountParts Returns 0

I'm trying to pull multipart emails in MIME format from an IMAP server using Indy 10.5.5 in Delphi 2010. These are the lines of code that I'm having trouble with are below, where I instatiate the curMessage object, retrieve a message into it, and then call CountParts:
var
curMessage: TIdMessage;
IMAP4: TIdIMAP4;
msgIndex: Integer;
begin
...
curMessage := TIdMessage.Create(nil);
IMAP4.Retrieve(msgIndex, curMessage);
curMessage.MessageParts.CountParts;
//code that checks counts
//and
end;
I then have some code that checks the various count properties of curMessage.MessageParts (i.e. TextPartCount). However, the CountPart procedure isn't returning anything, because the Count property referenced in the procedure block is 0, even though I've verified that the message is retrieved and placed into the curMessage.
One thing I've noticed, and haven't gotten to the bottom of yet, is that IsMsgSinglePartMime is coming back as true, even though all the messages on the server have Content-Type: multipart/mixed;.
Any help would be really appreciated.
What am I missing here? I can provide more code if needed,
Without seeing the actual email data, it is difficult to say for sure exactly why the data is not where you expect it to be. But if the TIdMessage.IsMsgSinglePartMime is getting set to True then that means that either:
TIdMessage.Encoding is meMIME but TIdMessage.MIMEBoundary.Count is 0, meaning there was no MIME boundary value detected in the top-level Content-Type header. If the Content-Type is a 'multipart/...' type, a boundary is required. If it is present, it is likely malformed in a way that prevented Indy from parsing it.
TIdMessage.Encoding is mePlainText but TIdMessage.ContentTransferEncoding is either 'base64' or 'quoted-printable'.
In either case, if there is body content present then it would end up in the TIdMessage.Body property if it is textual data, otherwise it would end up in the TIdMessage.MessageParts as an attachment instead. Since TIdMessage.MessageParts.Count is 0 in your case, the data is either in TIdMessage.Body, or is got discarded.
You may want to consider upgrading to a newer Indy version. The version shipped with D2010 is pretty old, and there have been fixes/changes made to TIdIMAP4 and TIdMessage (and its internal parsers) in recent years.

Incorrect boundary string in multipart/mixed message

I'm using Delphi 2006 to create and send an email message with an attachment in a personal-use-only application. I send the message with an instance of TIdSMTP, and then also put a copy into a specific IMAP folder with an instance of TIdIMAP4. This all works very nicely with the version of Indy 10 that was distributed with BDS2006, with one exception: the time is always incorrect in the email header.
I decided to fix that if I could, and after searching for a solution it seemed most reasonable to get the latest Indy 10 snapshot and use that.
That puts the correct time into the email header, but there's a new problem. The boundary string is now different in the header of the message that is added to the IMAP folder than what comes in the body of the email! (Please note that the message that was sent via SMTP is correct.)
This is the relevant header information from the older version of Indy 10:
Content-Type: multipart/mixed; boundary="XNlC6OyS4QSiHY2U=_jsXyps6TR34pFNsh"
MIME-Version: 1.0
Date: Tue, 22 Nov 2011 09:11:58 +0000
A test of the BDS2006-bundled version of Indy
--XNlC6OyS4QSiHY2U=_jsXyps6TR34pFNsh
Content-Type: application/octet-stream;
name="20111122.xls"
And this is the same header information from Indy 10.5.8 (snapshot 10_4702 which I installed yesterday):
Content-Type: multipart/mixed; boundary="CDbEncbFvL7RZdOJ3DOIRoRBs=_nBsbZms"
MIME-Version: 1.0
Date: Tue, 22 Nov 2011 07:33:46 -0600
investigating more deeply, why does the boundary indicator change?
--h=_WzGWJei29fng7SqdPpDh1nkJxJZhiGc
Content-Type: application/octet-stream;
name="20111122.xls"
The time stamp is fixed, but now the boundary string is incorrect. The result is that there appears to be nothing at all in the message that gets added to my IMAP folder.
Here is the relevant code that creates the email message and attachment, sends it, and puts a copy into the IMAP folder:
FTheMsg.Date := Now; // FTheMsg is a component dropped onto the form
FTheMsg.Recipients.EMailAddresses := edMailTo.Text;
FTheMsg.ClearBody;
FTheMsg.Subject := 'Glucose Readings ' + FormatDateTime('mm/dd/yy', FStartDate) + ' - ' +
FormatDateTime('mm/dd/yy', FEndDate);
FTheMsg.Body.Assign(FMemo.Lines);
// create the attachment
TIdAttachmentFile.Create(FTheMsg.MessageParts, fileName);
// send the mail!
FSmtp.Host := FSMTPHost; // values set up elsewhere, FSmtp is a component on the form
FImap.Host := FIMAPHost; // FImap is also a component on the form
FSmtp.Connect;
try
FSmtp.Send(FTheMsg);
FImap.Connect;
try
if (not FImap.AppendMsg('Sent Items', FTheMsg, FTheMsg.LastGeneratedHeaders, [mfSeen])) then
StatusBar1.Panels[4].Text := 'Failed append msg';
finally
FImap.Disconnect;
end;
finally
FSmtp.Disconnect;
end;
As I said, the email that gets sent is fine and displays properly. But the one that is added to my IMAP folder (in FImap.AppendMsg() above) is incorrect. I've attempted to trace through the code to see where it might be going wrong, but frankly, I'm not familiar enough with Indy and the various email protocols/RFCs to be able to determine what's going wrong. About all I can tell is that the older version saves the message to a temporary file before appending it to the folder, while the newer version saves it to a memory stream instead. Obviously, something is different about that, but I'm currently too ignorant to determine what.
Is there a simple way to correct the timestamp problem in the old version? If so, that would be fine for my use, as everything else appears to be correct. If not, what else do I need to do to fix the problem exhibited here with the incorrect boundary string?
(As this is an application strictly for my own use, I can live with the incorrect date if I have to, but not with the "empty-appearing" copy in my 'Sent Items' folder.)
If more information is needed, I'll gladly supply whatever I can.
[Edit: I did incorporate something of a kludge in MY code, using the older version of Indy. I simply set the date/time of the message to UTC/GMT time before sending it, and that, at least, allows the message to contain the correct time at the receiver's end. I don't particularly care for that fix, but it does the trick.]
Don't use the TIdMessage.Body property to hold your text when an attachment is present. Put the text into a TIdText object instead. Even better, use the TIdMessageBuilder... classes, such as TIdMessageBuilderPlain, to prepare the TIdMessage body for you.
Try this:
FTheMsg.Clear;
FTheMsg.Date := Now; // FTheMsg is a component dropped onto the form
FTheMsg.Recipients.EMailAddresses := edMailTo.Text;
FTheMsg.Subject := 'Glucose Readings ' + FormatDateTime('mm/dd/yy', FStartDate) + ' - ' + FormatDateTime('mm/dd/yy', FEndDate);
FTheMsg.ContentType := 'multipart/mixed';
TIdText.Create(FTheMsg.MessageParts, FMemo.Lines).ContentType := 'text/plain';
TIdAttachmentFile.Create(FTheMsg.MessageParts, fileName);
FSmtp.Connect;
try
FSmtp.Send(FTheMsg);
FImap.Connect;
try
if (not FImap.AppendMsg('Sent Items', FTheMsg, nil, [mfSeen])) then
StatusBar1.Panels[4].Text := 'Failed append msg';
finally
FImap.Disconnect;
end;
finally
FSmtp.Disconnect;
end;
Or:
FTheMsg.Clear;
FTheMsg.Date := Now; // FTheMsg is a component dropped onto the form
FTheMsg.Recipients.EMailAddresses := edMailTo.Text;
FTheMsg.Subject := 'Glucose Readings ' + FormatDateTime('mm/dd/yy', FStartDate) + ' - ' + FormatDateTime('mm/dd/yy', FEndDate);
with TIdMessageBuilderPlain.Create do
try
PlainText.Assign(FMemo.Lines);
Attachments.Add(fileName);
FillMessage(FTheMsg);
finally
Free;
end;
FSmtp.Connect;
try
FSmtp.Send(FTheMsg);
FImap.Connect;
try
if (not FImap.AppendMsg('Sent Items', FTheMsg, nil, [mfSeen])) then
StatusBar1.Panels[4].Text := 'Failed append msg';
finally
FImap.Disconnect;
end;
finally
FSmtp.Disconnect;
end;
Now, with that said, it is likely that it will still not work correctly either way. TIdIMAP4.AppendMsg() calls TIdMessage.SaveToStream() internally, which regenerates the email content fresh (and thus alters the boundary used in the body). Whether you pass in the pre-existing TIdMessage.LastGeneratedHeaders or let TIdIMAP4.AppendMsg() grab the current TIdMessage.Headers, they will be out of sync with the new boundary that TIdMessage.SaveToStream() generates.
To make sure both SMTP and IMAP4 are in sync, they need to receive the same data. Try calling TIdMessage.SaveToStream() manually first with the TIdMessage.NoEncode property set to False, then set the TIdMessage.NoDecode property to True and call TIdMessage.LoadFromStream() to reload the saved data as-is into the TIdMessage.Headers and TIdMessage.Body properties, then call TIdSMTP.Send() and TIdIMAP4.AppendMsg() with the TIdMessage.NoEncode property set to True so the TIdMessage.Headers and TIdMessage.Body are sent as-is.
I know, this goes against what the TIdIMAP4.AppendMsg() comments/docs say to do. AppendMsg() does not currently take MIME into account at all, so it does not ensure the MIME boundary in the header and body match each other. I will try to check in a fix for that. For Indy 11, Indy's entire MIME handling system is going to be redesigned, so I'll make sure it is possible to preserve boundaries, and/or to specify custom boundaries, so AppendMsg() can match the body boundary to the header boundary better.
IMAP4 is a very tricky protocol to work with in general.

Delphi: MAPILOGON ErrorCode 1

I tried with many versions of MAPISend, but I everytime got error in one place.
The MAPILogon returns with errorcode 1.
dwRet := MapiLogon(Handle,
nil,
nil,
MAPI_DIALOG or MAPI_NEW_SESSION,
0, #MAPI_Session);
I tried with "MAPISend component", this code:
http://prog.hu/tudastar/60044-6/Delphi-Email+csatolt+file+thunderbird.html
and 2 of others.
Interesting, that Acrobat Reader CAN use the MAPI with Attach to email function, and the "Send" "In Mail" context menu also working.
I don't understand why it isn't working, in my machine (Win7) it is working fine.
Then machines where I failed have WinXP OS, and they used Thunderbird.
What I can do to successfully logon into MAPI?
THanks:
dd
I think I found the problem.
The problem, that Delphi needs a Registry value named MAPI under
"HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Messaging Subsystem"
If this not present, it send 1 error code to you what is the base of the confusion.
This value must be string. The sysadmin wrote DWORD, and this caused the problem.
Thanks for your help:
dd
I am using RapWare components, http://www.rapware.nl/
Hth's.
Stanko.
I'm not sure about any Delphi-specific issues, but you don't need to call MAPILogon before calling MAPISendMail. If you do, I wouldn't check the return value. That's why Acrobat Reader was working and your SMAPI client was not.

Resources