Jump to content

Mark Williams

Members
  • Content Count

    274
  • Joined

  • Last visited

Everything posted by Mark Williams

  1. I can call LoadFromFile for TIDMessage on a MSG file. However, it has no return value to advise if it has successfully loaded the email. You only seem to know whether it has failed when you attempt to read certain properties eg Date which is returned as a 0 value. Is it therefore safe to assume that an email is in a format TIDMessage cannot read if it returns a 0 value for Date or is there a more reliable way of ascertaining if TIDMessage can read the particular email format?
  2. Mark Williams

    How to detect if TIDMessage is unable to read an email

    It may possibly be unsafe, but it may be the only option and therefore the safest one, albeit not 100% safe. However, I'm asking for alternative and hopefully better solutions from users familiar with TIDMessage who may have encountered this issue. I have tried reading a large number of different emails including MSG. I've also submitted pdf, xml, avi, jpg, pas etc. It will have a crack at anything without complaint. Consistently (and unsurprisingly) it returns 0 for Date for files in an unreadable format (or possibly I should say incorrect format). Every email I have submitted to it in the expected format it has returned a non 0 Date value. However, it is possible (though I suspect unlikely or at least very rare) that there may be emails otherwise in the expected format, but with an incorrect Date header. I would rather my procedure does not return with an unread result in such cases. Unless someone can suggest a more accurate solution, I will go with what I have, but I would just like to hear from someone who has been here before me
  3. Mark Williams

    How to detect if TIDMessage is unable to read an email

    I have worked through the code. Basically, it loads the file (whatever format it may be in) and attempts to parse the headers. If it cannot find a header it move on. So even with an outlook MSG file (which is in a proprietary format that IDMessage cannot read), it gives it a go and outputs something albeit not terribly useful. For the Date header, it calls a separate function that tries to parse the header value and if this is not in the right format it throws up and catches an exception and exits the function return a nil datetime value. I thought that might be the safest thing to use working on the assumption that ALL emails will have a Date header formatted in compliance with the standards and if it cannot be read that must mean that TIDMessage cannot read the format of that particular email. However, I am also aware that the standards are not strictly adhered to in all case and so my assumption is possibly unsafe. If it is unsafe then I am hoping there might be someone who has come up with a more reliable solution.
  4. Mark Williams

    TIDMessage Date

    I want to extract the UTC date time that an email was sent. I cannot work out whether I can just read TIDMessage's Date property or if I have to read the Date header. I am in a time zone that is currently aligned with UTC so I can't tell whether the Date property is UTC or local!
  5. Mark Williams

    TIDMessage Date

    To answer my own question "Yes I am". I can now see the function is converting the datetime to local time after deducting the offset. My error was to change the date on my pc back to the current date before reading the email with TIDMessage. The conversion from UniversalToLocal was being done at today's date when UTC is same as current date time. If I reset my clock back to August and read it again the IDMessage.Date reads the time as 10:02:026 which was the correct local time in August in UK. All very confusing! Of course, the same is also true for my original test with an unfaked email. Oh, the joys of living in a country which insists on changing the time twice a year!
  6. Mark Williams

    TIDMessage Date

    I have tested with an email from September when UK was + 1 hour ahead of UTC. I get the following results: IDMessage1.Date =25/09/2020 08:31:34 Date header: Fri, 25 Sep 2020 09:31:34 +0100 Both parties in UK. The email was received by me just after 09:31 local time. Of course, that doesn't mean it was sent at 9.31. It could have been sent at 8.31 I suppose. I just changed the clock on my pc to a date where UTC different from local time and I then sent myself an email. The results were: IDMessage.Date=14/08/2020 09:02:26 Date Header: Fri, 14 Aug 2020 10:02:26 +0100 The pc clock was at 10:02 when I sent the email. So the date header is showing the local time. IDMessage date seems to me to be showing UTC time. The function for reading the date header in IDGlobalProtocols is: function GMTToLocalDateTime(S: string): TDateTime; var DateTimeOffset: TDateTime; begin if RawStrInternetToDateTime(S, Result) then begin DateTimeOffset := GmtOffsetStrToDateTime(S); {-Apply GMT and local offsets} Result := Result - DateTimeOffset; Result := {$IFDEF HAS_UniversalTimeToLocal}UniversalTimeToLocal(Result){$ELSE}Result + OffsetFromUTC{$ENDIF}; end; end; As I read it, it is converting the date header to a datetime and then deducting the value of the DateTimeOffSet. As the date header (at least in my case) is showing the local time in any event, deducting the offset is going to produce the UTC time. Am I misunderstanding something?
  7. I am trying to work out the best way to batch read emails dropped into a windows explorer folder. I can think of three possibilities, but I can't get any of them to work! MAPI & IMessage This would probably do the job save for the fact that I cannot figure out how to open a file from explorer to use with the IMessage interface. Outlook An outlook MailItem would also probably do the job, but it has no LoadFromFile method and no other obvious method that I can find to load a file into a MailItem object. INDY TIDMessage I have tried with the following code: IDMessage1.LoadFromFile(FileName); with IDMessage1 do begin label6.caption := From.Text; label7.Caption := Recipients.EmailAddresses; label9.Caption := CCList.EmailAddresses; label10.Caption := BCCList.EmailAddresses; Label12.Caption := Subject; Label14.Caption := MsgId; Memo1.Text := Body.Text; end; Filename is a msg file dropped from outlook into explorer. It loads without complaint, but the output is wrong. Eg From.Text returns W is the correct initial for the sender. Recipients.EmailAddresses returns Again M is the correct initial. Subject returns This time with no leading double quote. I assume I am missing something, but I do not know what and I can find no helpful examples. I am looking for something that can reliably read emails in most formats. Don't know if TIDMessage is designed for this purpose. Hopefully someone can help re any of the above or even suggest any other possible solutions.
  8. Mark Williams

    TIDMessage Date

    Easy solution. Just read an older email when UK time was not aligned with UTC! The answer for anyone interested is that TIDMessage's date property shows the UTC time.
  9. Mark Williams

    Batch Reading Emails from Windows Explorer

    So presumably I would have to reinstall INDY every time I install a new version of Delphi? Is there anything wrong with my alternative solution ie copying IDCoderTNef.pas to a separate folder along with IdCompilerDefines.inc. This compiles, although I have not yet tested if it works as I don't have any winmail.dat files.
  10. Mark Williams

    Batch Reading Emails from Windows Explorer

    I tried that route. Added to the protocols folder and then tried to compile IndyProtocols270.bpl. Got an error "Cannot compile package 'IndyProtocols270' which is currently required by Delphi 10.4"
  11. Mark Williams

    Batch Reading Emails from Windows Explorer

    Adding TIDCoderNef.pas to the protocols folder installed with Delphi doesn't work. Compiling fails to locate the unit. Saving it in a different location causes compile to fail whilst trying to find IDCompilerDefines.inc. I have copied the latter from protocols folder. to my new location, which compiles fine. However, is this the right approach or should I be dealing with this in a different way?
  12. Mark Williams

    Batch Reading Emails from Windows Explorer

    No. Definitely version 10. I have a host of IDCoder... units in the protocols folder, but no TIDCoderTNEF. Indy was installed same time as I installed Delphi 10.4. Just been back over the last couple of installs 18.0, 19.0, 20.0 and latest is 21.0. IDCoderTNef is not in the protocols folder of any of these installs.
  13. Mark Williams

    Batch Reading Emails from Windows Explorer

    @Remy Lebeau I have found reference to TIDCoderTNef, but I can't this component nor can I find an IDCoderTNef unit. I can't find anything in the help files either. Has this been replaced? If not, where can I find it please and is there any help on or any examples of how to use it that you are aware of?
  14. Mark Williams

    Batch Reading Emails from Windows Explorer

    I don't want to import the emails into Outlook as it is an unnecessary and added overhead (it's also not as straightforward to do so for EML files as for MSG files). My app needs to deal with EML files on a folder in Explorer. I can read the properties I need quickly using TIDMessage. I then post that data and the file to the server/database. I don't need the overhead of loading them into Outlook before doing this. If TIDMessage could handle MSG files I'd do it the same way. However, it doesn't so I am considering using Outlook to do it for me. But that comes at a cost. So it may be better for me to do as you suggest and use StgOpenStorage just for MSG files. Haven't quite made my mind up yet.
  15. Mark Williams

    Batch Reading Emails from Windows Explorer

    In case anyone is interested, it is fairly straightforward to open a MSG file in an Outlook MailItem (if you know how). Code below (thanks to Dmitry Streblechenko posted on StackOverflow): var App, NS, Msg:Variant; begin App := CreateOLEObject('Outlook.Application'); NS := App.GetNamespace('MAPI'); NS.Logon; Msg := NS.OpenSharedItem(fileName); I've also found a VB example of how to import EML files into Outlook: https://www.howto-outlook.com/howto/import-eml-files.htm. This shows how to import them into an Outlook folder.
  16. Mark Williams

    Batch Reading Emails from Windows Explorer

    I am looking to handle email messages saved to disk in whatever format. I need to open the emails, read certain properties from them and then post the file and the data to a database. If I can do this with just the file (as I can with EML using TIDMessage) then there is no need to fire up Outlook and copy the files into Outlook and then process them.
  17. Mark Williams

    Batch Reading Emails from Windows Explorer

    I am processing the email files for upload to a server. I don't need to add them to Outlook to do this. If I can open and handle them via TIDMessage it will save a significant amount of time.
  18. Mark Williams

    Batch Reading Emails from Windows Explorer

    OK. Thanks for the info. It didn't throw up an exception when trying to open the .msg file. I have decided that possibly the best way to proceed is to use TIDMessage to open and read any emails in the right format and Outlook for any emails TIDMessage can't handle by adding the latter to a temp folder in Outlook, processing and then removing the temp folder (subject to me working out exactly how I do that!). If you or anyone else has any alternative suggestions before I start coding this, they would be really appreciated.
  19. Mark Williams

    Batch Reading Emails from Windows Explorer

    My Malware bytes is preventing access to this site as it believes there is a trojan. Just thought @mitzi would want to know!
  20. Mark Williams

    Batch Reading Emails from Windows Explorer

    I was hoping to find a one-size fits all solution. Off hand do you happen to know if most other email types are also structured storage files? Requiring Outlook wouldn't be an issue, but I think it's MAPI that's needed. I've had a look at the Microsoft docs this returns me an IMessage on top of the storage doc. I have also had a look for some examples of how to deploy OpenIMsgonIStg. Haven't found much on it yet and suspect it will take me some time (form me) to master. Do you (or anyone) happen to know know if the IMessage interface will work with other email types or just Outlook? Before I go down that route, I would really appreciate any feedback on whether TIDMessage can handle MSG files and, if so, how. @Remy Lebeau
  21. Mark Williams

    Batch Reading Emails from Windows Explorer

    Sorry if I didn't make my requirements clear. My app needs to be able to read emails in (hopefully) almost any format that have been dropped into an explorer folder. In my case I dropped them from Outlook so they were saved as .msg. Could be .eml format etc. I don't have control over the email source from which my users will dropping emails into Explorer. Basically, I wish to read the various properties of the email (From, To, CC, BCC, Subject, body, MessageID etc) and add them to a database. But to do that I need to be able to load the emails from a file rather than outlook. And that's where I am getting stuck. By way of update I have just saved an email from GMail to disk (so eml format) and that was read ok by TIDMessage save for the body part, which I assume requires me to read the messageParts. So with TIDMessage the issue seems to be with msg files. As I originally said, I am not particularly bothered how I do this as long as whichever method I adopt it can reliably open and read most email formats.
  22. Mark Williams

    IPropertyStore

    I want to use the IPropertyStore interface to read media file tags. I couldn't find any Delphi examples of how to do this, but I did find a C++ example: C++ Example I am not familiar with C++, but using this example I have got working Delphi code: var Store: IPropertyStore; v: PropVariant; begin if openDialog1.Execute then begin CoInitialize(Nil); SHGetPropertyStoreFromParsingName(pWideChar(openDialog1.FileName), Nil, GPS_READWRITE, IPropertyStore, store); store.GetValue(PKEY_Music_AlbumTitle, v); Showmessage(v.bstrVal); Couninitialize; end; end; This works without complaint (needs the following added to the uses clause WinApi.ShlOBj, WinAPI.ActiveX, WinAPI.PropKey, WinAPI.PropSys;). The C++ example says there is a very important undocumented function: store->release(). The IPropertyStore does not have this function. Does anyone know what if anything I need to do to clean up the IPropertyStore in Delphi after use?
  23. I am using late binding to open Word/Excel documents etc to try to read the built in and custom properties if documents/workbooks. var MSApp, Props, item:Variant; i, int:integer; d:TDateTime; f:Double; s:string; begin MSApp := CreateOLEObject('Word.Application'); MSApp.Documents.OpenNoRepairDialog(filename, false, true, false, password, password, False, password, password, emptyParam, emptyParam, false, true); MSApp.ActiveDocument.Repaginate; Props := MSAPP.ActiveDocument.BuiltInDocumentProperties; for i := 0 to Props.Count do begin item := Props.item[i]; memo1.Lines.Add('Name='+item.Name); case varType(item.value) of varSmallInt, varShortInt, VarInteger, varSingle, varByte, varWord, varLongWord, varInt64: begin int:=item.value; Memo1.Lines.Add('value as int='+int.ToString); end; varDate: begin d:=item.value; Memo1.Lines.Add('value as date='+DateTimeToStr(d)); end; varDouble, varCurrency: begin f:=item.value; Memo1.Lines.Add('value as float='+FloatToStr(f)); end; varBoolean: begin b:=item.value; Memo1.Lines.Add('value as boolean='+ord(b).ToString); end; varOleStr, varStrArg, varString: begin s:=item.value; Memo1.Lines.Add('value as string='+s); end else try s:=item.value; Memo1.Lines.Add('value as somethign else='+s); except end; end; end; I am getting errors and other issues with a number of the properties: DateTime There are three date time properties in the built in properties: Last print date Creation date Last save time My function fails with the print date and the last save time. I get an EOLEExecption "unspecified error" when querying the VarType of the item value (case varType(item.value) ). I don't get an error for Creation date, however, the creation date is always read as the current date time, regardless of what the properties of the document actually says. The format of all three dates appears identical in the document properties. Pages, word count ,number of characters etc Pages always returns 1 regardless of number of pages. I thought calling Repaginate first might resolve this, but it didn't. Word & character count always return 0 (which is incorrect). Any help with the above appreciated. Thanks.
  24. Mark Williams

    MS Office BuiltInDocumentProperties and CustomDocumentProperties

    Thanks, but no need for apology!
  25. Mark Williams

    MS Office BuiltInDocumentProperties and CustomDocumentProperties

    I though I stated that I was trying to read the BuiltInDocumentProperties of office documents and that I was having difficulties reading certain of those properties. I also provided the code and stated what were the problems I was experiencing. I'm not sure what further info was relevant. I wish to proceed, if at all possible (and I don't see why it shouldn't be) with OLE late binding to open the office documents (I need to save them in pdf format) and then read their BuiltInDocumentProperties whilst I have the document open. I appreciate your recommendation of OOXML, but I don't really have time to delve into this at the moment and would prefer to use BuiltInDocumentProperties, particularly as I have to open the document via its relevant MS app in any event.
×