Udostępnij za pośrednictwem


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.aspx

  • Anonymous
    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 removed

  • Anonymous
    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, kapil

  • Anonymous
    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.aspx

  • Anonymous
    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 kapil

  • Anonymous
    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 kapil

  • Anonymous
    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 kapil

  • Anonymous
    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 kapil

  • Anonymous
    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 kapil

  • Anonymous
    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 kapil

  • Anonymous
    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 Kapil

  • Anonymous
    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. Eric

  • Anonymous
    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. Eric

  • Anonymous
    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 english

  • Anonymous
    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 before

  • Anonymous
    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 soon

  • Anonymous
    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, Sunisha

  • Anonymous
    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 Advance

  • Anonymous
    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 days

  • Anonymous
    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, Jay

  • Anonymous
    June 27, 2007
    Hi, Is it possible to get the notifications in my application from listview created by MailSwitchToFolder() function.   Thanks and Regards, Sunisha

  • Anonymous
    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 . selva

  • Anonymous
    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:

  1. I get the IMsgStore for sms.
  2. Then I get the required folder using GetProps with a predefined folder type tag
  3. Then OpenEntry to get the IMAPIFolder
  4. 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++ user

  • Anonymous
    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, Paulo

  • Anonymous
    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? Carl

  • Anonymous
    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, Jake

  • Anonymous
    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:( selva

  • Anonymous
    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 transport

  • Anonymous
    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 removed

  • Anonymous
    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? thanks

  • Anonymous
    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_BODY

  • Anonymous
    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, DD

  • Anonymous
    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, DD

  • Anonymous
    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! DD

  • Anonymous
    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 advance

  • Anonymous
    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 lot

  • Anonymous
    February 16, 2008
    i got it , using SnApi.h and RegExt.h thanks a lot

  • Anonymous
    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 that

  • Anonymous
    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, Kris

  • Anonymous
    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 ? thanx

  • Anonymous
    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 removed

  • Anonymous
    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 removed

  • Anonymous
    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, Pierre

  • Anonymous
    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. Pierre

  • Anonymous
    March 11, 2009
    The comment has been removed

  • Anonymous
    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 /Rob

  • Anonymous
    June 04, 2009
    The comment has been removed

  • Anonymous
    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 removed

  • Anonymous
    July 24, 2009
    Hi, I am trying to read messages in SMS inbox. I am using VS2005 and WM5. I did the following steps,

  1. Got the SMS message store.
  2. Got the entry id of SMS Inbox using "GetReceiveFolder".
  3. Opened it using "OpenEntry".
  4. Got the contents of the inbox using "GetContentsTable".
  5. 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