Now that you have looked at all of the basic interfaces for working with the various MAPI objects, let's take a more detailed look at how you can use them to perform specific tasks with e-mail. Opening a Message Store
The following sample shows how to open a message store: HRESULT hr = S_OK; /////////////////////////////////////////// // Step 1 - Initialize COM/MAPI, and log on IMAPISession *pIMapi = NULL; if(FAILED(CoInitializeEx(NULL, 0))) return FALSE; if(MAPIInitialize(NULL) != S_OK) return FALSE; if(MAPILogonEx(0, NULL, NULL, 0, &pIMapi) != S_OK) { MAPIUninitialize(); return FALSE; } ////////////////////////////////////////////////////// // Step 2 - Get the pointer to the Message Store Table IMAPITable *pIMapiStoresTable = NULL; hr = pIMapi->GetMsgStoresTable(0, &pIMapiStoresTable); if(FAILED(hr)) { pIMapi->Logoff(0, 0, 0); pIMapi->Release(); pIMapi = NULL; MAPIUninitialize(); return FALSE; } //////////////////////////////////////////////////////////// // Step 3 - Query the table for the entry that matches the // name of the store we are interested in. IMsgStore *pPop3Store = NULL; while(1) { SRowSet *pRowSet = NULL; SizedSPropTagArray(2, tblColumns) = {2,{PR_DISPLAY_NAME, PR_ENTRYID}}; pIMapiStoresTable->SetColumns((LPSPropTagArray) &tblColumns, 0); hr = pIMapiStoresTable->QueryRows(1, 0, &pRowSet); if(FAILED(hr)) break; if(pRowSet->cRows != 1) break; //////////////////////////////////////////////////////////// // Step 4 - Compare the name with "POP3". If it's a // match, open it if(_tcscmp(TEXT("POP3"), pRowSet->aRow[0].lpProps[0]. Value.lpszW) == 0) {ENTRYID *pEntry = (ENTRYID *) pRowSet->aRow[0].lpProps[1].Value.bin.lpb; ULONG ulStoreBytes = pRowSet->aRow[0].lpProps[1].Value.bin.cb; pIMapi->OpenMsgStore(NULL, ulStoreBytes, pEntry, NULL, NULL, &pPop3Store); FreeProws(pRowSet); break; } // Free buffers allocated by MAPI FreeProws(pRowSet); }; // Clean up the store table pIMapiStoresTable->Release(); // Make sure we opened the store if(!pPop3Store) { pIMapi->Logoff(0, 0, 0); pIMapi->Release(); pIMapi = NULL; MAPIUninitialize(); return FALSE; } // Do something now.. Creating a New Message
The following sample shows how to create a new message: ////////////////////////////////////////// // Step 2 - Open up the Pop3 Drafts folder LPSPropValue rgprops = NULL; LPSPropValue lppPropArray = NULL; ULONG cValues = 0; IMAPIFolder *pPOPDraftsFolder = NULL; SizedSPropTagArray(2, rgTags) = {2,{PR_CE_IPM_DRAFTS_ENTRYID,PR_OBJECT_TYPE}}; // Now get the Drafts folder hr = pPop3Store->GetProps((LPSPropTagArray)&rgTags, MAPI_UNICODE, &cValues, &rgprops); if(FAILED(hr)) return FALSE; hr = pPop3Store->OpenEntry(rgprops[0].Value.bin.cb, (LPENTRYID)rgprops[0].Value.bin.lpb, NULL, MAPI_MODIFY, NULL, (LPUNKNOWN*)&pPOPDraftsFolder); if(FAILED(hr)) return FALSE; ////////////////////////////////////////// // Step 3 - Create a new message object IMessage *pNewMessage = NULL; hr = pPOPDraftsFolder->CreateMessage(NULL, 0, &pNewMessage); if(FAILED(hr)) return FALSE; ////////////////////////////////////////// // Step 4 - Add a subject and message flags SPropValue sMsgProps[2]; TCHAR tchSubject[128] = TEXT("\0"); memset(&sMsgProps, 0, sizeof(sMsgProps)); wsprintf(tchSubject, TEXT("Test Message Subject")); sMsgProps[0].ulPropTag = PR_MESSAGE_FLAGS; sMsgProps[0].Value.ul = MSGFLAG_UNSENT; sMsgProps[1].ulPropTag = PR_SUBJECT; sMsgProps[1].Value.lpszW = tchSubject; hr = pNewMessage->SetProps(2, sMsgProps, NULL); if(FAILED(hr)) { pNewMessage->Release(); return FALSE; } ////////////////////////////////////////// // Step 5 - Stream the message body IStream *pStream = NULL; TCHAR tchBody[255] = TEXT("\0"); wsprintf(tchBody, TEXT("This is a test of the message body")); hr = pNewMessage->OpenProperty(PR_BODY, NULL, 0, MAPI_CREATE|MAPI_MODIFY, (IUnknown **)&pStream); if(FAILED(hr)) { pNewMessage->Release(); return FALSE; } // Copy the body into the stream DWORD dwLength = (lstrlen(tchBody)+1)*sizeof(TCHAR); pStream->Write(tchBody, dwLength, NULL); pStream->Release(); ////////////////////////////////////////// // Step 6 - Create a recipient list SizedADRLIST(1, msgAdrList); // Allocate a buffer for the entry SPropValue rgMsgProps[3]; memset(&rgMsgProps, 0, sizeof(rgMsgProps)); rgMsgProps[0].ulPropTag = PR_ADDRTYPE; rgMsgProps[0].Value.lpszW = TEXT("SMTP"); rgMsgProps[1].ulPropTag = PR_EMAIL_ADDRESS; rgMsgProps[1].Value.lpszW = TEXT("emailname@emailaddress.com"); rgMsgProps[2].ulPropTag = PR_RECIPIENT_TYPE; rgMsgProps[2].Value.ul = MAPI_TO; msgAdrList.cEntries = 1; msgAdrList.aEntries->cValues = 3; msgAdrList.aEntries->rgPropVals = rgMsgProps; // Add the list to the message hr = pNewMessage->ModifyRecipients(MODRECIP_ADD, (LPADRLIST)&msgAdrList); // Free the buffer MAPIFreeBuffer((LPADRLIST)&msgAdrList); ////////////////////////////////////////// // Step 7 - Submit the message hr = pNewMessage->SubmitMessage(0); if(FAILED(hr)) return FALSE; // Clean up pNewMessage->Release(); pPOPDraftsFolder->Release(); pPop3Store->Release(); Reading a Message
To read the contents of a message, you would do the following: ////////////////////////////////////////// // Step 2 - Open up the Pop3 Inbox folder LPSPropValue rgprops = NULL; ULONG cValues = 0; IMAPIFolder *pPOPInboxFolder = NULL; SizedSPropTagArray(2, rgTags) = {2,{PR_CE_IPM_INBOX_ENTRYID,PR_OBJECT_TYPE}}; // Now get the Inbox folder hr = pPop3Store->GetProps((LPSPropTagArray)&rgTags, MAPI_UNICODE, &cValues, &rgprops); if(FAILED(hr)) return FALSE; hr = pPop3Store->OpenEntry(rgprops[0].Value.bin.cb, (LPENTRYID)rgprops[0].Value.bin.lpb, NULL, MAPI_MODIFY, NULL, (LPUNKNOWN*)&pPOPInboxFolder); if(FAILED(hr)) return FALSE; //////////////////////////////////////////////////////////// // Step 3 - Get the list of messages in the folder and their // ENTRY IDs IMAPITable *pIInboxTable = NULL; IMessage *pMsg = NULL; hr = pPOPInboxFolder->GetContentsTable(0, &pIInboxTable); if(FAILED(hr)) { pPOPInboxFolder->Release(); return FALSE; } while(1) { SRowSet *pRowSet = NULL; // Get the From, Subject and ID fields SizedSPropTagArray(3, tblMessages) = {3,{PR_SENDER_NAME,PR_SUBJECT,PR_ENTRYID}}; pIInboxTable->SetColumns((LPSPropTagArray)&tblMessages, 0); hr = pIInboxTable->QueryRows(1, 0, &pRowSet); if(pRowSet->cRows != 1) break; for(int nVal = 0; nVal < pRowSet->aRow[0].cValues; nVal++) { TCHAR tchProperties[10] = TEXT("\0"); DWORD dwType = 0, dwID = 0; dwType = PROP_TYPE(pRowSet->aRow[0].lpProps[nVal].ulPropTag); dwID = PROP_ID(pRowSet->aRow[0].lpProps[nVal].ulPropTag); wsprintf(tchProperties, TEXT("0x%08x Type:%04x ID:%04x\r\n"), pRowSet->aRow[0].lpProps[nVal].ulPropTag, dwType, dwID); // Do something, such as show the messages in a list? OutputDebugString(tchProperties); } ///////////////////////////////////////////////////////// // Step 4 - Open the message. For the sake of this example, // let's open the first message and break out hr = pPop3Store->OpenEntry (pRowSet->aRow[0].lpProps[2].Value.bin.cb, (LPENTRYID) pRowSet->aRow[0].lpProps[2].Value.bin.lpb, NULL, MAPI_MODIFY, NULL, (LPUNKNOWN*)&pMsg); FreeProws(pRowSet); break; } //////////////////////////////////////////////////////////// // Step 5 - Do something w/ the message if(pMsg) { // Get the from and subject LPSPropValue rgMsgprops = NULL; ULONG cMsgValues = 0; SizedSPropTagArray(2, rgMsgTags) = {2,{PR_SENDER_NAME, PR_SUBJECT}}; hr = pMsg->GetProps((LPSPropTagArray)&rgMsgTags, MAPI_UNICODE, &cMsgValues, &rgMsgprops); // Get the body IStream *pStream = NULL; TCHAR tchBody[255] = TEXT("\0"); hr = pMsg->OpenProperty(PR_BODY, NULL, 0, 0, (IUnknown **)&pStream); if(FAILED(hr)) { pMsg->Release(); pIInboxTable->Release(); pPOPInboxFolder->Release(); return FALSE; } // Read from the stream into the tchBody hr = pStream->Read(tchBody, 254, NULL); pStream->Release(); // Do something with it: TCHAR tchMsg[1024] = TEXT("\0"); wsprintf(tchMsg, TEXT("From: %s\r\nSubject: %s\r\nMsg: %s"), rgMsgprops[0].Value.lpszW,rgMsgprops[1]. Value.lpszW, tchBody); MessageBox(NULL, tchMsg, TEXT("New Message!"), MB_OK|MB_ICONINFORMATION); // Msg cleanup MAPIFreeBuffer(rgMsgprops); pMsg->Release(); } // Cleanup pIInboxTable->Release(); pPOPInboxFolder->Release(); Working with Message AttachmentsMessage attachments are used to send one or more additional "blobs" of data, such as a picture or sound file, along with an e-mail message. Each individual attachment to a message is supported by the IAttach interface. Although the IAttach interface has no unique methods, it is derived from the IMAPIProp interface. Table 11.22 describes the properties that are used to configure an attachment.
Creating an Attachment
The following example creates a message with an attachment: // This is at the point where our message has been created, // and we are about to send it. Before we do, let's attach // a sound file to the message. //////////////////////////////////////// // Step 2 - Attach a file to the message IAttach *pAttach = NULL; ULONG ulAttachNo = 0; hr = pNewMessage->CreateAttach(NULL, 0, &ulAttachNo, &pAttach); if(FAILED(hr)) return FALSE; /////////////////////////////////////////////////// // Step 3 - Set up the properties for the attachment SPropValue rgAttachProps[3]; TCHAR tchFileName[MAX_PATH] = TEXT("\0"); TCHAR tchFilePath[MAX_PATH] = TEXT("\0"); wsprintf(tchFileName, TEXT("Alarm1.wav")); wsprintf(tchFilePath, TEXT("\\Windows\\Alarm1.wav")); memset(&rgAttachProps, 0, sizeof(rgAttachProps)); rgAttachProps[0].ulPropTag = PR_ATTACH_METHOD; rgAttachProps[0].Value.ul = ATTACH_BY_VALUE; // Specify that we are attaching binary data. We'll stream // in the data using IStream below. rgAttachProps[1].ulPropTag = PR_ATTACH_DATA_BIN; rgAttachProps[2].ulPropTag = PR_ATTACH_FILENAME; rgAttachProps[2].Value.lpszW = tchFileName; hr = pAttach->SetProps(3, rgAttachProps, NULL); //////////////////////////////////////////////////////////// // Step 4 - Using IStream, let's stream in the attachment data // from the file HANDLE hAttachFile = NULL; IStream *pAttachStream = NULL; // Get the pointer to the property stream hr = pAttach->OpenProperty(PR_ATTACH_DATA_BIN, NULL, 0, MAPI_CREATE|MAPI_MODIFY, (IUnknown **)&pAttachStream); // Open up the file hAttachFile = CreateFile(tchFilePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_ NORMAL, 0); if(hAttachFile == INVALID_HANDLE_VALUE) { pAttach->Release(); pNewMessage->Release(); pPOPDraftsFolder->Release(); pPop3Store->Release(); return FALSE; } // Read from the file, and write it to the stream DWORD dwRead = 0, dwWritten = 0; LPVOID lpBuffer = NULL; lpBuffer = (LPVOID)LocalAlloc(LPTR, 4096); do { ReadFile(hAttachFile, lpBuffer, 4096, &dwRead, NULL); if(dwRead > 0) { hr = pAttachStream->Write(lpBuffer, dwRead, &dwWritten); if(FAILED(hr)) break; } }while(dwRead > 0); CloseHandle(hAttachFile); LocalFree(lpBuffer); pAttachStream->Commit(STGC_DEFAULT); pAttachStream->Release(); ////////////////////////////////////////// // Step 5 - Submit the message hr = pNewMessage->SubmitMessage(0); if(FAILED(hr)) return FALSE; // Clean up pAttach->Release(); pNewMessage->Release(); pPOPDraftsFolder->Release(); pPop3Store->Release(); Opening an Attachment
The following example shows how to open a message attachment: //////////////////////////////////////////////////////////// // Step 2 - Already have a message that is opened // so, let's go ahead and get the message's attachment by // first getting the attachment table for the message if(!pMsg) return FALSE; IMAPITable *pAttachTable = NULL; hr = pMsg->GetAttachmentTable(0, &pAttachTable); //////////////////////////////////////////////////////////// // Step 3 - Get the properties from the table for the // attachments for the first attachment. We'll only extract // the first one in this example. SRowSet *pAttachRowSet = NULL; SizedSPropTagArray(3, tblAttachColumns) = {3,{PR_ATTACH_NUM,PR_ATTACH_SIZE,PR_ATTACH_FILENAME}}; pAttachTable->SetColumns((LPSPropTagArray)&tblAttachColumns, 0); hr = pAttachTable->QueryRows(1, 0, &pAttachRowSet); if(pAttachRowSet->cRows != 1) return FALSE; //////////////////////////////////////////////////////////// // Step 4 - Grab the properties that we'll use long lAttachNum = 0; DWORD dwAttachSize = 0; TCHAR tchAttachName[MAX_PATH] = TEXT("\0"); lAttachNum = pAttachRowSet->aRow[0].lpProps[0].Value.l; dwAttachSize = pAttachRowSet->aRow[0].lpProps[1].Value.ul; _tcscpy(tchAttachName, pAttachRowSet->aRow[0].lpProps[2]. Value.lpszW); FreeProws(pAttachRowSet); //////////////////////////////////////////////////////////// // Step 5 - Get the IAttach interface for the attachment IAttach *pAttach = NULL; hr = pMsg->OpenAttach(lAttachNum, 0, 0, &pAttach); if(FAILED(hr)) return FALSE; //////////////////////////////////////////////////////////// // Step 6 - Get the IStream interface to stream the PR_ATTACH_ // DATA_BIN property out. Also, set up a file to write to. IStream *pAttachStream = NULL; HANDLE hAttachFile = NULL; TCHAR tchFilePath[MAX_PATH] = TEXT("\0"); wsprintf(tchFilePath, TEXT("\\%s"), tchAttachName); hAttachFile = CreateFile(tchFilePath, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); hr = pAttach->OpenProperty(PR_ATTACH_DATA_BIN, NULL, 0, 0, (IUnknown **)&pAttachStream); if(hAttachFile == INVALID_HANDLE_VALUE || FAILED(hr)) { pAttachStream->Release(); pAttach->Release(); pAttachTable->Release(); pMsg->Release(); pIInboxTable->Release(); pPOPInboxFolder->Release(); return FALSE; } //////////////////////////////////////////////////////////// // Step 7 - Read from the stream, write to the file. LPVOID lpBuffer = NULL; DWORD dwRead = 0, dwWritten = 0; lpBuffer = (LPVOID)LocalAlloc(LPTR, 4096); do { memset(lpBuffer, 0, 4096); pAttachStream->Read(lpBuffer, 4096, &dwRead); if(dwRead > 0) WriteFile(hAttachFile, lpBuffer, dwRead, &dwWritten, NULL); } while(dwRead > 0); CloseHandle(hAttachFile); LocalFree(lpBuffer); // Done. Clean up pAttachStream->Release(); pAttach->Release(); pAttachTable->Release(); pMsg->Release(); pIInboxTable->Release(); pPOPInboxFolder->Release(); |