Sending an Outgoing Message Requesting a Read Receipt With MAPI

[This is now documented here: https://msdn.microsoft.com/en-us/library/cc979231.aspx ]

This is the third part of a three part series documenting the MFCMAPI sample add-in CreateOutlookItemsAddin. We're in the process of updating the MAPI documentation and these articles are a preview of some of the new content. This article assumes you have downloaded the add-in from the above link and are running it inside the current version of MFCMAPI. Feedback on the article and on the code is especially welcome.

Part 1: Creating a Recurring Appointment With MAPI

Part 2: Creating a Recurring Task With MAPI

Sending an Outgoing Message Requesting a Read Receipt

When a read receipt is requested, the messaging system will generate a read report when the recipient has read the message.

To create and send an message requesting a read receipt

  1. Create an outgoing message. See Handling an Outgoing Message.
  2. Add the PR_READ_RECEIPT_REQUESTED property and set it to true.
  3. Add the PR_CONVERSATION_INDEX property.
  4. Add the PR_REPORT_TAG property.
  5. Submit the message by calling IMessage::SubmitMessage.

MFCMAPI demonstrates these steps with the AddMail function. AddMail takes numerous parameters from the Add Mail dialog box that is displayed when the user selects Add Mail on the Addins menu in MFCMAPI. The DisplayAddMailDialog method in Mail.cpp displays the dialog box and passes values from the dialog box to the AddMail method. The DisplayAddMailDialog method does not relate directly to creating a mail item using MAPI, so it is not listed here. The AddMail method is listed below. Note that the first parameter passed to the AddMail method is a pointer to an IMAPIFolder interface. Given lpFolder that represents an IMAPIFolder interface, the code calls IMAPIFolder::CreateMessage. The CreateMessage method returns a success code and a pointer to a pointer to an IMessage interface. Most of the AddMail function code handles the work of property setting in preparation for IMAPIProp::SetProps. If the SetProps call succeeds, IMAPIProp::SaveChanges commits the changes to the store and creates a new mail item. Then, if requested, IMessage::SubmitMessage is called to send the message.

AddMail uses two helper functions to build values for the PR_CONVERSATION_INDEX and PR_REPORT_TAG properties. These functions are named BuildConversationIndex and AddReportTag, respectively. BuildConversationIndex, located in CreateOutlookItemsAddin.cpp, does the same work that the built in MAPI function ScCreateConversationIndex when a parent isn’t passed. The format of the conversation index buffer which it generates is documented in [MS-OXOMSG].pdf, section 2.2.1.2, PidTagConversationIndex. AddReportTag, located in Mails.cpp, in turn calls BuildReportTag to build a structure for PR_REPORT_TAG. This structure is documented in [MS-OXOMSG].pdf, section 2.2.2.1.19, PidTagReportTag.

Code Snippet

 
HRESULT AddMail(LPMAPISESSION lpMAPISession,
                LPMAPIFOLDER lpFolder,
                LPWSTR szSubject,
                LPWSTR szBody,
                LPWSTR szRecipientName,
                BOOL bHighImportance,
                BOOL bReadReceipt,
                BOOL bSubmit,
                BOOL bDeleteAfterSubmit)
{
    if (!lpFolder) return MAPI_E_INVALID_PARAMETER;
    HRESULT hRes = S_OK;
    LPMESSAGE lpMessage = 0;
    // create a message and set its properties
    hRes = lpFolder->CreateMessage(0,
        0,
        &lpMessage);
    if (SUCCEEDED(hRes))
    {
        // Since we know in advance which props
        // we'll be setting, we can statically
        // declare most of the structures involved
        // and save expensive MAPIAllocateBuffer calls
        // For brevity, code to set most spvProps
        // has been removed. For the complete listing, see
        // AddMail in Mails.cpp
    spvProps[p_PR_MESSAGE_CLASS_W].Value.lpszW = L"IPM.Note";
    spvProps[p_PR_ICON_INDEX].Value.l = 0x103; // Unsent Mail
    spvProps[p_PR_SUBJECT_W].Value.lpszW = szSubject;
    spvProps[p_PR_CONVERSATION_TOPIC_W].Value.lpszW = szSubject;
    spvProps[p_PR_BODY_W].Value.lpszW = szBody;
    spvProps[p_PR_IMPORTANCE].Value.l = bHighImportance?IMPORTANCE_HIGH:IMPORTANCE_NORMAL;
    spvProps[p_PR_READ_RECEIPT_REQUESTED].Value.b = bReadReceipt?true:false;
    spvProps[p_PR_MESSAGE_FLAGS].Value.l = MSGFLAG_UNSENT;
    spvProps[p_PR_MSG_EDITOR_FORMAT].Value.l = EDITOR_FORMAT_PLAINTEXT;
    spvProps[p_PR_MESSAGE_LOCALE_ID].Value.l = 1033; // (en-us)
    spvProps[p_PR_INETMAIL_OVERRIDE_FORMAT].Value.l = NULL; // Mail system chooses default encoding scheme
    spvProps[p_PR_DELETE_AFTER_SUBMIT].Value.b = bDeleteAfterSubmit?true:false;
    spvProps[p_PR_INTERNET_CPID].Value.l = cpidASCII;

    hRes = BuildConversationIndex(
        &spvProps[p_PR_CONVERSATION_INDEX].Value.bin.cb,
        &spvProps[p_PR_CONVERSATION_INDEX].Value.bin.lpb);

    if (SUCCEEDED(hRes))
    {
        hRes = lpMessage->SetProps(NUM_PROPS, spvProps, NULL);
        if (SUCCEEDED(hRes))
        {
            hRes = AddRecipient(lpMAPISession,
                lpMessage,
                MAPI_TO,
                szRecipientName);
            AddInLog(true,L"CallMenu: AddRecipient - returned hRes = 0x%08X\n",hRes);
            if (SUCCEEDED(hRes))
            {
                if (bReadReceipt)
                {
                    hRes = AddReportTag(lpMessage);
                }

                if (SUCCEEDED(hRes))
                {
                    hRes = lpMessage->SaveChanges(KEEP_OPEN_READWRITE);
                    if (SUCCEEDED(hRes) && bSubmit)
                    {
                        hRes = lpMessage->SubmitMessage(NULL);
                    }
                }
            }
        }
    }
    if (spvProps[p_PR_CONVERSATION_INDEX].Value.bin.lpb) 
        delete[] spvProps[p_PR_CONVERSATION_INDEX].Value.bin.lpb;
}
if (lpMessage) lpMessage->Release();
return hRes;

}