Practical Use of MAPI
Practical Use of MAPI
Hi everyone, I’m Jay Ongg, ready to do more with MAPI. Last time, I wrote a function that displays the names of all the message accounts on your device. In this article, I’ll go a little bit further. I’ll talk a bit about how to manipulate folders, messages, and properties. This post is a bit code-heavy, but if you have any questions about it please feel free to ask (note this is sample code with some error checking thrown in), but I know that there are some ISVs who need some help with this. Rather than answering questions one at a time, I figure it’s more efficient to do this post). Hopefully my color-coded comments in the code (alliteration!) can explain what’s going on.
One thing that I really want is a way to back up my text messages. I’m going to present a function that will take an account name and ultimately, pass some message information to a function. This can be the basis of more advanced MAPI property manipulation.
Top-Level Function
HRESULT SaveSmsMessages(IMAPISession *pSession, LPCTSTR pszFilename)
{
static const SizedSPropTagArray (2, spta) = { 2, PR_DISPLAY_NAME, PR_ENTRYID };
HRESULT hr;
SRowSet *prowset = NULL;
CComPtr<IMAPITable> ptbl;
CComPtr<IMsgStore> pStore;
// Get the table of accounts
hr = pSession->GetMsgStoresTable(0, &ptbl);
CHR(hr);
// set the columns of the table we will query
hr = ptbl->SetColumns((SPropTagArray *) &spta, 0);
CHR(hr);
while (TRUE)
{
// Free the previous row
FreeProws (prowset);
prowset = NULL;
hr = ptbl->QueryRows (1, 0, &prowset);
if ((hr != S_OK) || (prowset == NULL) || (prowset->cRows == 0))
break;
ASSERT (prowset->aRow[0].cValues == spta.cValues);
SPropValue *pval = prowset->aRow[0].lpProps;
ASSERT (pval[0].ulPropTag == PR_DISPLAY_NAME);
ASSERT (pval[1].ulPropTag == PR_ENTRYID);
if (!_tcscmp(pval[0].Value.lpszW, TEXT("SMS")))
{
// Get the Message Store pointer
hr = pSession->OpenMsgStore(0, pval[1].Value.bin.cb, (LPENTRYID)pval[1].Value.bin.lpb, 0, 0, &pStore);
CHR(hr);
SaveMessages(pStore, pszFilename);
}
}
Error:
FreeProws (prowset);
return hr;
}
This function is similar to the function that I wrote last time. Instead of displaying the account names, I instantiate a message store object and navigate into it. The function iterates through each account, searching for SMS. Once the SMS row is found, we know that pval[1] has the ENTRYID of the associated message store object. Every MAPI object has a unique id, called the ENTRYID. The ENTRYID is always stored in the PR_ENTRYID property, which is a binary property (remember, you can tell the type of the property based on the definition of the constant).
We can then call IMAPISession::OpenMsgStore in order to obtain an IMsgStore pointer. From here, I call a new function, SaveMessage(), passing it the IMsgStore pointer along with the filename to write to.
SaveMessages
Sorry to have to give you such a big function, but this is somewhat similar to what we did to get the accounts. As above, we have to obtain a table of records, set the columns, and iterate through it. To clarify the code better, I’ll use inline comments to describe the important steps. MAPI requires quite a few stpes to do seemingly simple things. Hopefully this is a good technique for larger functions J.
HRESULT SaveMessages(IMsgStore *pStore, LPCTSTR pszFilename)
{
static const SizedSSortOrderSet(1, sortOrderSet) = { 1, 0, 0, { PR_MESSAGE_DELIVERY_TIME, TABLE_SORT_DESCEND } };
static const SizedSPropTagArray (3, spta) = { 3, PR_SENDER_NAME, PR_SUBJECT, PR_MESSAGE_DELIVERY_TIME };
HRESULT hr = S_OK;
LPENTRYID pEntryId = NULL;
ULONG cbEntryId = 0;
CComPtr<IMAPIFolder> pFolder;
CComPtr<IMAPITable> ptbl;
ULONG ulObjType = 0;
SRowSet *prowset = NULL;
// 1 First retrieve the ENTRYID of the Inbox folder of the message store
// Get the inbox folder
hr = pStore->GetReceiveFolder(NULL, MAPI_UNICODE, &cbEntryId, &pEntryId, NULL);
CHR(hr);
// 2 we have the entryid of the inbox folder, let's get the folder and messages in it
hr = pStore->OpenEntry(cbEntryId, pEntryId, NULL, 0, &ulObjType, (LPUNKNOWN*)&pFolder);
CHR(hr);
ASSERT(ulObjType == MAPI_FOLDER);
// 3 From the IMAPIFolder pointer, obtain the table to the contents
hr = pFolder->GetContentsTable(0, &ptbl);
CHR(hr);
// 4 Sort the table that we obtained. This is determined by the sortOrderSet variable
hr = ptbl->SortTable((SSortOrderSet *)&sortOrderSet, 0);
CHR(hr);
// 5 Set the columns of the table we will query. The columns of each row are determined by spta
hr = ptbl->SetColumns ((SPropTagArray *) &spta, 0);
CHR(hr);
// now iterate through each message in the table
while (TRUE)
{
// Free the previous row
FreeProws (prowset);
prowset = NULL;
hr = ptbl->QueryRows (1, 0, &prowset);
if ((hr != S_OK) || (prowset == NULL) || (prowset->cRows == 0))
break;
ASSERT (prowset->aRow[0].cValues == spta.cValues);
SPropValue *pval = prowset->aRow[0].lpProps;
// 6 Get the three properties we need: Sender name, Subject, and Delvery time.
ASSERT (pval[0].ulPropTag == PR_SENDER_NAME);
ASSERT (pval[1].ulPropTag == PR_SUBJECT);
ASSERT (pval[2].ulPropTag == PR_MESSAGE_DELIVERY_TIME);
LPCTSTR pszSender = pval[0].Value.lpszW;
LPCTSTR pszSubject = pval[1].Value.lpszW;
SYSTEMTIME st = {0};
FileTimeToSystemTime(&pval[2].Value.ft, &st);
// 7 Pass the parameters to a function to archive (this function is not written)
hr = AppendToFile(pszFilename, pszSender, pszSubject, st);
CHR(hr);
}
Error:
FreeProws (prowset);
MAPIFreeBuffer(pEntryId);
return hr;
}
Hope this helps. Next time I’ll talk about creating an Outlook menu extension, as well as some helpful APIs I haven’t talked about yet.
Comments
Anonymous
April 23, 2007
Is there any way to access my pocket outlook Email (specifically Activesynced email) through managed code? As far as I could tell digging through MSDN, it's possible to send e-mail but not access my actual messages.Anonymous
April 23, 2007
Hi Union, You can do this type of stuff in managed code. Take a look at the comments in http://blogs.msdn.com/windowsmobile/archive/2007/03/21/getting-started-with-mapi.aspx Hopefully you can get some pointers and things to look up in MSDN from there.Anonymous
April 23, 2007
Can you tell us why the SMS message is retrieved through the subject property instead of body? I would also like to see a topic on sending SMS messages. Last time I tried that the message stayed in the outbox folder. I had to use SMS API to send SMS messages. I am just curious, I too have moved on to the managed world.Anonymous
April 23, 2007
Hi, I wasn't around when whoever designed SMS did it, so I don't really know the answer. My guess would be that it's faster to read from PR_SUBJECT (which is just a string) instead of PR_BODY (where you have to open an IStream). Since most SMS's are limited in size, PR_SUBJECT made more sense. As for how to send SMS's, what did you try that failed?Anonymous
April 23, 2007
Hi, I checked some old sources dated back in 2002. Here's what I tried, rough pseudo code: Get drafts folder (PR_CE_IPM_DRAFTS_ENTRYID). Create message. Set recipient. Set the message subject. And finally SubmitMessage(0) for the message. As far as I recall the message went to outbox just fine but stayed there until the user opened the outbox and resent the message. Anyway, all this happened long, long time ago. May be I made some mistake or may be it was a real problem with the device I used back then (O2 XDA PPC 2002 phone-edition). SMS API solved the problem so I did't thought about MAPI anymore for sending messages.Anonymous
April 24, 2007
HarriK Take a look onto this aticle: http://www.wimobot.com/wmapps/mobilesecretary/ . Mobile Secretary has been writen by BCross: http://blogs.msdn.com/windowsmobile/archive/2006/10/23/the-mobile-secretary.aspxAnonymous
April 25, 2007
I would like to point out that currently Microsoft.WindowsMobile.PocketOutlook has the ability to:
- Enumerate messaging accounts.
- Send Email
- Send SMS
- Intercept SMS Currently it does not allow you to enumerate folders, or enumerate messages in folders. That said, you can always use DllImports to get that functionality from native MAPI. Thanks, -Luis Cabrera
Anonymous
April 26, 2007
Surely someone must have gone through the trouble of DllImporting all these functions already? Anyone?Anonymous
April 26, 2007
Hi Doug, I'm not sure if you would want to use DllImport versions of these methods, or use the managed Microsoft.WindowsMobile.PocketOutlook classes. The latter is cleaner in C# and comes installed with Windows Mobile SDKs.Anonymous
April 26, 2007
The comment has been removedAnonymous
April 27, 2007
The managed Microsoft.WindowsMobile.PocketOutlook interface seems very limited in its abilities with messaging accounts. As LuisCa said, "Currently it does not allow you to enumerate folders, or enumerate messages in folders." I would like to be able to add and delete emails from the message stores, just as I can with contacts or appointments.Anonymous
April 28, 2007
i have the same problem as Doug has. i want to delete sms and arrange them based on certain filtering options.. As LuisCa said, "Currently it does not allow you to enumerate folders, or enumerate messages in folders." so wats the way around for this in managed code?? Thanks, kapilAnonymous
April 29, 2007
How can I retrieve the attachment of the email on windows mobile device?Anonymous
April 29, 2007
Hi Eric, look at IMessage::GetAttachmentTable - you can then get attachments from this table. http://msdn2.microsoft.com/en-us/library/ms860101.aspxAnonymous
May 01, 2007
Hi Jay, i'm creating a new folder in mapi using createFolder() and than i try to switch to that folder using MailSwitchToFolder() which returns E_FAIL,, can we switch to folders created using createFolder()?? Thanks kapilAnonymous
May 01, 2007
Hi kapil, MailSwitchToFolder should work. What parameters are you passing to CreateFolder, on which account, and what parameters are you passing to MailSwitchToFolder?Anonymous
May 01, 2007
Hi Jay, thanks for your prompt reply.. i am doing the following steps: ULONG cbEntryId = 0; CComPtr<IMAPIFolder> pFolder; LPMAPIFOLDER pfld=NULL; LPTSTR lpszFolderName=_T("TempFolder"); LPSPropValue pPropVals; //(here pStore is the SMS store) hr = pStore->GetProps (&propDefaultFolder, MAPI_UNICODE, &cbEntryId, &pPropVals); SBinary& eidInbox = pPropVals->Value.bin; hr = pStore->OpenEntry(eidInbox.cb, (LPENTRYID)eidInbox.lpb, NULL, MAPI_MODIFY, NULL, (LPUNKNOWN*)& pFolder); CHR(hr); hr=pFolder->CreateFolder(NULL,lpszFolderName,NULL,NULL,MAPI_UNICODE,&pfld); CHR(hr); propDefaultFolder.aulPropTag[0] = PR_ENTRYID ; hr=pfld->GetProps(&propDefaultFolder, MAPI_UNICODE, &cbEntryId, &pPropVals); eidInbox = pPropVals->Value.bin; hr = pStore->OpenEntry(eidInbox.cb, (LPENTRYID)eidInbox.lpb, NULL, 0, NULL, (LPUNKNOWN*)& pfld); hr = MailSwitchToFolder((LPENTRYID)eidInbox.lpb,eidInbox.cb); //the last statement returns E_FAIL as result sorry for the lengthy code.. i had to write it to explain my problem :(.. thanks kapilAnonymous
May 01, 2007
Another thing to add.. the folders are created as subfolders of the Inbox folder and i can switch to them manually using stylus on emulator. so only problem is with switching programmatically .. i guess there's some hierarchy problem..?? thanks kapilAnonymous
May 03, 2007
anyone there??? i 'm stuck with this mailswitchtofolder()....:(Anonymous
May 04, 2007
Jay, I found this article very informative. You have shown how to access SMS folder. Following a path of logical extension, I tried developing code for accessing the IMAP4 Inbox folder. I could access most of the properties of the emails. Only the Body of the email was what where I got stuck. I used the OpenProperty()method of Messages with PR_CE_MIME_TEXT property. The stream interface which I used with that, returns no data. It would be great if you could write another small article on how to access the Body of Email, especially IMAP4... BR, AL.Anonymous
May 04, 2007
Hi AL, to access the body, you have to create a stream. You get the stream from the PR_BODY property. Look into IMessage:OpenProperty, and output it into an IStream pointer. From there you can read/write to the stream.Anonymous
May 05, 2007
hi, when i try to use MailSwitchToFolder to switch to a folder created using Createfoder() method on win mob 6 professional emulator i get E_FAIL as result. but when i use the same code on win mob 5 pocket pc phone emulator i get S_OK as result but no switching occurs. is this a bug?? thanks kapilAnonymous
May 06, 2007
Hi Kapi, Try contacting me offline. I'm unsure as to why the folder doesn't work. You may need to set some properties.Anonymous
May 06, 2007
hi Jay, can u please tell me your contact info... thanks kapilAnonymous
May 06, 2007
Hi Kapil, for the Microsoft employees who post, you can find out email addresses by taking our blog name @microsoft.com. I hesitate to post my email explicitly to avoid spam crawlers.Anonymous
May 06, 2007
Ok Jay, i understand ur problem.. i'll try contacting u .. if feasible than u can drop me a mail on my email id. thanks kapilAnonymous
May 07, 2007
Hi Jay, Thanks for your response. I have already tried the PR_BODY property and it returns error. From what I have read in the blogs about CEMAPI, is that, the PPC2003 supports the PR_BODY property, but with WM5.0 this property is no longer supported and instead the PR_CE_MIME_TEXT property is used with body of email available as MIME output. Please have a look at the code snippet below for understanding my issue, I am using WM5.0 Pocket PC SDK. Anyway, the PR_CE_MIME_TEXT property does return succesfully, but I don't know how to decode the MIME output. Is there any method to decode the MIME output from Stream to text readable format. //---------------------------------------------------- hr = pMsg->OpenProperty(PR_BODY, &IID_IStream, STGM_READ, MAPI_MODIFY, (IUnknown **)&pStm); if (hr != S_OK) { MessageBox(_T("PR_BODY FAILED"),_T("Warning"), MB_OK); return; } TCHAR cMsgBody[255]; ULONG NoBytesRead = msgsize; ULONG cbCount; hr = pStm->Read(cMsgBody, 254, &cbCount); contdbgstatic.SetWindowTextW((LPCTSTR)cMsgBody); //---------------------------------------------------- Thanks, AL.Anonymous
May 07, 2007
Hi AL, PR_BODY will work with certain messages. as for PR_CE_MIME_TEXT decoding, you probably will have to decode it - the MIME formats are all documented (in non-MSFT documentation).Anonymous
May 07, 2007
Jay, I found that the "ActiveSync" Email account provides the email-body as a ASCII (CHAR) text stream... But the IMAP4 appears to be MIME encoded... Now I am researching on MIME parsers, which I can fit into my application. Thanks for your help. BR, AL.Anonymous
May 08, 2007
Hi Jay, I create folder using the statement hr=pFolder->CreateFolder(NULL,lpszFolderName,NULL,NULL,MAPI_UNICODE|OPEN_IF_EXISTS,&pfld);. where pFolder is the parent folder created using PR_IPM_WASTEBASKET_ENTRYID Then i get the entry id of the created folder using the following code : propDefaultFolder.cValues = 1; propDefaultFolder.aulPropTag[0] = PR_ENTRYID ; hr=pfld->GetProps(&propDefaultFolder, MAPI_UNICODE, &cbEntryId, &ptempVals); And, then I do mailswitchtofolder. The code is hr = MailSwitchToFolder((LPENTRYID)ptempVals[0].Value.bin.lpb,ptempVals[0].Value.bin.cb); The folder doesnt show. But, if I open up messaging application where the folder tree view is shown, then simply close the messaging appln and go back to my application and again run mailswitchtofolder, It works...my folder shows up in list view. Strange !! Seems I m missing some proprty or step. any idea what property needs to be set?? thanks KapilAnonymous
May 08, 2007
Hi Kapil, can you send me an email privately? The way you leave comments, I cannot answer you privately, and I'd like to talk about this outside the forum.Anonymous
May 08, 2007
Hi Jay, I try to get the attachment table by GetAttachmentTable(), but I don't know how to save the attachment to a file on the windows mobile device. Could you please tell me how to do this? Thank you. EricAnonymous
May 08, 2007
Hi Eric, Have you looked into IMessage::OpenAttach and finding the properties of the attachment?Anonymous
May 08, 2007
Hi Jay, I can save the attachment to a file now. Thanks for your help. EricAnonymous
May 09, 2007
great! Just curious what was the problem (you can email me privately if you want)?Anonymous
May 09, 2007
Hey Jay, I am trying to access the PR_SENDER_NAME property for the OUTLOOK E-Mail account ("ActiveSync"), and it gives me something which doesn't look like SENDER NAME I checked this, ASSERT (pval[0].ulPropTag == PR_SENDER_NAME); the ulPropTag shows 0x000a while the PR_SENDER_NAME = 0x0C1A. This means its not mapped properly. What could have gone wrong... Now its 2 things I am not able to get, PR_BODY and PR_SENDER_NAME... BR, AL.Anonymous
May 09, 2007
Hi AL, that property does not exist on the message store, only for messages. You may want to look at the PR_EMAIL_ADDRESS - that is set for message accounts like POP3 and IMAP, am not sure if it's set for Activesync (although if it's not now, it will be in the future).Anonymous
May 09, 2007
hi all, this article really help. so, how to save sent item or get sent item folder from smartphone? sorry for my englishAnonymous
May 09, 2007
eantaru, you can look at the IMessage interface to see how to save a message. to get a sent message, you have to navigate to the Sent Items folder, and enumerate the messages. Then you can find the message.Anonymous
May 10, 2007
jayongg, should i create folder first before read the data from sent item folder? because, i dont know how to open it and read per messages. like the sample that can read per sms inbox, but for sent item thanks beforeAnonymous
May 10, 2007
here the code: HRESULT smsHelper::GetSMSMsgStore(const CComPtr<IMAPISession>& spSession, CComPtr<IMsgStore>& spMsgStore) { // first we get the msgstores table from the session CComPtr<IMAPITable> spTable; HRESULT hr = spSession->GetMsgStoresTable(MAPI_UNICODE, &spTable); if (FAILED(hr)) { //AfxMessageBox(IDS_SMS_FAIL_MSGSTORE_TABLES); return FALSE; } // next we loop over the message stores opening each msgstore and // getting its name to see if the name matches SMS. // If it does then we break out of the loop while (TRUE) { SRowSet* pRowSet = NULL; hr = spTable->QueryRows(1, 0, &pRowSet); // If we failed to query the // rows then we need to break if (FAILED(hr)) { //AfxMessageBox(IDS_SMS_FAILEDTABLE); break; } // if we got no rows back then just exit the loop //remembering to set an error if (pRowSet->cRows == 1) { ASSERT(pRowSet->aRow[0].lpProps->ulPropTag == PR_ENTRYID); SBinary& blob = pRowSet->aRow[0].lpProps->Value.bin; hr = spSession->OpenMsgStore(NULL, blob.cb, (LPENTRYID)blob.lpb, NULL, 0, &spMsgStore); if (FAILED(hr)) //AfxMessageBox(IDS_SMS_FAILED_OPENMSGSTORE); ; } else { //AfxMessageBox(IDS_SMS_MSGSTORENOTFOUND); hr = HRESULT_FROM_WIN32(ERROR_NOT_FOUND); } // now remember to free the row set FreeProws(pRowSet); if (FAILED(hr)) { break; } // now get the display name property from the // message store to compare it against the name // 'SMS' SPropTagArray props; props.cValues = 1; props.aulPropTag[0] = PR_DISPLAY_NAME; ULONG cValues; SPropValue* pProps = NULL; hr = spMsgStore->GetProps(&props, MAPI_UNICODE, &cValues, &pProps); if (FAILED(hr) || cValues != 1) { //AfxMessageBox(IDS_SMS_FAILED_GETNAME); break; } // if the name matches SMS then break and as // hr == S_OK the current MsgStore smart pointer // will correctly be set. if (_tcsicmp(pProps[0].Value.lpszW, _T("SMS")) == 0) { break; } } // if we failed for some reason then we clear out // the msgstore smartpointer and return the error. if (FAILED(hr)) { spMsgStore.Release(); } return hr; } HRESULT smsHelper::GetSMSFolder(const CComPtr<IMsgStore>& spMsgStore, CComPtr<IMAPIFolder>& spFolder) { // Now get the Drafts folder. SPropTagArray propDefaultFolder; propDefaultFolder.cValues = 1; propDefaultFolder.aulPropTag[0] = PR_CE_IPM_DRAFTS_ENTRYID;// PR_CE_IPM_INBOX_ENTRYID; ULONG cValues; LPSPropValue pPropVals; HRESULT hr = spMsgStore->GetProps (&propDefaultFolder, MAPI_UNICODE, &cValues, &pPropVals); if (FAILED(hr)) { //AfxMessageBox(IDS_SMS_FOLDERNOTFOUND); return hr; } SBinary& eidDrafts = pPropVals->Value.bin; hr = spMsgStore->OpenEntry(eidDrafts.cb, (LPENTRYID)eidDrafts.lpb, NULL, MAPI_MODIFY, NULL, (LPUNKNOWN*)&spFolder); if (FAILED(hr)) { //AfxMessageBox(IDS_SMS_FOLDERNOTOPENED); AfxMessageBox(_T("error")); } return hr; } HRESULT smsHelper::SendSMSMessage(const CComPtr<IMAPISession>& spSession) { // now get the SMS message store CComPtr<IMsgStore> spMsgStore; HRESULT hr = GetSMSMsgStore(spSession, spMsgStore); if (FAILED(hr)) { return hr; } CComPtr<IMAPIFolder> spFolder; hr = GetSMSFolder(spMsgStore, spFolder); if (FAILED(hr)) { return hr; } CComPtr<IMessage> spMessage; //here, //i dont know what i supose to do then //i want to see each message from sent item folder return FALSE; } BOOL smsHelper::DoGetSentItem() { HRESULT hr = MAPIInitialize(NULL); if (FAILED(hr)) { //AfxMessageBox(IDS_SMS_FAIL_MAPIINIT); return hr; } else ; // initialized the MAPI subsystem CComPtr<IMAPISession> spSession; BOOL bRet = FALSE; hr = MAPILogonEx(0 ,NULL, NULL, 0, &spSession); if (FAILED(hr)) { //AfxMessageBox(IDS_SMS_FAIL_MAPILOGON); } else { bRet = SUCCEEDED(SendSMSMessage(spSession)); spSession->Logoff(0, 0, 0); spSession.Release(); } MAPIUninitialize(); return bRet; }Anonymous
May 18, 2007
Hi jayongg, i'm a vietnamese, i'm a female final-year student, field of information technology. At present, i meet with difficulties, my theme is programming for pocket pc in visual C++, main function is convert system time into correlative text(example: 1:00 am into "Mot", then write a function convert that text into voice that recorded and processed from my voic( example: from the function's result above, i have a string "Mot", then play a correlative wav file,ex:Mot.wav). My trouble is i have never programed for pocket pc, in addition i see visual C++ is difficult to understand and complex for me. i don't know where begin, i have not material and can't find material, my friends can not help me,hopefully you help me, i'm at a standstill, please send material and give practical advices for me. (i use Visual Studio 2005 tool), thank you very much indeed. hearing from you soonAnonymous
May 20, 2007
I have a serivce application which consists of both C# and C++ modules. What I want's is to catch the email sent event and do some insertion in DB. That is when ever some body send an email from the device I want's to catch that event. Any solution in managed or unmanaged can be worth. Please if any bosy have an idea then let me know Thanks and Kind regards.Anonymous
June 05, 2007
Hi Jay, Is it possible to get the notifications in my application from listview created by MailSwitchToFolder() function. Thanks and Regards, SunishaAnonymous
June 06, 2007
I need to develop a custom Add in which must capture the Send event from the Pocket Outlook. Is there any code snippet in C# that I can make use of for the same Thanks in AdvanceAnonymous
June 24, 2007
Hi, My MMS messages are blocked by outbox. Is there any way to get rid of this issue?Anonymous
June 25, 2007
Hi "test", without more info it is tough to tell you what's going on. In addition, Microsoft doesn't make MMS clients - you need to contact your operator/OEM and find out what's going on.Anonymous
June 26, 2007
What would have to be done to embed SaveMessages into a .dll that can be invoked from C#? POOM is nice enough to give the account names, as mentioned here before. It would be really handy with a library function that can store a directory based on those strings. C++ seems so aliene these daysAnonymous
June 26, 2007
Hi Lobo, If you wish to export SaveMessages, it is possible as a standard export in a DLL. Then you can write a C# wrapper to P/Invoke it. Hope that helps. You may need to write some more C++ to get an IMsgStore (see the first post in this series) and pass it to SaveMessages. Thanks, JayAnonymous
June 27, 2007
Hi, Is it possible to get the notifications in my application from listview created by MailSwitchToFolder() function. Thanks and Regards, SunishaAnonymous
June 28, 2007
If you're looking to be notified when a user switches folders, that is not possible (I think).Anonymous
July 04, 2007
Hi all, who know the way to get properties in compose email screen of Pop3/pocket? i mean that get CC,BCC,FROM... Thanks. dzungtran.Anonymous
July 08, 2007
Hey Jay, these postings have been very helpful - thanks so much! I'm having a frustrating problem when my app is processing messages at the same time as the phone is synchronizing to pull down new activesync mail. When I time it just right it manifests as either a Datatype Misalignment or Access Violation. Last time the debugger landed on the call to IMAPITable QueryRows. All I do is loop thru the message stores and then thru the messages. Using vs2005 with win mobile 5 smartphone sdk on a motorola q. Any ideas? Is there something besides checking return codes that I need to coexist and play nice with MAPI?Anonymous
July 10, 2007
I heard that Microsoft was working on Deepfish mobile browser. Have you guys checked out Picsel Browser? It works on Windows mobile and is awesome (much better than pocket IE). There is no retail version available on their website (they sell it to OEM) but I found a copy in a user forum and tried it on WM5. Reminded me of the iPhone browser and has similar touch interface and zooming capabilities. I think Microsoft should buy that company and acquire its patent. Here is their website: http://www.picsel.com/index.php/solutions/view/C11/ (I am not affiliated with this company whatsoever)Anonymous
July 19, 2007
I've tried everything to get at the recipients but it tells me there are none. Anyone know why? pFolder->OpenEntry(pval[0].Value.bin.cb, (LPENTRYID)pval[0].Value.bin.lpb, NULL, 0, &ulObjType, (LPUNKNOWN*)&pMsg); hr = pMsg->GetRecipientTable(0, &iTable); hr is always MAPI_E_NO_RECIPIENTS.Anonymous
July 27, 2007
How can we insert a sms entry into the message store table.Anonymous
July 27, 2007
selva, you will need to create a new message. Look into CreateMessage().Anonymous
July 29, 2007
I tried using the above code. I am getting a value : pval[0].ulPropTag=10. Can you tell me which property this 10 referes to :Anonymous
July 30, 2007
One more to add. I got this above value " pval[0].ulPropTag=10." when i tried to get the Props of the Inbox settingthe SPropTagArray STags = { 1,{ PR_SENDER_NAME}}; How to get the prop of inbox using pStore->GetProps if i use the displayname, it gives the inbox of the mail. But i want the inbox of sms. can u help . selvaAnonymous
August 13, 2007
Hello Everybody, I need to count all the SMS messages and to read all of them too. For the moment I have written a code that works fine with all the predefined sms folders:
- I get the IMsgStore for sms.
- Then I get the required folder using GetProps with a predefined folder type tag
- Then OpenEntry to get the IMAPIFolder
- GetProps with PR_CONTENT_COUNT But I guess I will encounter problems when a custom folder will be created. I won't be able to get its property tag or even know whether it exists. How can I enumerate all the folders? Is it possible to do using some other interface perhaps a low level one? Really need help on the subject. Thanks in advance and Best Regards, Vladimir
Anonymous
August 21, 2007
Hi, can I put a contextmenu-item on the inbox messages using C#? I'm not a C++ userAnonymous
September 08, 2007
any thoughts on why im only getting a few sms and not all of them?Anonymous
September 10, 2007
Hello! Like many here, I need to access the SMS messages in the Inbox folder on my smartphone. Is there any way to do this with managed code? I'm using Compact Framework 2.0 in a Smartphone with Windows Mobile 5.0 Smartphone and doing this project in C#. The SmsAccount doesn't give me almost any options (Dispose(), Send() and Name), so how can I do this? Thanks in advance for any help, PauloAnonymous
September 12, 2007
Hi there I have exactly the same problem as Paulo above. Jay - thanks for an excellent, and informative posting - but, unfortunately, when people start asking about managed code examples half way through the comments, you suddenly seem to go a bit quiet! As has been pointed out, the windowsmobile.pocketoutlook namespace does contain SMSAccount and EmailAccount objects, but they lack functions to enumerate and read messages. Do you have any examples of wrapper functions, or ways to do this from managed code? CarlAnonymous
October 02, 2007
Hi, Can you tell me where I can find code sample which is sending e-mail with attachment using managed code. Thanks, JakeAnonymous
October 04, 2007
Hi, On Windows Mobile 5.0, I'm getting a crash when I try to do an OpenEntry() using a PR_ENTRYID obtained from a previous MAPI session. As the documentation indicated, in the previous session I opened the item and used GetProps() to make sure I have the 'persistent' ID rather than the one for this session. I even get a crash if I just try to do an OpenEntry() on the PR_ENTRYID of a store. I believe I have valid values for each of these because if I enumerate through the stores and use CompareEntryIDs(), I get the right match on the store. On the message, I can call MailDisplayMessage() with my message PR_ENTRYID and it works properly. Can you give me some hints on what I might be doing wrong? If MailDisplayMessage() can find the message, there should be a way for my code to do it also, right?Anonymous
October 24, 2007
Hi, i was sucessfull in reading the SMS that comes to the inbox. Now i am trying to read the MMS. How can i parse the property's of MMS. I can able to get only the PR_SUBJECT of the Message. Hope some one help me:( selvaAnonymous
November 03, 2007
Hi, Very fast help in every aspect. I am making a backup tool for mobile. I have successfully got all the SMS in the sent folder. I got the text in SMS, time of SMS. But I am not getting the number to which the SMS was sent. PR_SENDER_NAME gives the number for Inbox messages. But it doesn't work for sent messages. Any help friends.Anonymous
December 18, 2007
Hi, I want to know how to write an SMS in the Inbox. What I am trying to do is implement a backup and restore (SMS) feature on Pocket PC. "Restore" means I have to read the SMSes from a persistent store and write it back into the Inbox. I have the necessary information, like Sender Mobile Number and the message body. I am even able to write the message body in the Inbox. But, I can't find a way to write the Sender number for this message, so the message appears in the Inbox without the Sender Number now. Any idea how to go about it?Anonymous
January 10, 2008
I use WM 6.0 for Pocket PC. Is it possible to associate single Message store with two Messaging transport. ex MMS and SMS transportAnonymous
January 11, 2008
Yes, it is possible. This has been done by various third party MMS providers in the past. Have your MMS message get created into SMS account, and set the message class to IPM.MMS, and add that to the MsgClasses registry key under SMS.Anonymous
January 14, 2008
I have done the same.But MMS Transport DLL(Custom) does not load and Initialize.I think without MMS account its not possible. Do you sujjest any way to load MMS transport DLL with only SMS account?Anonymous
January 15, 2008
Can I tell if a message is still actively being received or that synchronization is happening?Anonymous
January 15, 2008
you can tell if Activesync is syncing (music, messages, contacts, calendar, tasks) by looking up the following reg value: HKEY_LOCAL_MACHINESystemStateActiveSync "Synchronizing" You can't tell if a particular message is currently being downloaded. You can tell if a message is partially downloaded by getting PR_MSG_STATUS,and checking for MSGSTATUS_HEADERONLY or MSGSTATUS_PARTIAL (look up these constants and its neighbors in cemapi.h).Anonymous
January 16, 2008
hi jayongg, could you sujjest any way to load MMS transport DLL with only SMS account?Anonymous
January 16, 2008
The comment has been removedAnonymous
January 16, 2008
Hello Manish, I'm not sure that's possible.Anonymous
January 16, 2008
Thankyou Jayongg for prompt reply...Anonymous
January 17, 2008
hello jayongg, I would like to know how to read the from/body of an sms. Can you share a pc of code which can guide me regarding this? thanksAnonymous
January 17, 2008
Ashish, look at the SaveMessages() function in this blog post. it does that. SMS messages keep the body in PR_SUBJECT, not PR_BODYAnonymous
January 17, 2008
Hi Jay! Could please tell me why can I retrieve the PR_CE_SMS_RAW_HEADER property? I would like to check some bytes into the SMS message header he same way the J2ME applications does when using JSR-120 specification.Anonymous
January 23, 2008
Hi Jay, I'm trying to intercept incoming SMS on a specific port. I've successfully gotten the WM2006-TV_Inbox sample to intercept incoming SMS messages through the custom RuleClient, but I need access to the SMS port information, and don't see it anywhere in the MAPI. Can you explain how the MAPI relates to the SMS API? Are they compatable? Are they alternate, but non-compatable APIs? How would I use the SMS API against individual messages in the MsgStore? Can this be done? Can I retrieve messge entries from the store and cast them as SMS messages? Are there converters? How would I get at the WCMP_PROVIDER_SPECIFIC_DATA and WDP_PROVIDER_SPECIFIC_DATA from MAPI? Thanks, DDAnonymous
January 23, 2008
Hi, what port data are you talking about? WDP ports over SMS? The SMS API deals with managing SMS's, but MAPI deals with managing messages. Windows Mobile uses the SMS APIs to read SMS messages and drop them into MAPI with properties set. SMS API cannot be used against the message store - it has no knowledge of them. I don't understand what you mean by casting messages as SMS messages? You can't get the WCMP_* data via MAPI, you need to use the SMS API's - probably at the time of receipt. You would then need to replace/shim the existing SMS driver.Anonymous
January 23, 2008
Hi Jay, I have the same problem ddevine reported. I am trying to port a J2ME application to C#. The J2ME application is capable to intercep text (not WDP) SMS messages based on some port information that is stored on the SMS PDB header. I could retrieve that information when I used the SMS API and according to the documentation, that information should be available into PR_CE_SMS_RAW_HEADER property when we use the MAPI. However, this property is empty. So, is the documentation wrong!? Should we use the SMS API and replace the tmail.exe process as the default SMS interceptor? Thanks, Rodrigo.Anonymous
January 24, 2008
Rodrigo's point helps to clarify what I meant too. I'm not fully versed on the J2ME spec, so forgive if some thoughts are muddled... I'm attempting to port a J2ME application to WM6 also. We've got existing handsets and a server/billing/Customer Service system already setup that's driven through port directed SMS messages to the handsets. The purpose of the port directed SMSs is to change the state of our application (subscribed/un-subscribed/update). I would like to leverage our existing system so that we don't need to re-engineer our server transmission system just for WM. J2ME apps have the ability to listen on specific ports for incoming messages. From my looking this morning at WDP, it appears that this functionality matches, with the J2ME simply providing access to that transport functionality. My understanding is that for ports other than the standard text port, the messages are not visable to the handset user. The notation for setting up a connection looks similar to standard IP syntax..."sms://5551212:1234" In this case, I'm assuming that the port is "1234." I'll just cut to the chase...How would I setup similar functionality on WM? I've tried using the "SmsSetMessageNotification()," but I don't see any means of locking this notification to a specific port... I don't want to intercept everything, only incoming messages on "sms://5551212:1234." How would I get the same functionality? Thanks Jay, DDAnonymous
January 24, 2008
Hi, that question is beyond my area of expertise. I recommend looking at the WAP stack, and possibly some code in the SDK. The WM6 SDK has a sample on WDP over SMS, which may be useful. If you need more help then try contacting Microsoft Developer support.Anonymous
January 24, 2008
Hi Jay, There is no solution available on the SDK. We just need to know if the property PR_CE_SMS_RAW_HEADER works and we are too stupid to retrieve it. Otherwise, we will have to change a server application that works perfectly fine with J2ME applications, but is compatible with Microsoft WDP API. Could you please talk to the guy who coded that property? Thanks, Rodrigo.Anonymous
January 24, 2008
By the way, here is the property description: The PR_CE_SMS_RAW_HEADER property contains the header portion of a RAW SMS message. This is contained in RAW_PROVIDER_SPECIFIC_DATA::pbHeaderData, which is returned from the SmsReadMessage function in its pbProviderSpecificBuffer parameter. When I used the SMS API, I was able to retrieve that data and checked 4 bytes that represent the SMS port number...Anonymous
January 24, 2008
Hi, PR_CE_SMS_RAW_HEADER stores an object of type RAW_PROVIDER_SPECIFIC_DATA (defined in sms.h of the SDK). I'm unsure if that is what you need.Anonymous
January 24, 2008
Thanks Jay, I think WAP/WDP might be the answer I was looking for. Thanks for the help, and great job on the Blog! DDAnonymous
January 28, 2008
Hi Jay, I am doing a project that can intercept incoming and outgoing messages, check the content and forward it. I understand c# can intercept incoming sms using Microsoft.WindowsMobile.PocketOutlook namespace but i am stucked here since I dont know how to intercept outgoing sms. So I am thinking of retrieving sms from outbox and check then forward. Could you pls help? Thank you so much.Anonymous
January 28, 2008
Hi Jeff, I don't work with the C# version of the API, and I'm not sure if we can intercept outgoing SMS. Perhaps some other commenter can help?Anonymous
January 30, 2008
hi Jay, I am unable to find any SMS Text Messages in my InBox. e.g. ptbl->GetRowCount(0, &messageCount); always gives me a 0 messageCount. When I peek into my SMS Inbox on the device using the stock version of Messaging Software from MSFT, I found many SMS Text Messages inside my InBox. Thanks for your advice in advanceAnonymous
February 02, 2008
Hi Jay again, If you are not familiar with C# version of this API, is it possible to retrieve the messages from outbox from time to time and do some content checking? I mean using your normal way. I need to get the outbox messages, check it and forward to numbers. Thanks a lot in advance.Anonymous
February 02, 2008
Hi Jeff, you can write an app or service that listens for MAPI notifications. You can then check for messages that get copied to that folder and open/check them.Anonymous
February 02, 2008
Thanks for the quick reply. Unfortunately I am not so familiar with MAPI...Is there any portion of code or sample for this? Thanks.Anonymous
February 02, 2008
Jeff, look in the SDK for MAPI notifications.Anonymous
February 02, 2008
Thanks again Jay, I will look into that and see what I can do. Good Article! Btw, you from Singapore?Anonymous
February 16, 2008
I would like to ask how can i detect how many messages are new to the user from SMS inbox. Can someone give hints. thanks a lotAnonymous
February 16, 2008
i got it , using SnApi.h and RegExt.h thanks a lotAnonymous
February 24, 2008
Is the name of the store (SMS) guaranteed to be the same on all versions of Windows Mobile or is there some proper localizable string that we should use?? I mean suppose I need to access the SMS store on some WM which is say chinese? Would I need to do something special for thatAnonymous
February 24, 2008
Unless the OEM has done something out of the ordinary, the SMS store should be "SMS"Anonymous
March 21, 2008
I would liked to call out and see if there was an answer to this question, I am having the same problem for Mobile 2003 SE and Mobile 5. "I've tried everything to get at the recipients but it tells me there are none. Anyone know why? pFolder->OpenEntry(pval[0].Value.bin.cb, (LPENTRYID)pval[0].Value.bin.lpb, NULL, 0, &ulObjType, (LPUNKNOWN*)&pMsg); hr = pMsg->GetRecipientTable(0, &iTable); hr is always MAPI_E_NO_RECIPIENTS. "Anonymous
April 21, 2008
How to read the message properties from Compose screen? I have added a menu option in the compose screen. In the action, I need to read the properties (To, Body etc.). Thanks, KrisAnonymous
April 22, 2008
look in mapitags.h for a list of properties. from there you can use HrGetOneProp. For the "To" you need to open the recipient table. You can find info in the SDK docs.Anonymous
May 05, 2008
jayongg, thanks for the reply. I saw the example 'Readviewmenuext' in SDK. HrGetOneProp needs (IMAPIProp*) as first parameter. To get this Prop pointer, we need IMessage pointer. How to get this 'IMessage' pointer for the message entered in the Compose window? This message is not yet there in any message folder.Anonymous
May 06, 2008
I have the same problem as Johny Alan. I can't read the number to which the SMS was sent in sent items. I've tried almost every PR_XXX :(. Any help appreciated. Thanks Nick.Anonymous
May 06, 2008
Try reading the recipient table to get the list of recipients for the message.Anonymous
May 07, 2008
GetRecipientTable works fine - thanks!!Anonymous
June 01, 2008
I want to store email in inbox folder by coding, how can I do it? I only do it in draft or outbox folder, but can't store it in inbox folder. I'm very appreciated that you give me any clue or tip. Thanks in advance.Anonymous
June 01, 2008
The reason is that once I got email info from others channel, I can store it in inbox folder, thus can have the push mail function.Anonymous
June 02, 2008
Is there a VB.NET version of it? I need to do a school project in VB that requires this.Anonymous
June 02, 2008
I want to know how to get SMS from a Windows Mobile phone's inbox as well as to delete it. But both need to be done on VB.NET. Anyone knows how?Anonymous
July 02, 2008
Hi :) We have problem with retrieving MMS messages. We are able to get subject, phone nr, date. The main problem is we aren't able to get body like photo file. In our work we use a Palmtop(QTEK S100) with operating system Windows Mobile 2003 SE and library CEMAPI in C++. I know I can use IMessage... but i don`t know how to get a pointer to IMessage:( http://msdn.microsoft.com/en-us/library/bb446198.aspx Can Any one help please?Anonymous
July 07, 2008
Hi your article is fine but i am looking for send mail functionality. I am developing WM application. I have to add email functionality in my application. I want to use pocket outlook interface for sending mail.I have a button on my userinterface. I want that after clicking this button outlook interface open.. I am using device emulator. can anyone show me the way to achive this ? thanxAnonymous
July 07, 2008
- MAPI: the wrong approach (yet interesting sample code) - WebDAV: DELETE command via HTTP - Customize
Anonymous
July 21, 2008
The comment has been removedAnonymous
August 14, 2008
Do you have similar program write on VB?Anonymous
August 14, 2008
Hello! I'm trying to install the MapiRule sample from MS on a SmartpHone Mteor with WM5. I've followed all the steps and signed it with the test cert. Still it won't get installed at the device. It says "This software is not authorized...". It works fine with PPC WM6. Any ideas? Any help appreciated. Thanks Nick.Anonymous
August 28, 2008
Nice tutorial for beginer. I learnt alot from the steps provide. is it possible to send SMS to device(self) without using GSM operator with MAPI ?Anonymous
December 04, 2008
If I create MAPI Store with CreateMsgStore, why doesnt it appear in list of accounts on wm6 standard emulator? What else should be done?Anonymous
December 31, 2008
The comment has been removedAnonymous
February 02, 2009
Hallo All! Can someone tell me is where any flags or properties for IMessage Object to knew if e-mail an new created mail, forward mail or reply mail? Thanks for any help!Anonymous
February 12, 2009
Hi Jay and everyone. I am struggling with attachment as well. Doing the work as explained before, on a WM5 device works good. But, on the device, when I want to retrieve the attachment with createAttach, the attachment is just invisible. The message icon in the messages list shows attachment is notified, but when I open the message, there is only the attachment row (for editing interface) with no name, no icon and no link on where i can click to open this attachment. If this message is sent through outlook via activesync, the message contains, effectively , the attachment. Therefore, what do I miss for MAPI not too completely "see" there is an attachment ?? Thanks a lot for your help, PierreAnonymous
February 16, 2009
That is answer from my own question. OK I can now retrieve the attachments. The problem was I didn't provide anything in PR_ATTACH_SIZE. By doing so, the attachment appears :) Hope this can help. PierreAnonymous
March 11, 2009
The comment has been removedAnonymous
March 13, 2009
Hey.. I got where I went wrong. we should use PS_MESSAGE_CLASS2 instead of PS_MESSAGE_CLASS0 for the TEXT_PROVIDER_SPECIFIC_DATA structure.Anonymous
May 06, 2009
I want to make an application that encrypts all the sms messages in the inbox. How can i modify your code to be able to alter the contents of the messages? Best regards /RobAnonymous
June 04, 2009
The comment has been removedAnonymous
June 17, 2009
Hi, I need to develop some kind of messaging client. which need imap4 (receive) and smtp(sending) support. but my ui requirements are different. is there some way i can use imap4, smtp stack of MS without accessing the mapi?Anonymous
July 14, 2009
The comment has been removedAnonymous
July 24, 2009
Hi, I am trying to read messages in SMS inbox. I am using VS2005 and WM5. I did the following steps,
- Got the SMS message store.
- Got the entry id of SMS Inbox using "GetReceiveFolder".
- Opened it using "OpenEntry".
- Got the contents of the inbox using "GetContentsTable".
- Queried the table using "QueryRows". The code got compiled successfully. The problem is QueryRows is not returning any rows even though I have messages in my Inbox. When I debug the rowset returned by QueryRows I am getting the errors "CXX0017: Error: symbol 'ulPropTag' not found" and "CXX0017: Error: symbol 'dwAlignPad' not found". Please help me out with this. Regards Dia