free web page counters

Windows Mobile Pocket PC Smartphone Programming

==>Click here for the SiteMap<==. Original contents with decent amount of source codes.

Thursday, March 02, 2006

How to retrieve/get TO, CC, BCC recipient address of an email through CEMAPI (C++) in Windows Mobile device?

====>SiteMap of this Blog<===

How to retrieve/get TO, CC, BCC recipient address of an email through CEMAPI (C++) in Windows Mobile device?

Whenever you deal with email application through MAPI (or, CEMAPI, the trimmed version in Windows Mobile devices), quite possibly you need to load TO addresses, CC addresses from a given email message (or BCC addresses in case the message is in "draft" folder or "Sent Item" folder) . For example, when developing a mail transport, you not only need to synchronize the account's inbox with the remote server, but also have to deal with outgoing messages. Inevitably, you have to know TO/CC/BCC of any outgoing message.

Intuitive thought is to query them as corresponding properties from the message object IMessage using its GetProps method. Although the CEMAPI documentation is scarce, one can still find such properties from the header files:


Unfortunately all of three properties returned me empty strings, at least in Pocket PC 2003 devices. Time to take a google search to see whether other people ran into the same issue. I did find two fellow clueless guys, who posted the question but got no useful answers:

So I had to take the more complex approach, using the recipient table. Every message has a recipient table. Each record in the recipient table is a recipient, and has a couple of properties/columns. As with any other MAPI stuff, an email address is a property, a recipient's name is also a property, and an address type (TO/CC/BCC) is also a property.

So I changed my simple code to a slightly longer one:

  • opening the recipient table by calling GetRecipientTable,
  • setting the interested properties by calling SetColumns,
  • iterating through the table record-by-record by calling QueryRows

Heck! This seemingly perfect and innocent code still did not work. After a debug, I soon realized that SetColumns returns a COM error meaning not implemented. Not surprisingly, CEMAPI is not the full-fleged MAPI in the desktop world, and here we tasted a slight bitterness.

So the natural solution is to loop though all the properties for each record, and figure out the type of each property. The number of the properties for each recipient is SRow.cValues, and the type of each property is specified in SPropValue.ulPropTag. Below is a code snippet:

  // the hack is to loop through all rows without limiting the columns
  HRESULT hr = pMessage->GetRecipientTable(0, &pRecipientTable);

  // iterate all the recipients
  while (TRUE) {
    hr = pRecipientTable->QueryRows(1, 0, &pRows);
    if (FAILED(hr) || !pRows || pRows->cRows != 1) break;

    // nProps is the number of columns in the recipient table
    int nProps = pRows->aRow[0].cValues;
    ULONG ulReceipType = 0;

    // loop through all the properties
    for (int ii = 0; ii < nProps; ii++) {

      ULONG ulPT = pRows->aRow[0].lpProps[ii].ulPropTag;
      switch (ulPT) {
      case PR_EMAIL_ADDRESS:
        // This is the email address
        szReceipEmail = pRows->aRow[0].lpProps[ii].Value.LPSZ;
        // this is the recipient type: TO/CC/BCC
        ulReceipType = pRows->aRow[0].lpProps[ii].Value.ul;
      case PR_DISPLAY_NAME:
        // this is the display name
        szReceipName = pRows->aRow[0].lpProps[ii].Value.LPSZ;
      }  // switch

Category: [Outlook / Transport / MAPI]

====>SiteMap of this Blog<===