Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28630 Discussions

Automatic extraction of e-mail attachments?

michael_green
Beginner
954 Views
Hi All,

I am getting daily automatically generated e-mails from our local weather bureau. The e-mail contains a .zip attachment. I have been trying to find a way to automatically open the e-mail and place the attachment in a standard folder where I can arrange for a Fortran program to deal with it as a scheduled task.

I have downloaded Jugoslav's excellent MAPItest program (from his home page) and tried to modify it to receive e-mails as well as send them, but with no success.

Does anyone have any experience with this sort of thing? I would value any suggestions related to any method of doing this.

With many thanks,
Mike
0 Kudos
13 Replies
Jugoslav_Dujic
Valued Contributor II
954 Views
Mike, sorry, I'm short on time to play with this. From a quck read of MSDN documentation, you need to:

1) Call MAPIReadMail to extract the whole message to a temporary file (now, I'm not sure how you get the lpszMessageID)
2) You get an array lppMessage of MapiMessage structures, each containing nFileCount and lpFiles, pointing to an array of MapiFileDesc structure
3) Each MapiFileDesc contains information about the extracted attachment.




0 Kudos
anthonyrichards
New Contributor III
954 Views
What is your e-mail application? If Outlook, I would consider writing a VBasic program for this. On the other hand, there is a lot of resource out there if you Google it. Try a search for "Visual Basic extract e-mail attachment'. There are some good cheap software that will do this.
0 Kudos
michael_green
Beginner
954 Views
Hi Guys,

Thanks for your input. I am using Outlook 2007. I have already spent many hours searching the Web and have found a wealth of stuff out there, but since I can already use Jugoslav's Fortran to send e-mails I would like to pursue it a little furthre before I try something else.

From my reading of the documentation I believe I need to logon ...

iret = MAPILogon(0, "Microsoft Outlook"C, ""C, 0, 0, LOC(hSession)) !Works OK

Then I must call MAPIFindNext ...

iret = MAPIFindNext(hSession,0,""C,""C,MAPI_UNREAD_ONLY,0,msgID) !Seems to work, but see below

After which I must call MAPIReadMail ...

iret = MAPIReadMail(hSession, 0, msgID, MAPI_BODY_AS_FILE, 0,msg ) !This fails.

I think the problem lies with the call to MAPIFindNext which returns a message ID (msgID). The actual value I get for msgID is always something like BC@>l9&![eR, in other words, what looks like the character representation of a series of random bytes - I would expect to see something I can at least partially read. I have tried dozens of variations of the above but without success.

Many thanks for any further insights.

Mike
0 Kudos
Jugoslav_Dujic
Valued Contributor II
954 Views
Quoting michaelgreen
I think the problem lies with the call to MAPIFindNext which returns a message ID (msgID). The actual value I get for msgID is always something like BC@>l9&![eR, in other words, what looks like the character representation of a series of random bytes - I would expect to see something I can at least partially read. I have tried dozens of variations of the above but without success.

Many thanks for any further insights.

Mike

As I get it, the msgID is an opaque string, i.e. a message handle of sorts, so you cannot deduce anything from its contents.

For each retrieved message, you should call MAPIReadMail with ulUIParam=MAPI_ENVELOPE_ONLY, which would extract only the message header into the MapiMessage structure. If the contents match your filter, only then call MAPIReadMail for that message with full contents & attachments. You will probably want to .OR. the MAPI_PEEK flag, in order to not mark all examined messages as read.

By the way, I've stumbled upon this piece of info on that same page that you may find useful:

File attachments are saved to temporary files, and the names are returned to the caller in the message structure...

The caller is responsible for freeing the MapiMessage structure by calling the MAPIFreeBuffer function and deleting any files associated with attachments included with the message.

0 Kudos
michael_green
Beginner
954 Views
I think I am going to give up on this. I have tried every conceivable combination of flags and other settings but I have never got MAPIReadMail to succeed.

MAPIFindNext does seem to be working OK - I get a different msgID depending on which flag I use, and with MAPI_UNREAD_ONLY, if there are no unread messages, MAPIFindNext tells me so. But MAPIReadMail is a no-go for me, and yetI am sure, from all the reading I have done, I am using it correctly.

Thanks for your help

Mike
0 Kudos
Jugoslav_Dujic
Valued Contributor II
954 Views
If you like, drop me an e-mail with your code (jdujic AT uns.ac.rs). I'd like to take a look (no promises though).
0 Kudos
anthonyrichards
New Contributor III
954 Views
I downloaded the MAPI stuff from Jugoslav's site and tried the test program with the same frustrating results. However, after a nights sleep and a fresh look, I think I stumbled upon the solution to the problem (or, at least, to the the first one).

Check out MAPI.F90. You will find the following:

lpMAPIReadMail = GetProcAddress(hMapiLib,"MAPISaveMail"C)
bOK = bOK.and.(lpMAPIReadMail.ne.0)
lpMAPISaveMail = GetProcAddress(hMapiLib,"MAPIReadMail"C)
bOK = bOK.and.(lpMAPISaveMail.ne.0)

Note that you will now try MAPISaveMail when you think you are trying MAPIReadMail, and vice versa!

When I found this, I corrected the code and the MAPIReadMail FINALLY worked with return code zero.

I used
iret = MAPIReadMail(hSession, 0, MsgID, MAPI_BODY_AS_FILE, 0,newmsg )

but the only item set in the returned message structure newmsg is the first ULRESERVED component. This points to an address in memory where, after a few garbage characters, some real e-mail stuff can be seen, e.g. subject, sender etc. So there is hope!
0 Kudos
anthonyrichards
New Contributor III
954 Views
Here is some intriguing stuff.
After the MAPIReadmail puts a pointer into the UlReserved component, a look at that address yields the attached memory picture.
The Address pointed to is 3E60890.
The first 48 bytes appear to be rubbish, however, if you look at bytes 5 to 8, note that they are C0 08 E6 03.
If you write them in reverse, you get an address 03 E6 08 C0 which is nearby and, lo and behold, if you look at the contents you find that it is the starting point of the message subject text.

Similarly, bytes 17 -20, taken in reverse order, yield 03 E6 08 C0, which is a nearby address that yields the message received date.

Further examination of the memory block yields the path to a temporary file containing the message body, and so on.

So what needs to be discovered is why the extracted data about the message is not being distributed correctly into the MAPIMESSAGE structure, even though the mail message data is being found OK.

(P.S. this was done using CVF and MS DEvStudio. The MAPI32.DLL I have is dated 2004)
0 Kudos
Jugoslav_Dujic
Valued Contributor II
954 Views
I downloaded the MAPI stuff from Jugoslav's site and tried the test program with the same frustrating results. However, after a nights sleep and a fresh look, I think I stumbled upon the solution to the problem (or, at least, to the the first one).

Check out MAPI.F90. You will find the following:

lpMAPIReadMail = GetProcAddress(hMapiLib,"MAPISaveMail"C)
bOK = bOK.and.(lpMAPIReadMail.ne.0)
lpMAPISaveMail = GetProcAddress(hMapiLib,"MAPIReadMail"C)
bOK = bOK.and.(lpMAPISaveMail.ne.0)

.

Damn, and after Mike's post I even double-checked the INTERFACEs in MAPI.f90, but checking this part seemed really over the top. Thanks for spotting that. I suppose I'll have to update the website after some time...

0 Kudos
Jugoslav_Dujic
Valued Contributor II
954 Views
What you describe, Tony, sounds as if one level of indirection is missing somewhere. That "pp" in lppMessage raises suspicion; maybe I misread the original documentation, which reads:

lppMessage [out]

Pointer to the location where the message is written.

While you're at it, what happens if you replace:

[fortran]!DEC$ATTRIBUTES REFERENCE:: lppMessage
type(t_MapiMessage) lppMessage

[/fortran]
with

[fortran]type(t_MapiMessage), pointer:: lppMessage
[/fortran]
(AFAIK, the REFERENCE is not necessary when the argument is pointer?). Since it must be released with MAPIFreeBuffer, I guess that MAPI does the memory (de)allocation, ergo we need a pointer here (a Fortran pointer will do, although integer(LPVOID) is much cleaner interface -- you just need to dereference it with a pointer(lpMessage, newmessage))
0 Kudos
anthonyrichards
New Contributor III
954 Views

You have hit the nail on the head.
The following works:
In MAPI.F90 put

interface
integer function MAPIReadMail(lhSession,ulUIParam,lpszMessageID,flFlags,ulReserved,lppMessage)
!DEC$ATTRIBUTES STDCALL:: MAPIReadMail
use mapity
integer lhSession
integer ulUIParam
!DEC$ATTRIBUTES REFERENCE:: lpszMessageID
character(*) lpszMessageID
integer flFlags
integer ulReserved
!DEC$ATTRIBUTES REFERENCE:: lppMessage
Integer lppmessage
end function
end interface
pointer(lpMAPIReadMail,MAPIReadMail)

In MAPITEST.F90 put

type(t_MapiMessage) :: NewMsg
pointer(lppmessage,NewMsg)
.....
.....
iret = MAPIReadMail(hSession, 0, MsgID, MAPI_BODY_AS_FILE, 0,lppmessage )

and sure enough, when lppmessage is dereferenced, NEWMSG is correctly populated with all the message details!

Well done.

P.S. How to deal with the Originator, Recipients and Files descriptors?

0 Kudos
Jugoslav_Dujic
Valued Contributor II
954 Views
MAPI.zip on xeffort.com is now fixed and updated. Thanks folks.

Since you opened the new thread, I replied there.
0 Kudos
michael_green
Beginner
954 Views
Hi Jugoslav & Anthony,

I have been away for a few days so missed all the interesting discussion between yourselves on this thread and the other one (Dereferencing a C++ array ...). I just want to say thank you for some great input - all my problems are basically solved now. The only potential show stopper in my plan is Outlook's insistence on warning me that a program is trying to read my e-mail - although the trust centre gives an option to allow a program to send e-mail, receiving e-mail doesn't get a mention. If anyone has any ideas ... ?

But thanks again - I learnt heaps.

Mike
0 Kudos
Reply