Important:
This is retired content. This content is outdated and is no longer being maintained. It is provided as a courtesy for individuals who are still using these technologies. This content may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist.
4/8/2010

New messages are created and sent from a message store's Draftsfolder. After you create a message, you set its property values (subject, body, list of recipients, and so on) and then post the message.

To send a message

  1. Initialize the MAPI subsystem, and log onto a MAPI session. For more information, see Beginning a MAPI Session.

  2. Establish a connection to a message store. For more information, see Connecting to a Message Store.

  3. Create a message object. For more information, see Creating a Message.

  4. Prepare and set the list of recipients for the message. Typically, there are three properties to set for each recipient: PR_RECIPIENT_TYPE, PR_ADDRTYPE, and PR_EMAIL_ADDRESS.

    1. Allocate memory for the list of recipients by calling MAPIAllocateBufferwith the total size of the recipient list.

      Copy Code
      ULONG		cRecipients = 1; 				 // Send a
      message to one recipient.
      LPWSTR			 pszTo = L"you@mycompany.com";  // The e-mail
      address of the recipient.
      ULONG cRecipientProperties = 3; 				 // Set three
      properties for the recipient.
      LPADRLIST   pRecipientList = NULL;
      ULONG	cbRecipientList = 0;
      
      cbRecipientList = sizeof(ADRLIST) + 
      						cRecipients * (sizeof(ADRENTRY) + 
      										cRecipientProperties *
      (sizeof(SPropValue) + 
      													 
      (wcslen(pszTo)+3) * sizeof(WCHAR)));
      
      hr = MAPIAllocateBuffer(cbRecipientList, (LPVOID FAR
      *)&pRecipientList);
      
    2. Initialize the recipient list by using memset to set the entire buffer to 0, and then begin filling-in values for the recipient list.

      Copy Code
      memset(pRecipientList, 0, cbRecipientList);
      
      pRecipientList->cEntries = cRecipients;
      pRecipientList->aEntries[0].cValues = cRecipientProperties;
      
    3. Initialize the array of recipient properties.

      Copy Code
      int cbRecipientProperties = 0;
      cbRecipientProperties = cRecipientProperties * sizeof(SPropValue);
      
      hr = MAPIAllocateBuffer(cbRecipientProperties, (LPVOID FAR
      *)&pRecipientList->aEntries[0].rgPropVals);
      memset(pRecipientList->aEntries[0].rgPropVals, 0,
      sizeof(SPropValue) * 3);
      
    4. Set the recipient type property value to indicate whether the recipient is listed on the To:, Cc:, or Bcc: fields by using the PR_RECIPIENT_TYPEproperty. This is the first of three properties that are being set in the recipient list.

      Copy Code
      pRecipientList->aEntries[0].rgPropVals[0].ulPropTag = 
      PR_RECIPIENT_TYPE;
      pRecipientList->aEntries[0].rgPropVals[0].Value.
      ul  = 
      MAPI_TO;
      
    5. Set the address type property value to SMTP by using the PR_ADDRTYPEproperty. This is the second of three properties that are being set in the recipient list.

      Copy Code
      pRecipientList->aEntries[0].rgPropVals[1].ulPropTag   = 
      PR_ADDRTYPE;
      pRecipientList->aEntries[0].rgPropVals[1].Value.lpszW = 
      L"SMTP";
      
    6. Set the e-mail address for each message recipient by using the PR_EMAIL_ADDRESSproperty. This is the third and final property that is being set in the recipient list.

      Copy Code
      pRecipientList->aEntries[0].rgPropVals[2].ulPropTag   = 
      PR_EMAIL_ADDRESS;
      pRecipientList->aEntries[0].rgPropVals[2].Value.lpszW = 
      pszTo;
      
    7. Add the list of recipients to your message by calling the IMessage::ModifyRecipientsmethod with the MODRECIP_ADDflag.

      Copy Code
      hr = pMsg->ModifyRecipients(MODRECIP_ADD, 
      pRecipientList);
      
    8. Free the memory resources taken by the Drafts Folder by calling MAPI IUnknown::Release, and by the list of recipients by calling MAPIFreeBuffer.

      Copy Code
      hr = pFldrDrafts->Release();
      pFldrDrafts = NULL;
      
      hr = MAPIFreeBuffer(pRecipientList->aEntries[0].rgPropVals);
      hr = MAPIFreeBuffer(pRecipientList);
      
  5. Prepare and set the following properties of the message: PR_MSG_STATUS, PR_MESSAGE_FLAGS, and PR_SUBJECT.

    1. Allocate memory for the message property array by calling MAPIAllocateBufferwith the total size of the message properties. To find out how many bytes of memory the properties will require, add the size of the SPropTagArraydata type, to the size of four SPropValuestructure (one for each property), and then add the number of characters in the subject line, multiplied by the number of bytes taken be each of its UNICODE characters.

      Copy Code
      LPSPropValue rgpMsgProperties = NULL;   // A pointer to the
      property value structure.
      int		cbMsgProperties  = 0; // The size, in bytes, of
      the properties.
      int		cMsgProperties   = 4; // The number of
      properties.
      LPWSTR	 pszSubject	 = L"This is only a MAPI Text
      Message";
      
      cbMsgProperties = sizeof(SPropTagArray) 
      + 
      										cMsgProperties *
      (sizeof(SPropValue) 
      + 
      																 
      (wcslen(pszSubject) + 3) * sizeof(WCHAR));
      
      hr = MAPIAllocateBuffer(cbMsgProperties, (LPVOID FAR
      *)&rgpMsgProperties);
      
    2. Initialize the message property array by using memset to set the entire buffer to 0.

      Copy Code
      memset(rgpMsgProperties, 0, cbMsgProperties);
      
    3. Set the message's subject by setting the PR_SUBJECTproperty to a value of pszSubject.

      Copy Code
      rgpMsgProperties[0].ulPropTag   = 
      PR_SUBJECT;
      rgpMsgProperties[0].Value.lpszW = 
      pszSubject;
      
    4. Set a couple flags on the message by setting the PR_MESSAGE_FLAGSproperty to the bitmask value MSGFLAG_UNSENTand MSGFLAG_FROMME.

      Copy Code
      rgpMsgProperties[1].ulPropTag = 
      PR_MESSAGE_FLAGS;
      rgpMsgProperties[1].Value.ul  = 
      MSGFLAG_FROMME | MSGFLAG_UNSENT;   // Notice how to combine
      multiple flags.
      
    5. Tag the message to identify that it is intended to be received as an SMTP message (as opposed to SMS) by setting the PR_MSG_STATUSproperty to a value of MSGSTATUS_RECTYPE_SMTP.

      Copy Code
      rgpMsgProperties[2].ulPropTag = 
      PR_MSG_STATUS;
      rgpMsgProperties[2].Value.ul  = 
      MSGSTATUS_RECTYPE_SMTP;
      
    6. Set the message's importance level to High by setting the PR_IMPORTANCEproperty to a value of IMPORTANCE_HIGH.

      Copy Code
      rgpMsgProperties[3].ulPropTag = 
      PR_IMPORTANCE;
      rgpMsgProperties[3].Value.ul  = 
      IMPORTANCE_HIGH;
      
    7. Add the array of properties to the message by calling the IMAPIProp::SetPropsmethod on the IMessageobject.

      Copy Code
      hr = pMsg->SetProps(cMsgProperties, rgpMsgProperties, NULL);
      
    8. Free the memory buffer for the message property array by calling MAPIFreeBuffer.

      Copy Code
      hr = MAPIFreeBuffer(rgpMsgProperties);
      
  6. Prepare and write the text body of the message.

    1. Declare a NULL IStreaminterface object, and then call the IMAPIProp::OpenPropertymethod of the IMessageobject to get a reference to the message body text stream.

      Copy Code
      LPSTREAM pStream = NULL;
      hr = pMsg->OpenProperty(PR_BODY, NULL, 0, MAPI_MODIFY |
      MAPI_CREATE, 
      (LPUNKNOWN *)&pStream);
      
    2. Write text to the body of the message by calling the IStream::Writemethod of the IStreamobject.

      Copy Code
      LPWSTR  pszBody = L"This text belongs to the body of the message.";
      ULONG	cbBody = 0;
      ULONG cbWritten = 0;
      
      cbBody = (wcslen(pszBody) + 1) * sizeof(WCHAR);
      
      hr = pStream->
      Write(pszBody, cbBody, &cbWritten);
      
    3. If it is no longer needed, release the IStreamobject by calling MAPI IUnknown::Releaseon it.

      Copy Code
      pStream->
      Release();
      pStream = NULL;
      
  7. Submit the message by calling the IMessage::SubmitMessagemethod of the IMessageobject.

    Copy Code
    hr = pMsg->
    SubmitMessage(0);
    
  8. If it is no longer needed, release the IMessageobject by calling MAPI IUnknown::Releaseon it.

    Copy Code
    pMsg->
    Release();
    pMsg = NULL;
    

Example

The following code example is a function that encapsulates the entire set of programmatic steps necessary to send an e-mail message from a Windows Mobile device.

Note:
To make the following code example easier to read, security checking and error handling are not included. This code example should not be used in a release configuration unless it has been modified to include them.
Copy Code
void MessagingApp(void)
{
	ICEMAPISession  * pSession	= NULL;
	IMsgStore	 * pMsgStrore  = NULL;
	IMessage		* pMsg		= NULL;
	IMAPITable	* pTable	= NULL;
	SRowSet		 * pSRowSet	= NULL;
	IMAPIFolder	 * pFldrDrafts = NULL;

	ULONG				rgTags[] = { 1, {PR_CE_IPM_DRAFTS_ENTRYID}
};
	LPSPropValue		rgProps = NULL;
	ULONG				 cValues = 0;

	hr = MAPIInitialize(NULL); 								 
 // Initialize the MAPI COM server.
	hr = MAPILogonEx(0, NULL, NULL, 0, (LPMAPISESSION
*)&pSession);  // Logon and get a Session pointer.

	hr = pSession->GetMsgStoresTable(0, &pTable); 	 
		// Get a pointer to Message Store table (Accounts
collection).

	hr = pTable->QueryRows(1, 0, &pSRowSet); 		
		// Get a pointer to the first row, which contains all the
																 
 // properties of the first Message Store.

	// Get the message store's Entry ID.
	hr = pSession->OpenMsgStore(0,
							 
pSRowSet->aRow[0].lpProps[0].Value.bin.cb, 
								(ENTRYID
*)pSRowSet->aRow[0].lpProps[0].Value.bin.lpb, 
								NULL, 0, &pMsgStrore);

	// Get the Drafts Folder's Entry ID.
	hr = pMsgStrore->GetProps((LPSPropTagArray)rgTags,
MAPI_UNICODE, &cValues, &rgProps);

	// Get a handle to the Drafts Folder.
	hr = pMsgStrore->OpenEntry(rgProps[0].Value.bin.cb,
							 (LPENTRYID)rgProps[0].Value.bin.lpb,

								NULL, MAPI_MODIFY, NULL,
(LPUNKNOWN*)&pFldrDrafts);

	// Create a new Message object in the Drafts folder.
	hr = pFldrDrafts->CreateMessage(NULL, 0, &pMsg);

	// Setup the Recipient List.
	int cRecipients		= 1; 		 // Count of the
number of Recipients. Sending to only one person.
	int cRecipientProperties = 3; 		 // Count of
properties for each Recipient.
	int nRecipientIndex	= 0;

	WCHAR * pszTo = L"someone@microsoft.com";   // Address of
Recipient.

	ADRLIST * pRecipientList = NULL; 		// List of
Recipients, stored in an Address List.
												// This can be a
semi-colon separated list.

	int cbRecipientList = 0; 				// The size of the
Recipient List, in bytes.
	cbRecipientList = sizeof(ADRLIST) + 
						cRecipients * (sizeof(ADRENTRY) + 
										cRecipientProperties *
(sizeof(SPropValue) + 
																 
(wcslen(pszTo) + 3) * sizeof(WCHAR)));

	// Allocate memory for the Address List.
	hr = MAPIAllocateBuffer(cbRecipientList, (LPVOID FAR
*)&pRecipientList);

	memset(pRecipientList, 0, cbRecipientList);

	pRecipientList->cEntries			= cRecipients;
	pRecipientList->aEntries[0].cValues = cRecipientProperties;

	// The size of the array of Recipient properties, in bytes.
	int cbRecipientProperties = 0;
	cbRecipientProperties = cRecipientProperties *
sizeof(SPropValue);

	hr = MAPIAllocateBuffer(cbRecipientProperties, (LPVOID FAR
*)&pRecipientList->aEntries[nRecipientIndex].rgPropVals);
	memset(pRecipientList->aEntries[nRecipientIndex].rgPropVals,
0, sizeof(SPropValue) * 3);

	pRecipientList->aEntries[nRecipientIndex].cValues =
cRecipientProperties;
	 
   
pRecipientList->aEntries[nRecipientIndex].rgPropVals[0].ulPropTag
 = PR_RECIPIENT_TYPE;
   
pRecipientList->aEntries[nRecipientIndex].rgPropVals[0].Value.ul
  = MAPI_TO;

   
pRecipientList->aEntries[nRecipientIndex].rgPropVals[1].ulPropTag
 = PR_ADDRTYPE;
   
pRecipientList->aEntries[nRecipientIndex].rgPropVals[1].Value.LPSZ
= TEXT("SMTP");

   
pRecipientList->aEntries[nRecipientIndex].rgPropVals[2].ulPropTag
 = PR_EMAIL_ADDRESS;
   
pRecipientList->aEntries[nRecipientIndex].rgPropVals[2].Value.LPSZ
= pszTo;

	hr = pMsg->ModifyRecipients(MODRECIP_ADD, pRecipientList);  
	// Add the Recipients List to the message.

	hr = pFldrDrafts->Release();

	pFldrDrafts = NULL;

	hr =
MAPIFreeBuffer(pRecipientList->aEntries[nRecipientIndex].rgPropVals);
	hr = MAPIFreeBuffer(pRecipientList);

	// Setup the message's properties.
	LPSPropValue rgpMsgProperties = NULL;   // An array of
properties.
	int		 cbMsgProperties = 0; // The size of the
array of properties.
	int			cMsgProperties = 4; // The number of
properties for the message.

	LPWSTR			 pszSubject = L"This is only a MAPI Text
Message"; // The message Subject line.

	cbMsgProperties = sizeof(SPropTagArray) + 
									cMsgProperties *
(sizeof(SPropValue) + 
												 
(wcslen(pszSubject) + 3) * sizeof(WCHAR));

	hr = MAPIAllocateBuffer(cbMsgProperties, (LPVOID FAR
*)&rgpMsgProperties);
	memset(rgpMsgProperties, 0, cbMsgProperties);

	rgpMsgProperties[0].ulPropTag   = PR_SUBJECT;
	rgpMsgProperties[0].Value.lpszW = pszSubject;

	rgpMsgProperties[1].ulPropTag   = PR_MESSAGE_FLAGS;
	rgpMsgProperties[1].Value.ul	= MSGFLAG_FROMME |
MSGFLAG_UNSENT;   // A combination of flags.

	rgpMsgProperties[2].ulPropTag   = PR_MSG_STATUS;
	rgpMsgProperties[2].Value.ul	= MSGSTATUS_RECTYPE_SMTP;

	rgpMsgProperties[3].ulPropTag   = PR_IMPORTANCE;
	rgpMsgProperties[3].Value.ul	= IMPORTANCE_HIGH;

	hr = pMsg->SetProps(cMsgProperties, rgpMsgProperties, NULL);
	hr = MAPIFreeBuffer((void *)rgpMsgProperties);

	LPSTREAM pStream = NULL;
	hr = pMsg->OpenProperty(PR_BODY, NULL, 0, MAPI_MODIFY |
MAPI_CREATE, (LPUNKNOWN *)&pStream);

	LPWSTR pszBody  = L"Text in Body of Message.";
	ULONG cbBody	= 0;
	ULONG cbWritten = 0;

	cbBody = (wcslen(pszBody) + 1) * sizeof(WCHAR);

	hr = pStream->Write(pszBody, cbBody, &cbWritten);

	pStream->Release();
	pStream = NULL;

	hr = pMsg->SubmitMessage(0);

	pMsg->Release();
	pMsg = NULL;
}

Both the Windows Mobile Professional SDK and the Windows Mobile Standard SDK ship with a code sample called Sending E-mail, which you can build and run to gain a better understanding of the fundamental messaging concepts. The default location for the sample:

C:\Program Files\Windows Mobile 6.5.3 DTK\Samples\Common\CPP\Win32\SendMail\SendMail.sln

Compiling the Code

To compile the code sample, you must add references to the CE MAPI type library and the CE MAPI header files, to your project.

  1. Add preprocessor directives that include the header files in with the rest of your project files when you build your project. You do this by typing the following statements at the top of either your main C++ source file or your header file.

    Copy Code
    #include <cemapi.h>
    #include <mapidefs.h>
    #include <mapiutil.h>
    #include <mapix.h>
    
  2. Specify a linker dependency to the CE MAPI type library as a project property.

    1. Press Alt+F7, and the Project Property Pagesdialog box appears.

    2. In the dialog box, navigate to the Inputproperty page for the Linker(navigate to Configuration Properties> Linker> Input).

    3. In Additional Dependencies, type cemapi.lib, and then click OK.

  3. Rebuild the Solution (press Ctrl+Alt+F7).

Robust Programming

A robust program is one that continues normal execution after surviving circumstances that cause lesser programs to crash. Robust programs are designed from the ground-up with error handling in mind. To facilitate this, Win32 COM functions and methods always return success/failure information in the form of a 32-bit HRESULT, which you can use to "trap" conditions that you anticipate will cause problems for your program.

The header file winerror.h contains the error code definitions along with a host of generic error handling macros that you can use in your code. For example, you can use the following two macros to test for success and failure of any COM procedure call.

Copy Code
#define SUCCEEDED(hr) ((HRESULT)(hr) >= 0)   // Note that
non-negative numbers indicate success.
#define FAILED(hr)	((HRESULT)(hr) < 0)

The following code example is a typical method that demonstrates robust programming.

Copy Code
BOOL MAessaging::LogOntoMAPI()
{
	HRESULT hr;

hr = MAPILogonEx(0, NULL, NULL, 0, (LPMAPISESSION
*)&pSession);

	if(FAILED(hr))
	{
		MessageBox(NULL, _T("Failed to log onto the MAPI
Session."), _T("Warning"), MB_OK);
		return FALSE;
}

	return TRUE;
}

See Also