Not able to send email from Outlook 365 (both old and new outlook) using Full MAPI in C++
We have an application which has option to send emails through Outlook with the option of using either Limited MAPI or Full MAPI. Till now it worked smoothly for all the cases.
But we started facing problem after introduction of Outlook 365. Sending emails using Limited MAPI works well, but emails are not getting sent (nor they appear in outbox) using Full MAPI. For some of the developers, emails sending from the classic outlook 365 using Full MAPI works but for few of them it does not work. And sending mails from the new outlook using Full MAPI does not work at all.
We are using C++ to develop the application.
I am hereby attaching the code to send email using Full MAPI. Any help is highly appreciated.
header file –
#pragma once
#define MDB_ONLINE ((ULONG) 0x00000100)
#include <MAPI.h>
#include <vector>
namespace ISolCommExtMAPI64Bridge {
enum EmailPriority
{
ePriorityLow = 0,
ePriorityNormal = 1,
ePriorityHigh = 2,
};
class MAPIMail64
{
public:
MAPIMail64(void);
~MAPIMail64(void);
int Send();
std::vector<CAtlStringW> attachmentList;
std::vector<CAtlStringW> toRecipientstList;
std::vector<CAtlStringW> CCRecipientstList;
std::vector<CAtlStringW> BCCRecipientstList;
CAtlStringW messageText;
EmailPriority priority;
CAtlStringW senderAddress;
CAtlStringW senderName;
CAtlStringW subject;
CAtlStringW type;
CAtlStringW lastErrorString;
bool MAPIAvailable;
CAtlStringW version;
private:
void Cleanup();
HRESULT InitialiseAndLogon();
HRESULT OpenDefaultMessageStore();
HRESULT OpenOutbox();
HRESULT SetProperty(ULONG ulProperty, CAtlStringW itemText);
HRESULT SetPropertyType2(ULONG ulProperty, CAtlStringW itemText);
HRESULT AddHeaderInformationtoMessage();
HRESULT SetPriority();
int SendMailUsingFullMapiAPI();
HRESULT ProcessAttachments();
HRESULT AddAttachment(CAtlStringW filePathName);
CAtlStringW GetRecipients(const std::vector<CAtlStringW> &recipientsList);
CAtlStringW ErrorMessage(DWORD dwError);
LPMAPISESSION mapiSession;
IMAPITable *messageStoresTable;
LPSRowSet defaultStoreProperties;
IMsgStore *defaultStore;
IMAPIFolder *outbox;
IMessage *message;
LPATTACH attachment;
LPSPropValue recipientValues;
LPADRLIST recipientList;
IStream *messageBody;
LPSTREAM pStrmDest;
LPADRBOOK addrBook;
LPENTRYID EID;
};
}
cpp file-
/**************************************************************************************************
Copyright (c) IRIS Software Ltd 2010
All rights reserved.
Module : MAPIMail64.cpp – This code is a 64 bit copy from the MAPIMail class in the IsolCommExtMAPI
sibling to this project.
NOTE THIS IS BUILT AS A 64-BIT APPLICATION.
+———————+ _________________ +—————————–+
| ISolCommExtMAPI.dll | _________________ > | ISolCommExtMAPI64Bridge.exe |
+———————+ NAMED PIPE / +—————————–+
SendMailUsing64BitBridgeProcess() main()
Author : JDLC
Date : 18/02/2019
Desc : Uses MAPI to send emails and attachments via a 64 Bit proxy process.
This gets around the MS Windows restriction of a 32-bit process (IRIS applications)
not being able to invoke 64-bit mail applications such as Outlook.
**************************************************************************************************/
#include <boost/asio.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <windows.h>
#include “stdafx.h”
#include “MAPIMail64.h”
#include <MAPI.h>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <sstream>
#include <atlbase.h>
#include <atlcom.h>
#define CbNewFlagList(_c_)
(offsetof(FlagList, ulFlag) + ((_c_) * sizeof(ULONG)))
namespace ISolCommExtMAPI64Bridge {
MAPIMail64::MAPIMail64(void)
{
mapiSession = NULL;
messageStoresTable = NULL;
defaultStoreProperties = NULL;
defaultStore = NULL;
outbox = NULL;
message = NULL;
recipientValues = NULL;
recipientList = NULL;
messageBody = NULL;
attachment = NULL;
pStrmDest = NULL;
addrBook = NULL;
EID = NULL;
messageText = _T(“”);
priority = EmailPriority::ePriorityNormal;
senderAddress = _T(“”);
senderName = _T(“”);
subject = _T(“”);
type = _T(“”);
lastErrorString = _T(“”);
MAPIAvailable = false;
version = _T(“”);
}
MAPIMail64::~MAPIMail64(void)
{
}
//CAtlStringW MAPIMail64::ErrorMessage(HRESULT hr) {
// wchar_t* szError = nullptr;
// FormatMessageW(
// FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
// NULL,
// hr,
// MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
// (LPWSTR)&szError,
// 0,
// NULL);
// CAtlStringW errorMessage(szError);
// LocalFree(szError);
// return errorMessage;
//}
void DisplayError(const CAtlStringW& errorMessage)
{
// Convert CAtlStringW to LPCSTR using WideCharToMultiByte
int length = WideCharToMultiByte(CP_UTF8, 0, errorMessage, -1, NULL, 0, NULL, NULL);
if (length > 0)
{
char* utf8String = new char[length];
WideCharToMultiByte(CP_UTF8, 0, errorMessage, -1, utf8String, length, NULL, NULL);
// Display the error message in a message box
MessageBoxA(NULL, utf8String, “Error”, MB_OK | MB_ICONERROR);
delete[] utf8String;
}
}
/**************************************************************************************************
Send()
Main method for class.
RETURNS – 0 if succesful
1 or 2 if a failure occurs during the send process
**************************************************************************************************/
int MAPIMail64::Send()
{
return SendMailUsingFullMapiAPI();
}
/**************************************************************************************************
SendMailUsingFullMapiAPI() – This is the pre-existing method but in 64-bit build exe
Main method for class. calls in sequence meethods that set up MAPI structures and then attempts to
generate the email. Makes sure everything is cleaned up where necassary.
RETURNS – 0 if succesful
1 or 2 if a failure occurs during the send process
**************************************************************************************************/
int MAPIMail64::SendMailUsingFullMapiAPI()
{
try
{
HRESULT hRes = InitialiseAndLogon();
lastErrorString = “InitialiseAndLogon – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){ //Sets Error in method
return 1;}
hRes = OpenDefaultMessageStore();
if(FAILED(hRes)){ //Sets Error in method
return 1;}
hRes = OpenOutbox();
lastErrorString = “OpenOutbox – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){ //Sets Error in method
return 1;}
//Release as we no longer need
if(defaultStore != NULL)
{
defaultStore->Release();
defaultStore = NULL;
}
mapiSession->OpenAddressBook(
NULL,
NULL,
NULL,
&addrBook);
//Create the mail message
hRes = outbox->CreateMessage(NULL, 0, &message);
lastErrorString = “outbox->CreateMessage – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){
lastErrorString = “outbox->CreateMessage failed” +ErrorMessage(hRes);
return 1;}
//Dont use address book here – > emails may not be in exchange server
//”To” Recipients and header info
hRes = AddHeaderInformationtoMessage();
lastErrorString = “outbox->AddHeaderInformationtoMessage – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){ //Sets Error in method
return 1;}
//Set Sender Details
hRes = SetPropertyType2(PR_SENDER_NAME,senderName);
lastErrorString = “PR_SENDER_NAME – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){ //Sets Error in method
return 1;}
hRes = SetPropertyType2(PR_SENDER_EMAIL_ADDRESS, senderAddress);
lastErrorString = “PR_SENDER_EMAIL_ADDRESS – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){ //Sets Error in method
return 1;}
//Message Subject
hRes = SetPropertyType2(PR_SUBJECT, subject);
lastErrorString = “PR_SUBJECT – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){ //Sets Error in method
return 1;}
//Set Low/Normal/High Importance
hRes = SetPriority();
lastErrorString = “SetPriority() – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){ //Sets Error in method
return 1;}
//Message Body
hRes = SetProperty(PR_BODY, messageText);
lastErrorString = “PR_BODY – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){ //Sets Error in method
return 1;}
hRes = ProcessAttachments();
lastErrorString = “ProcessAttachments – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){ //Sets Error in method
return 1;}
// SEND MESSAGE
hRes = message->SubmitMessage(0);
lastErrorString = “message->SubmitMessage – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes))
{
lastErrorString = “message->SubmitMessage failed” +ErrorMessage(hRes);
return 1;
}
}
catch(std::exception& ex)
{
CAtlStringW error(ex.what());
lastErrorString = “MAPIMail64::SendMailUsingMapiStubLibary exception caught : ” + error;
Cleanup();
return 1;
}
catch(…)
{
lastErrorString = “MAPIMail64::SendMailUsingMapiStubLibary unknown exception caught”;
Cleanup();
return 2; //unknown exception
}
Cleanup();
return 0;
}
HRESULT MAPIMail64::InitialiseAndLogon()
{
//Initialise connection
MAPIINIT_0 mapi_ver = {0, MAPI_MULTITHREAD_NOTIFICATIONS};
HRESULT hRes = MAPIInitialize(&mapi_ver);
lastErrorString = “InitialiseAndLogon MAPIInitialize – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){
lastErrorString = “MAPIInitialize failed” +ErrorMessage(hRes);
DisplayError(lastErrorString);
return hRes;}
//Obtain Default Profile and Logon – if default logon cant be found picker dialog will show.
LPTSTR lpProfile = NULL;
hRes = MAPILogonEx(0, NULL, NULL, MAPI_USE_DEFAULT | MAPI_EXTENDED | MAPI_NEW_SESSION | MAPI_LOGON_UI, &mapiSession);
lastErrorString = “InitialiseAndLogon MAPILogonEx – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){
lastErrorString = “MAPILogonEx failed” +ErrorMessage(hRes);
DisplayError(lastErrorString);
return hRes;}
return S_OK;
}
HRESULT MAPIMail64::OpenDefaultMessageStore()
{
//Get the Message Store Table
HRESULT hRes = mapiSession->GetMsgStoresTable(0, &messageStoresTable);
lastErrorString = “GetMsgStoresTable – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){
lastErrorString = “MAPIMail64::InitialiseAndLogon, mapiSession->GetMsgStoresTable failed” +ErrorMessage(hRes);
DisplayError(lastErrorString);
return hRes;}
// Obtain the default store properties
SizedSPropTagArray(2, resourceFlagsTag);
resourceFlagsTag.cValues = 2; // Number of properties below we are specifying
resourceFlagsTag.aulPropTag[0] = PR_DEFAULT_STORE;
resourceFlagsTag.aulPropTag[1] = PR_ENTRYID;
SRestriction defaultStoreRestrictions;
defaultStoreRestrictions.rt = RES_BITMASK;
defaultStoreRestrictions.res.resBitMask.relBMR = BMR_NEZ;
defaultStoreRestrictions.res.resBitMask.ulPropTag = PR_RESOURCE_FLAGS;
defaultStoreRestrictions.res.resBitMask.ulMask = STATUS_DEFAULT_STORE;
hRes = HrQueryAllRows(messageStoresTable, (LPSPropTagArray)&resourceFlagsTag, &defaultStoreRestrictions, NULL, NULL, &defaultStoreProperties);
lastErrorString = “HrQueryAllRows – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){
lastErrorString = “HrQueryAllRows failed” +ErrorMessage(hRes);
DisplayError(lastErrorString);
return hRes;}
if (defaultStoreProperties->cRows != 1) // There can only be 1 default store
{
lastErrorString = “MAPIMail64::InitialiseAndLogon, HrQueryAllRows more then 1 default row returned” +ErrorMessage(hRes);
DisplayError(lastErrorString);
return E_FAIL;
}
//Obtain Default Message Stores ID
LPSPropValue defaultStoreId = PpropFindProp(defaultStoreProperties->aRow[0].lpProps, defaultStoreProperties->aRow[0].cValues, PR_ENTRYID);
if (defaultStoreId == NULL){
lastErrorString = “MAPIMail64::InitialiseAndLogon, PpropFindProp failed” +ErrorMessage(hRes);
DisplayError(lastErrorString);
return hRes;}
//Open Default Message Store
ENTRYID *default_store_entry_id = (LPENTRYID)defaultStoreId->Value.bin.lpb;
//MAPI_NO_CACHE is not being used http://support.microsoft.com/default.aspx?id=834496 as MDB_ONLINE is being used (will this be a issue if other applications have already opened in cache mode)
//Removed MDB_ONLINE as it does not save emails in outbox
hRes = mapiSession->OpenMsgStore(NULL, defaultStoreId->Value.bin.cb, default_store_entry_id, NULL, MAPI_BEST_ACCESS | MDB_WRITE, &defaultStore);
lastErrorString = “OpenMsgStore – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){
lastErrorString = “MAPIMail64::InitialiseAndLogon, mapiSession->OpenMsgStore failed” +ErrorMessage(hRes);
DisplayError(lastErrorString);
return hRes;}
//Release as we no longer need
if( defaultStoreProperties != NULL)
{
FreeProws(defaultStoreProperties);
defaultStoreProperties = NULL;
}
if( messageStoresTable != NULL)
{
messageStoresTable->Release();
messageStoresTable = NULL;
}
return S_OK;
}
HRESULT MAPIMail64::OpenOutbox()
{
// Get the properties of the PR_IPM_OUTBOX_ENTRYID property
SizedSPropTagArray(2, outbox_entry_id_query);
outbox_entry_id_query.cValues = 1;
outbox_entry_id_query.aulPropTag[0] = PR_IPM_OUTBOX_ENTRYID;
ULONG resultCount = 0;
SPropValue *results;
HRESULT hRes = defaultStore->GetProps((LPSPropTagArray)&outbox_entry_id_query, 0, &resultCount, &results);
if(FAILED(hRes)){
lastErrorString = “MAPIMail64::OpenOutbox, GetProps failed” +ErrorMessage(hRes);
return hRes;
}
if(resultCount != 1) // There can only be 1 outbox
{
lastErrorString = “MAPIMail64::OpenOutbox, Result Count for Outbox’s is more then one – E_FAIL”;
return E_FAIL;
}
//Open the outbox folder //MAPI_BEST_ACCESS | MAPI_MODIFY = returns highest level access allowed
ULONG outboxType;
hRes = defaultStore->OpenEntry(results[0].Value.bin.cb, (LPENTRYID)results[0].Value.bin.lpb, NULL, MAPI_MODIFY , &outboxType, (LPUNKNOWN *)&outbox);
if(FAILED(hRes)){
lastErrorString = “MAPIMail64::OpenOutbox, OpenEntry failed” +ErrorMessage(hRes);
return hRes;}
return S_OK;
}
CAtlStringW MAPIMail64::GetRecipients(const std::vector<CAtlStringW> &recipientsList)
{
//Create a list of semi colon delaminated recipients
CAtlStringW recipients = “”;
std::vector<CAtlStringW>::const_iterator itr;
size_t items_remaining = recipientsList.size();
for ( itr = recipientsList.begin(); itr != recipientsList.end(); ++itr )
{
recipients += *itr;
if(items_remaining > 1)
{
recipients += “;”; // We dont want this on the last recipent
}
items_remaining–;
}
return recipients;
}
HRESULT MAPIMail64::ProcessAttachments()
{
HRESULT hRes = S_OK;
std::vector<CAtlStringW>::iterator itr;
for ( itr = attachmentList.begin(); itr != attachmentList.end(); ++itr )
{
hRes = AddAttachment(*itr);
}
return S_OK;
}
HRESULT MAPIMail64::AddAttachment(CAtlStringW filePathName)
{
HRESULT hRes = S_OK;
try
{
pStrmDest = NULL;
ULONG ulAttNum = 0;
std::ifstream is;
is.open (filePathName, std::ifstream::in | std::ios::binary);
if(!is){
return E_FAIL;}
// get length of file:
long length = 0;
is.seekg (0, std::ios::end);
length = static_cast<long> (is.tellg());
is.seekg (0, std::ios::beg);
// allocate memory:
char *buffer = NULL;
buffer = new char[length];
// read data as a block:
is.read(buffer,length);
is.close();
SPropValue *oneProp = NULL;
enum {METHOD,ATTACH_FILENAME,ATTACH_LONG_FILENAME,ATTACH_PATHNAME,ATTACHMENT_FLAGS,ATTACH_SIZE,NUM_ATT_PROPS};
SPropValue props[NUM_ATT_PROPS];
SPropProblemArray* probs=NULL;
ULONG bytesWritten = 0;
// extract file name from attachment file path name
std::wstring attachmentFileName{};
int lastSlashPos = filePathName.ReverseFind(‘\’);
if (lastSlashPos != -1)
{
attachmentFileName = filePathName.Mid(lastSlashPos + 1);
}
else
{
attachmentFileName = filePathName;
}
auto pAttachmentFileName = const_cast<LPWSTR>(attachmentFileName.c_str());
// Create an attachment on the message
hRes = message->CreateAttach(NULL, (ULONG)0, &ulAttNum, &attachment);
if(FAILED(hRes)){
lastErrorString = “message->CreateAttach failed” +ErrorMessage(hRes);
return hRes;}
props[METHOD].ulPropTag =PR_ATTACH_METHOD;
props[METHOD].Value.l =ATTACH_BY_VALUE;
//set attachment properties
props[ATTACH_PATHNAME].ulPropTag =PR_ATTACH_PATHNAME;
props[ATTACH_PATHNAME].Value.lpszW = filePathName.LockBuffer();;
props[ATTACH_FILENAME].ulPropTag =PR_ATTACH_FILENAME;
props[ATTACH_FILENAME].Value.lpszW = pAttachmentFileName;
props[ATTACH_LONG_FILENAME].ulPropTag =PR_ATTACH_LONG_FILENAME;
props[ATTACH_LONG_FILENAME].Value.lpszW = pAttachmentFileName;
props[ATTACHMENT_FLAGS].ulPropTag = PR_MESSAGE_FLAGS;
props[ATTACHMENT_FLAGS].Value.l = 0;
props[ATTACH_SIZE].ulPropTag = PR_ATTACH_SIZE;
props[ATTACH_SIZE].Value.l = length;
hRes=attachment->SetProps(NUM_ATT_PROPS, props, &probs);
if(FAILED(hRes)){
lastErrorString = “attachment->SetProps” +ErrorMessage(hRes);
return hRes;}
hRes = attachment->OpenProperty(PR_ATTACH_DATA_BIN,(LPIID)&IID_IStream, STGM_WRITE, MAPI_CREATE|MAPI_MODIFY , (LPUNKNOWN*)&pStrmDest);
if(FAILED(hRes)){
lastErrorString = “attachment->OpenProperty” +ErrorMessage(hRes);
return hRes;}
hRes = pStrmDest->Write(buffer,length,&bytesWritten);
hRes = pStrmDest->Commit(0);
// Save the changes to the Attachment and message
hRes = attachment->SaveChanges(0);
hRes = message->SaveChanges(KEEP_OPEN_READWRITE);
//Clear up stuff we don’t need
filePathName.UnlockBuffer();
memset(&buffer[0], 0, sizeof(buffer));
delete [] buffer;
delete oneProp;
if( pStrmDest != NULL)
{
pStrmDest->Release();
}
if( attachment != NULL)
{
attachment->Release();
}
}
catch(std::ios_base::failure ex)
{
CAtlStringW error(ex.what());
lastErrorString = “attachment->SetProps ” + error;
return E_FAIL;
}
return hRes;
}
HRESULT MAPIMail64::SetProperty(ULONG ulProperty, CAtlStringW itemText)
{
//Currently used for body text
HRESULT hRes = message->OpenProperty(ulProperty, &IID_IStream, NULL, MAPI_CREATE | MAPI_MODIFY | KEEP_OPEN_READWRITE | FORCE_SAVE | MAPI_ACCESS_MODIFY, (LPUNKNOWN *)&messageBody);
if (FAILED(hRes)){
lastErrorString = “message->OpenProperty” +ErrorMessage(hRes);
return hRes;}
ULONG written;
ULONG body_str_len = itemText.GetLength() * sizeof(wchar_t);
hRes = messageBody->Write(itemText.GetBuffer(), body_str_len, &written);
itemText.ReleaseBuffer();
if (FAILED(hRes)){
lastErrorString = “messageBody->Write” +ErrorMessage(hRes);
return hRes;}
//Make sure expected data was written
if((written != body_str_len) && (written !=NULL))
{
return E_FAIL;
}
BOOL body_updated = FALSE;
hRes = RTFSync(message, RTF_SYNC_RTF_CHANGED | RTF_SYNC_BODY_CHANGED, &body_updated);
if (FAILED(hRes)){
lastErrorString = “RTFSync” +ErrorMessage(hRes);
return hRes;}
if (body_updated)
{
message->SaveChanges(KEEP_OPEN_READWRITE);
}
//Cleanup
messageBody->Commit(STGC_DEFAULT);
messageBody->Release();
messageBody = NULL;
return S_OK;
}
HRESULT MAPIMail64::SetPropertyType2(ULONG ulProperty, CAtlStringW itemText)
{
SPropValue prop;
prop.ulPropTag=ulProperty;
prop.Value.lpszW = itemText.GetBuffer();
itemText.ReleaseBuffer();
HRESULT hRes = message->SetProps(1, &prop, NULL);
if (FAILED(hRes)){
lastErrorString = “SetPropertyType2, “+itemText+ ” , message->SetProps” +ErrorMessage(hRes);
return hRes;}
return hRes;
}
HRESULT MAPIMail64::SetPriority()
{
LONG importance = IMPORTANCE_NORMAL;
switch(priority)
{
case EmailPriority::ePriorityNormal:
importance = IMPORTANCE_NORMAL;
break;
case EmailPriority::ePriorityLow:
importance = IMPORTANCE_LOW;
break;
case EmailPriority::ePriorityHigh:
importance = IMPORTANCE_HIGH;
break;
default:
importance = IMPORTANCE_NORMAL;
}
SPropValue prop;
prop.ulPropTag=PR_IMPORTANCE;
prop.Value.l=importance;
HRESULT hRes = message->SetProps(1, &prop, NULL);
if (FAILED(hRes))
{
lastErrorString = “SetPriority, message->SetProps” +ErrorMessage(hRes);
return hRes;
}
return hRes;
}
HRESULT MAPIMail64::AddHeaderInformationtoMessage()
{
const long bufferMultiplier = 5; // This value equals the size of the recipient values we are submitting
//Allocate email header space
HRESULT hRes = MAPIAllocateBuffer(sizeof(SPropValue) * bufferMultiplier, (LPVOID *)&recipientValues);
lastErrorString = “MAPIAllocateBuffer – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes))
{
lastErrorString = “AddHeaderInformationtoMessage, MAPIAllocateBuffers” +ErrorMessage(hRes);
return hRes;
}
//Create Email header information
recipientValues[0].ulPropTag = PR_ADDRTYPE; //Only used by windows CE, but does not work without it.
recipientValues[0].Value.lpszW = _T(“SMTP”);
recipientValues[1].ulPropTag = PR_RECIPIENT_TYPE;
recipientValues[1].Value.l = MAPI_TO;
CAtlStringW recipients = GetRecipients(toRecipientstList);
CAtlStringW displayName = recipients;
recipientValues[2].ulPropTag = PR_DISPLAY_NAME;
recipientValues[2].Value.lpszW = displayName.GetBuffer();
recipientValues[3].ulPropTag = PR_EMAIL_ADDRESS;
recipientValues[3].Value.lpszW = recipients.GetBuffer();
recipientValues[4].ulPropTag = PR_ENTRYID;
hRes = addrBook->CreateOneOff(
recipientValues[2].Value.lpszW,
recipientValues[0].Value.lpszW,
recipientValues[3].Value.lpszW,
MAPI_UNICODE,
&recipientValues[4].Value.bin.cb,
&EID);
recipientValues[4].Value.bin.lpb = (LPBYTE)EID;
lastErrorString = “CreateOneOff – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
//Create recipient list
hRes = MAPIAllocateBuffer(CbNewADRLIST(1), (LPVOID *)&recipientList);
lastErrorString = “MAPIAllocateBuffer – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes))
{
lastErrorString = “AddHeaderInformationtoMessage, MAPIAllocateBuffer” +ErrorMessage(hRes);
return hRes;
}
//Populate List
recipientList->cEntries = 1;
recipientList->aEntries[0].ulReserved1 = 0;
recipientList->aEntries[0].cValues = 5; //count of value groups we are sending
recipientList->aEntries[0].rgPropVals = recipientValues;
//Add recipient information to the message
hRes = message->ModifyRecipients(MODRECIP_ADD, recipientList);
lastErrorString = “ModifyRecipients – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){
lastErrorString = “AddHeaderInformationtoMessage, message->ModifyRecipients” +ErrorMessage(hRes);
return hRes;}
return S_OK;
}
void MAPIMail64::Cleanup()
{
if(defaultStoreProperties != NULL)
{
FreeProws(defaultStoreProperties);
}
if(defaultStore != NULL)
{
defaultStore->Release();
}
if(messageStoresTable != NULL)
{
messageStoresTable->Release();
}
if(messageBody != NULL)
{
messageBody->Release();
}
if(EID != NULL)
{
MAPIFreeBuffer(EID);
}
if(recipientList != NULL)
{
FreePadrlist(recipientList);
}
if(addrBook != NULL)
{
addrBook->Release();
}
if(message != NULL)
{
message->Release();
}
if(outbox != NULL)
{
outbox->Release();
}
if(mapiSession != NULL)
{
mapiSession->Logoff(NULL, 0, 0);
mapiSession->Release();
}
MAPIUninitialize();
}
CAtlStringW MAPIMail64::ErrorMessage(DWORD dwError)
{
CAtlStringW sErr;
sErr.FormatMessage(_T(” : HRESULT = %1!x!”), dwError);
return sErr;
}
}
We have an application which has option to send emails through Outlook with the option of using either Limited MAPI or Full MAPI. Till now it worked smoothly for all the cases.But we started facing problem after introduction of Outlook 365. Sending emails using Limited MAPI works well, but emails are not getting sent (nor they appear in outbox) using Full MAPI. For some of the developers, emails sending from the classic outlook 365 using Full MAPI works but for few of them it does not work. And sending mails from the new outlook using Full MAPI does not work at all.We are using C++ to develop the application.I am hereby attaching the code to send email using Full MAPI. Any help is highly appreciated.header file – #pragma once
#define MDB_ONLINE ((ULONG) 0x00000100)
#include <MAPI.h>
#include <vector>
namespace ISolCommExtMAPI64Bridge {
enum EmailPriority
{
ePriorityLow = 0,
ePriorityNormal = 1,
ePriorityHigh = 2,
};
class MAPIMail64
{
public:
MAPIMail64(void);
~MAPIMail64(void);
int Send();
std::vector<CAtlStringW> attachmentList;
std::vector<CAtlStringW> toRecipientstList;
std::vector<CAtlStringW> CCRecipientstList;
std::vector<CAtlStringW> BCCRecipientstList;
CAtlStringW messageText;
EmailPriority priority;
CAtlStringW senderAddress;
CAtlStringW senderName;
CAtlStringW subject;
CAtlStringW type;
CAtlStringW lastErrorString;
bool MAPIAvailable;
CAtlStringW version;
private:
void Cleanup();
HRESULT InitialiseAndLogon();
HRESULT OpenDefaultMessageStore();
HRESULT OpenOutbox();
HRESULT SetProperty(ULONG ulProperty, CAtlStringW itemText);
HRESULT SetPropertyType2(ULONG ulProperty, CAtlStringW itemText);
HRESULT AddHeaderInformationtoMessage();
HRESULT SetPriority();
int SendMailUsingFullMapiAPI();
HRESULT ProcessAttachments();
HRESULT AddAttachment(CAtlStringW filePathName);
CAtlStringW GetRecipients(const std::vector<CAtlStringW> &recipientsList);
CAtlStringW ErrorMessage(DWORD dwError);
LPMAPISESSION mapiSession;
IMAPITable *messageStoresTable;
LPSRowSet defaultStoreProperties;
IMsgStore *defaultStore;
IMAPIFolder *outbox;
IMessage *message;
LPATTACH attachment;
LPSPropValue recipientValues;
LPADRLIST recipientList;
IStream *messageBody;
LPSTREAM pStrmDest;
LPADRBOOK addrBook;
LPENTRYID EID;
};
} cpp file- /**************************************************************************************************
Copyright (c) IRIS Software Ltd 2010
All rights reserved.
Module : MAPIMail64.cpp – This code is a 64 bit copy from the MAPIMail class in the IsolCommExtMAPI
sibling to this project.
NOTE THIS IS BUILT AS A 64-BIT APPLICATION.
+———————+ _________________ +—————————–+
| ISolCommExtMAPI.dll | _________________ > | ISolCommExtMAPI64Bridge.exe |
+———————+ NAMED PIPE / +—————————–+
SendMailUsing64BitBridgeProcess() main()
Author : JDLC
Date : 18/02/2019
Desc : Uses MAPI to send emails and attachments via a 64 Bit proxy process.
This gets around the MS Windows restriction of a 32-bit process (IRIS applications)
not being able to invoke 64-bit mail applications such as Outlook.
**************************************************************************************************/
#include <boost/asio.hpp>
#include <boost/asio/ip/tcp.hpp>
#include <windows.h>
#include “stdafx.h”
#include “MAPIMail64.h”
#include <MAPI.h>
#include <iostream>
#include <fstream>
#include <iomanip>
#include <sstream>
#include <atlbase.h>
#include <atlcom.h>
#define CbNewFlagList(_c_)
(offsetof(FlagList, ulFlag) + ((_c_) * sizeof(ULONG)))
namespace ISolCommExtMAPI64Bridge {
MAPIMail64::MAPIMail64(void)
{
mapiSession = NULL;
messageStoresTable = NULL;
defaultStoreProperties = NULL;
defaultStore = NULL;
outbox = NULL;
message = NULL;
recipientValues = NULL;
recipientList = NULL;
messageBody = NULL;
attachment = NULL;
pStrmDest = NULL;
addrBook = NULL;
EID = NULL;
messageText = _T(“”);
priority = EmailPriority::ePriorityNormal;
senderAddress = _T(“”);
senderName = _T(“”);
subject = _T(“”);
type = _T(“”);
lastErrorString = _T(“”);
MAPIAvailable = false;
version = _T(“”);
}
MAPIMail64::~MAPIMail64(void)
{
}
//CAtlStringW MAPIMail64::ErrorMessage(HRESULT hr) {
// wchar_t* szError = nullptr;
// FormatMessageW(
// FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
// NULL,
// hr,
// MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
// (LPWSTR)&szError,
// 0,
// NULL);
// CAtlStringW errorMessage(szError);
// LocalFree(szError);
// return errorMessage;
//}
void DisplayError(const CAtlStringW& errorMessage)
{
// Convert CAtlStringW to LPCSTR using WideCharToMultiByte
int length = WideCharToMultiByte(CP_UTF8, 0, errorMessage, -1, NULL, 0, NULL, NULL);
if (length > 0)
{
char* utf8String = new char[length];
WideCharToMultiByte(CP_UTF8, 0, errorMessage, -1, utf8String, length, NULL, NULL);
// Display the error message in a message box
MessageBoxA(NULL, utf8String, “Error”, MB_OK | MB_ICONERROR);
delete[] utf8String;
}
}
/**************************************************************************************************
Send()
Main method for class.
RETURNS – 0 if succesful
1 or 2 if a failure occurs during the send process
**************************************************************************************************/
int MAPIMail64::Send()
{
return SendMailUsingFullMapiAPI();
}
/**************************************************************************************************
SendMailUsingFullMapiAPI() – This is the pre-existing method but in 64-bit build exe
Main method for class. calls in sequence meethods that set up MAPI structures and then attempts to
generate the email. Makes sure everything is cleaned up where necassary.
RETURNS – 0 if succesful
1 or 2 if a failure occurs during the send process
**************************************************************************************************/
int MAPIMail64::SendMailUsingFullMapiAPI()
{
try
{
HRESULT hRes = InitialiseAndLogon();
lastErrorString = “InitialiseAndLogon – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){ //Sets Error in method
return 1;}
hRes = OpenDefaultMessageStore();
if(FAILED(hRes)){ //Sets Error in method
return 1;}
hRes = OpenOutbox();
lastErrorString = “OpenOutbox – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){ //Sets Error in method
return 1;}
//Release as we no longer need
if(defaultStore != NULL)
{
defaultStore->Release();
defaultStore = NULL;
}
mapiSession->OpenAddressBook(
NULL,
NULL,
NULL,
&addrBook);
//Create the mail message
hRes = outbox->CreateMessage(NULL, 0, &message);
lastErrorString = “outbox->CreateMessage – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){
lastErrorString = “outbox->CreateMessage failed” +ErrorMessage(hRes);
return 1;}
//Dont use address book here – > emails may not be in exchange server
//”To” Recipients and header info
hRes = AddHeaderInformationtoMessage();
lastErrorString = “outbox->AddHeaderInformationtoMessage – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){ //Sets Error in method
return 1;}
//Set Sender Details
hRes = SetPropertyType2(PR_SENDER_NAME,senderName);
lastErrorString = “PR_SENDER_NAME – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){ //Sets Error in method
return 1;}
hRes = SetPropertyType2(PR_SENDER_EMAIL_ADDRESS, senderAddress);
lastErrorString = “PR_SENDER_EMAIL_ADDRESS – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){ //Sets Error in method
return 1;}
//Message Subject
hRes = SetPropertyType2(PR_SUBJECT, subject);
lastErrorString = “PR_SUBJECT – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){ //Sets Error in method
return 1;}
//Set Low/Normal/High Importance
hRes = SetPriority();
lastErrorString = “SetPriority() – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){ //Sets Error in method
return 1;}
//Message Body
hRes = SetProperty(PR_BODY, messageText);
lastErrorString = “PR_BODY – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){ //Sets Error in method
return 1;}
hRes = ProcessAttachments();
lastErrorString = “ProcessAttachments – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){ //Sets Error in method
return 1;}
// SEND MESSAGE
hRes = message->SubmitMessage(0);
lastErrorString = “message->SubmitMessage – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes))
{
lastErrorString = “message->SubmitMessage failed” +ErrorMessage(hRes);
return 1;
}
}
catch(std::exception& ex)
{
CAtlStringW error(ex.what());
lastErrorString = “MAPIMail64::SendMailUsingMapiStubLibary exception caught : ” + error;
Cleanup();
return 1;
}
catch(…)
{
lastErrorString = “MAPIMail64::SendMailUsingMapiStubLibary unknown exception caught”;
Cleanup();
return 2; //unknown exception
}
Cleanup();
return 0;
}
HRESULT MAPIMail64::InitialiseAndLogon()
{
//Initialise connection
MAPIINIT_0 mapi_ver = {0, MAPI_MULTITHREAD_NOTIFICATIONS};
HRESULT hRes = MAPIInitialize(&mapi_ver);
lastErrorString = “InitialiseAndLogon MAPIInitialize – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){
lastErrorString = “MAPIInitialize failed” +ErrorMessage(hRes);
DisplayError(lastErrorString);
return hRes;}
//Obtain Default Profile and Logon – if default logon cant be found picker dialog will show.
LPTSTR lpProfile = NULL;
hRes = MAPILogonEx(0, NULL, NULL, MAPI_USE_DEFAULT | MAPI_EXTENDED | MAPI_NEW_SESSION | MAPI_LOGON_UI, &mapiSession);
lastErrorString = “InitialiseAndLogon MAPILogonEx – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){
lastErrorString = “MAPILogonEx failed” +ErrorMessage(hRes);
DisplayError(lastErrorString);
return hRes;}
return S_OK;
}
HRESULT MAPIMail64::OpenDefaultMessageStore()
{
//Get the Message Store Table
HRESULT hRes = mapiSession->GetMsgStoresTable(0, &messageStoresTable);
lastErrorString = “GetMsgStoresTable – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){
lastErrorString = “MAPIMail64::InitialiseAndLogon, mapiSession->GetMsgStoresTable failed” +ErrorMessage(hRes);
DisplayError(lastErrorString);
return hRes;}
// Obtain the default store properties
SizedSPropTagArray(2, resourceFlagsTag);
resourceFlagsTag.cValues = 2; // Number of properties below we are specifying
resourceFlagsTag.aulPropTag[0] = PR_DEFAULT_STORE;
resourceFlagsTag.aulPropTag[1] = PR_ENTRYID;
SRestriction defaultStoreRestrictions;
defaultStoreRestrictions.rt = RES_BITMASK;
defaultStoreRestrictions.res.resBitMask.relBMR = BMR_NEZ;
defaultStoreRestrictions.res.resBitMask.ulPropTag = PR_RESOURCE_FLAGS;
defaultStoreRestrictions.res.resBitMask.ulMask = STATUS_DEFAULT_STORE;
hRes = HrQueryAllRows(messageStoresTable, (LPSPropTagArray)&resourceFlagsTag, &defaultStoreRestrictions, NULL, NULL, &defaultStoreProperties);
lastErrorString = “HrQueryAllRows – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){
lastErrorString = “HrQueryAllRows failed” +ErrorMessage(hRes);
DisplayError(lastErrorString);
return hRes;}
if (defaultStoreProperties->cRows != 1) // There can only be 1 default store
{
lastErrorString = “MAPIMail64::InitialiseAndLogon, HrQueryAllRows more then 1 default row returned” +ErrorMessage(hRes);
DisplayError(lastErrorString);
return E_FAIL;
}
//Obtain Default Message Stores ID
LPSPropValue defaultStoreId = PpropFindProp(defaultStoreProperties->aRow[0].lpProps, defaultStoreProperties->aRow[0].cValues, PR_ENTRYID);
if (defaultStoreId == NULL){
lastErrorString = “MAPIMail64::InitialiseAndLogon, PpropFindProp failed” +ErrorMessage(hRes);
DisplayError(lastErrorString);
return hRes;}
//Open Default Message Store
ENTRYID *default_store_entry_id = (LPENTRYID)defaultStoreId->Value.bin.lpb;
//MAPI_NO_CACHE is not being used http://support.microsoft.com/default.aspx?id=834496 as MDB_ONLINE is being used (will this be a issue if other applications have already opened in cache mode)
//Removed MDB_ONLINE as it does not save emails in outbox
hRes = mapiSession->OpenMsgStore(NULL, defaultStoreId->Value.bin.cb, default_store_entry_id, NULL, MAPI_BEST_ACCESS | MDB_WRITE, &defaultStore);
lastErrorString = “OpenMsgStore – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){
lastErrorString = “MAPIMail64::InitialiseAndLogon, mapiSession->OpenMsgStore failed” +ErrorMessage(hRes);
DisplayError(lastErrorString);
return hRes;}
//Release as we no longer need
if( defaultStoreProperties != NULL)
{
FreeProws(defaultStoreProperties);
defaultStoreProperties = NULL;
}
if( messageStoresTable != NULL)
{
messageStoresTable->Release();
messageStoresTable = NULL;
}
return S_OK;
}
HRESULT MAPIMail64::OpenOutbox()
{
// Get the properties of the PR_IPM_OUTBOX_ENTRYID property
SizedSPropTagArray(2, outbox_entry_id_query);
outbox_entry_id_query.cValues = 1;
outbox_entry_id_query.aulPropTag[0] = PR_IPM_OUTBOX_ENTRYID;
ULONG resultCount = 0;
SPropValue *results;
HRESULT hRes = defaultStore->GetProps((LPSPropTagArray)&outbox_entry_id_query, 0, &resultCount, &results);
if(FAILED(hRes)){
lastErrorString = “MAPIMail64::OpenOutbox, GetProps failed” +ErrorMessage(hRes);
return hRes;
}
if(resultCount != 1) // There can only be 1 outbox
{
lastErrorString = “MAPIMail64::OpenOutbox, Result Count for Outbox’s is more then one – E_FAIL”;
return E_FAIL;
}
//Open the outbox folder //MAPI_BEST_ACCESS | MAPI_MODIFY = returns highest level access allowed
ULONG outboxType;
hRes = defaultStore->OpenEntry(results[0].Value.bin.cb, (LPENTRYID)results[0].Value.bin.lpb, NULL, MAPI_MODIFY , &outboxType, (LPUNKNOWN *)&outbox);
if(FAILED(hRes)){
lastErrorString = “MAPIMail64::OpenOutbox, OpenEntry failed” +ErrorMessage(hRes);
return hRes;}
return S_OK;
}
CAtlStringW MAPIMail64::GetRecipients(const std::vector<CAtlStringW> &recipientsList)
{
//Create a list of semi colon delaminated recipients
CAtlStringW recipients = “”;
std::vector<CAtlStringW>::const_iterator itr;
size_t items_remaining = recipientsList.size();
for ( itr = recipientsList.begin(); itr != recipientsList.end(); ++itr )
{
recipients += *itr;
if(items_remaining > 1)
{
recipients += “;”; // We dont want this on the last recipent
}
items_remaining–;
}
return recipients;
}
HRESULT MAPIMail64::ProcessAttachments()
{
HRESULT hRes = S_OK;
std::vector<CAtlStringW>::iterator itr;
for ( itr = attachmentList.begin(); itr != attachmentList.end(); ++itr )
{
hRes = AddAttachment(*itr);
}
return S_OK;
}
HRESULT MAPIMail64::AddAttachment(CAtlStringW filePathName)
{
HRESULT hRes = S_OK;
try
{
pStrmDest = NULL;
ULONG ulAttNum = 0;
std::ifstream is;
is.open (filePathName, std::ifstream::in | std::ios::binary);
if(!is){
return E_FAIL;}
// get length of file:
long length = 0;
is.seekg (0, std::ios::end);
length = static_cast<long> (is.tellg());
is.seekg (0, std::ios::beg);
// allocate memory:
char *buffer = NULL;
buffer = new char[length];
// read data as a block:
is.read(buffer,length);
is.close();
SPropValue *oneProp = NULL;
enum {METHOD,ATTACH_FILENAME,ATTACH_LONG_FILENAME,ATTACH_PATHNAME,ATTACHMENT_FLAGS,ATTACH_SIZE,NUM_ATT_PROPS};
SPropValue props[NUM_ATT_PROPS];
SPropProblemArray* probs=NULL;
ULONG bytesWritten = 0;
// extract file name from attachment file path name
std::wstring attachmentFileName{};
int lastSlashPos = filePathName.ReverseFind(‘\’);
if (lastSlashPos != -1)
{
attachmentFileName = filePathName.Mid(lastSlashPos + 1);
}
else
{
attachmentFileName = filePathName;
}
auto pAttachmentFileName = const_cast<LPWSTR>(attachmentFileName.c_str());
// Create an attachment on the message
hRes = message->CreateAttach(NULL, (ULONG)0, &ulAttNum, &attachment);
if(FAILED(hRes)){
lastErrorString = “message->CreateAttach failed” +ErrorMessage(hRes);
return hRes;}
props[METHOD].ulPropTag =PR_ATTACH_METHOD;
props[METHOD].Value.l =ATTACH_BY_VALUE;
//set attachment properties
props[ATTACH_PATHNAME].ulPropTag =PR_ATTACH_PATHNAME;
props[ATTACH_PATHNAME].Value.lpszW = filePathName.LockBuffer();;
props[ATTACH_FILENAME].ulPropTag =PR_ATTACH_FILENAME;
props[ATTACH_FILENAME].Value.lpszW = pAttachmentFileName;
props[ATTACH_LONG_FILENAME].ulPropTag =PR_ATTACH_LONG_FILENAME;
props[ATTACH_LONG_FILENAME].Value.lpszW = pAttachmentFileName;
props[ATTACHMENT_FLAGS].ulPropTag = PR_MESSAGE_FLAGS;
props[ATTACHMENT_FLAGS].Value.l = 0;
props[ATTACH_SIZE].ulPropTag = PR_ATTACH_SIZE;
props[ATTACH_SIZE].Value.l = length;
hRes=attachment->SetProps(NUM_ATT_PROPS, props, &probs);
if(FAILED(hRes)){
lastErrorString = “attachment->SetProps” +ErrorMessage(hRes);
return hRes;}
hRes = attachment->OpenProperty(PR_ATTACH_DATA_BIN,(LPIID)&IID_IStream, STGM_WRITE, MAPI_CREATE|MAPI_MODIFY , (LPUNKNOWN*)&pStrmDest);
if(FAILED(hRes)){
lastErrorString = “attachment->OpenProperty” +ErrorMessage(hRes);
return hRes;}
hRes = pStrmDest->Write(buffer,length,&bytesWritten);
hRes = pStrmDest->Commit(0);
// Save the changes to the Attachment and message
hRes = attachment->SaveChanges(0);
hRes = message->SaveChanges(KEEP_OPEN_READWRITE);
//Clear up stuff we don’t need
filePathName.UnlockBuffer();
memset(&buffer[0], 0, sizeof(buffer));
delete [] buffer;
delete oneProp;
if( pStrmDest != NULL)
{
pStrmDest->Release();
}
if( attachment != NULL)
{
attachment->Release();
}
}
catch(std::ios_base::failure ex)
{
CAtlStringW error(ex.what());
lastErrorString = “attachment->SetProps ” + error;
return E_FAIL;
}
return hRes;
}
HRESULT MAPIMail64::SetProperty(ULONG ulProperty, CAtlStringW itemText)
{
//Currently used for body text
HRESULT hRes = message->OpenProperty(ulProperty, &IID_IStream, NULL, MAPI_CREATE | MAPI_MODIFY | KEEP_OPEN_READWRITE | FORCE_SAVE | MAPI_ACCESS_MODIFY, (LPUNKNOWN *)&messageBody);
if (FAILED(hRes)){
lastErrorString = “message->OpenProperty” +ErrorMessage(hRes);
return hRes;}
ULONG written;
ULONG body_str_len = itemText.GetLength() * sizeof(wchar_t);
hRes = messageBody->Write(itemText.GetBuffer(), body_str_len, &written);
itemText.ReleaseBuffer();
if (FAILED(hRes)){
lastErrorString = “messageBody->Write” +ErrorMessage(hRes);
return hRes;}
//Make sure expected data was written
if((written != body_str_len) && (written !=NULL))
{
return E_FAIL;
}
BOOL body_updated = FALSE;
hRes = RTFSync(message, RTF_SYNC_RTF_CHANGED | RTF_SYNC_BODY_CHANGED, &body_updated);
if (FAILED(hRes)){
lastErrorString = “RTFSync” +ErrorMessage(hRes);
return hRes;}
if (body_updated)
{
message->SaveChanges(KEEP_OPEN_READWRITE);
}
//Cleanup
messageBody->Commit(STGC_DEFAULT);
messageBody->Release();
messageBody = NULL;
return S_OK;
}
HRESULT MAPIMail64::SetPropertyType2(ULONG ulProperty, CAtlStringW itemText)
{
SPropValue prop;
prop.ulPropTag=ulProperty;
prop.Value.lpszW = itemText.GetBuffer();
itemText.ReleaseBuffer();
HRESULT hRes = message->SetProps(1, &prop, NULL);
if (FAILED(hRes)){
lastErrorString = “SetPropertyType2, “+itemText+ ” , message->SetProps” +ErrorMessage(hRes);
return hRes;}
return hRes;
}
HRESULT MAPIMail64::SetPriority()
{
LONG importance = IMPORTANCE_NORMAL;
switch(priority)
{
case EmailPriority::ePriorityNormal:
importance = IMPORTANCE_NORMAL;
break;
case EmailPriority::ePriorityLow:
importance = IMPORTANCE_LOW;
break;
case EmailPriority::ePriorityHigh:
importance = IMPORTANCE_HIGH;
break;
default:
importance = IMPORTANCE_NORMAL;
}
SPropValue prop;
prop.ulPropTag=PR_IMPORTANCE;
prop.Value.l=importance;
HRESULT hRes = message->SetProps(1, &prop, NULL);
if (FAILED(hRes))
{
lastErrorString = “SetPriority, message->SetProps” +ErrorMessage(hRes);
return hRes;
}
return hRes;
}
HRESULT MAPIMail64::AddHeaderInformationtoMessage()
{
const long bufferMultiplier = 5; // This value equals the size of the recipient values we are submitting
//Allocate email header space
HRESULT hRes = MAPIAllocateBuffer(sizeof(SPropValue) * bufferMultiplier, (LPVOID *)&recipientValues);
lastErrorString = “MAPIAllocateBuffer – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes))
{
lastErrorString = “AddHeaderInformationtoMessage, MAPIAllocateBuffers” +ErrorMessage(hRes);
return hRes;
}
//Create Email header information
recipientValues[0].ulPropTag = PR_ADDRTYPE; //Only used by windows CE, but does not work without it.
recipientValues[0].Value.lpszW = _T(“SMTP”);
recipientValues[1].ulPropTag = PR_RECIPIENT_TYPE;
recipientValues[1].Value.l = MAPI_TO;
CAtlStringW recipients = GetRecipients(toRecipientstList);
CAtlStringW displayName = recipients;
recipientValues[2].ulPropTag = PR_DISPLAY_NAME;
recipientValues[2].Value.lpszW = displayName.GetBuffer();
recipientValues[3].ulPropTag = PR_EMAIL_ADDRESS;
recipientValues[3].Value.lpszW = recipients.GetBuffer();
recipientValues[4].ulPropTag = PR_ENTRYID;
hRes = addrBook->CreateOneOff(
recipientValues[2].Value.lpszW,
recipientValues[0].Value.lpszW,
recipientValues[3].Value.lpszW,
MAPI_UNICODE,
&recipientValues[4].Value.bin.cb,
&EID);
recipientValues[4].Value.bin.lpb = (LPBYTE)EID;
lastErrorString = “CreateOneOff – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
//Create recipient list
hRes = MAPIAllocateBuffer(CbNewADRLIST(1), (LPVOID *)&recipientList);
lastErrorString = “MAPIAllocateBuffer – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes))
{
lastErrorString = “AddHeaderInformationtoMessage, MAPIAllocateBuffer” +ErrorMessage(hRes);
return hRes;
}
//Populate List
recipientList->cEntries = 1;
recipientList->aEntries[0].ulReserved1 = 0;
recipientList->aEntries[0].cValues = 5; //count of value groups we are sending
recipientList->aEntries[0].rgPropVals = recipientValues;
//Add recipient information to the message
hRes = message->ModifyRecipients(MODRECIP_ADD, recipientList);
lastErrorString = “ModifyRecipients – ” + ErrorMessage(hRes);
DisplayError(lastErrorString);
if(FAILED(hRes)){
lastErrorString = “AddHeaderInformationtoMessage, message->ModifyRecipients” +ErrorMessage(hRes);
return hRes;}
return S_OK;
}
void MAPIMail64::Cleanup()
{
if(defaultStoreProperties != NULL)
{
FreeProws(defaultStoreProperties);
}
if(defaultStore != NULL)
{
defaultStore->Release();
}
if(messageStoresTable != NULL)
{
messageStoresTable->Release();
}
if(messageBody != NULL)
{
messageBody->Release();
}
if(EID != NULL)
{
MAPIFreeBuffer(EID);
}
if(recipientList != NULL)
{
FreePadrlist(recipientList);
}
if(addrBook != NULL)
{
addrBook->Release();
}
if(message != NULL)
{
message->Release();
}
if(outbox != NULL)
{
outbox->Release();
}
if(mapiSession != NULL)
{
mapiSession->Logoff(NULL, 0, 0);
mapiSession->Release();
}
MAPIUninitialize();
}
CAtlStringW MAPIMail64::ErrorMessage(DWORD dwError)
{
CAtlStringW sErr;
sErr.FormatMessage(_T(” : HRESULT = %1!x!”), dwError);
return sErr;
}