<?xml version="1.0" encoding="UTF-8"?><!-- generator="wordpress.com" -->
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	>

<channel>
	<title>illustrative-mapi-example &amp;laquo; WordPress.com Tag Feed</title>
	<link>http://en.wordpress.com/tag/illustrative-mapi-example/</link>
	<description>Feed of posts on WordPress.com tagged "illustrative-mapi-example"</description>
	<pubDate>Mon, 20 May 2013 18:22:34 +0000</pubDate>

	<generator>http://en.wordpress.com/tags/</generator>
	<language>en</language>

<item>
<title><![CDATA[MAPI How-to]]></title>
<link>http://mapilessons.wordpress.com/2012/04/04/mapi-how-to/</link>
<pubDate>Wed, 04 Apr 2012 16:27:58 +0000</pubDate>
<dc:creator>mapilessons</dc:creator>
<guid>http://mapilessons.wordpress.com/2012/04/04/mapi-how-to/</guid>
<description><![CDATA[Sending an email seems like a simple task, but what if you don&#8217;t want to (or can&#8217;t) actu]]></description>
<content:encoded><![CDATA[<p>Sending an email seems like a simple task, but what if you don&#8217;t want to (or can&#8217;t) actually hit the &#8220;Send&#8221; button? What if you need to send out a bunch of emails, every day? Especially when these emails are mostly the same, you want to use MAPI, Microsoft&#8217;s Messaging Application Programming Interface.</p>
<p>Of course, you could just buy a commercial tool to get this done, but where&#8217;s the fun in that? I had a bunch of emails that needed to be sent daily (to around 50 distinct recipients), which is a huge time hog if you do it by hand. So, I decided that I&#8217;d try to write some code in C++ to get the emails sent automatically. That doesn&#8217;t sound too imposing, but it ended up being trickier than I&#8217;d expected, which is why I&#8217;m writing this &#8211; so that the next confused newbie with MAPI isn&#8217;t lost in the dark reaches of the internet searching for a serviceable example.</p>
<p>I finally found one at <a href="http://mapistublibrary.codeplex.com/" target="_blank">http://mapistublibrary.codeplex.com/</a> contained within the documentation for their library, which goes around linking with MAPI explicitly to allow MAPI to function on both 32 and 64 bit platforms. How I got to this point I won&#8217;t detail, but suffice to say that it involved a lot of looking through various forums and webpages without ever encountering an example that just sent email. There was one that did it &#8211; but for a Pocket PC! That was the one I&#8217;d been using to model my code on before I came across this one.</p>
<p>Essentially, I took their example and made it work for me. Because of this, the MAPI Stub Library is necessary if using code based on this, but it&#8217;s free and there&#8217;s documentation on how to install it, so that shouldn&#8217;t cause a problem for anybody. Here&#8217;s the main body of my code. I&#8217;ll explain most of it in detail as we go through &#8211; at least the parts I understand. I&#8217;m no expert, but I&#8217;ve picked up enough that I hope my explanation will be helpful to the MAPI uninitiated.</p>
<p><code><br />
#include &#60;windows.h&#62;</p>
<p>#include &#60;mapix.h&#62;<br />
#include &#60;mapiutil.h&#62;<br />
#include &#60;mapi.h&#62;<br />
#include &#60;atlbase.h&#62;</p>
<p>#include &#60;string&#62;<br />
#include &#60;string.h&#62;<br />
#include &#60;vector&#62;<br />
#include &#60;fstream&#62;<br />
#include &#60;assert.h&#62;<br />
//#include &#60;stdlib.h&#62;</p>
<p>#include &#60;iostream&#62;<br />
#include &#60;iomanip&#62;</p>
<p>using namespace std;</p>
<p>#pragma warning( disable : 4127)</p>
<p>#define CORg(_hr) \<br />
&#160;&#160;&#160;&#160;&#160;&#160;do { \<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;hr = _hr; \<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;if (FAILED(hr)) \<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;{ \<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;std::wcout &#60;&#60; L"FAILED! hr = " &#60;&#60; std::hex &#60;&#60; hr &#60;&#60; L". LINE = " &#60;&#60; std::dec &#60;&#60; __LINE__ &#60;&#60; std::endl; \<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;std::wcout &#60;&#60; L" &#62;&#62;&#62; " &#60;&#60; (wchar_t*) L#_hr &#60;&#60; std::endl; \<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;goto Error; \<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;} \<br />
&#160;&#160;&#160;&#160;&#160;&#160;} while (0)</p>
<p>int ListStoresTable(IMAPISession *pSession)<br />
{<br />
&#160;&#160;&#160;&#160;&#160;&#160;HRESULT hr = S_OK;<br />
&#160;&#160;&#160;&#160;&#160;&#160;CComPtr spTable;<br />
&#160;&#160;&#160;&#160;&#160;&#160;SRowSet *pmrows = NULL;</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;enum MAPIColumns<br />
&#160;&#160;&#160;&#160;&#160;&#160;{<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;COL_ENTRYID = 0,<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;COL_DISPLAYNAME_W,<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;COL_DISPLAYNAME_A,<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;cCols // End marker<br />
&#160;&#160;&#160;&#160;&#160;&#160;};</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;static const SizedSPropTagArray(cCols, mcols) =<br />
&#160;&#160;&#160;&#160;&#160;&#160;{<br />
&#160;&#160;&#160;&#160;&#160;&#160;cCols,<br />
&#160;&#160;&#160;&#160;&#160;&#160;{<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;PR_ENTRYID,<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;PR_DISPLAY_NAME_W,<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;PR_DISPLAY_NAME_A,<br />
&#160;&#160;&#160;&#160;&#160;&#160;}<br />
};</p>
<p>CORg(pSession-&#62;GetMsgStoresTable(0, ;spTable));</p>
<p>CORg(spTable-&#62;SetColumns((LPSPropTagArray);mcols, TBL_BATCH));<br />
CORg(spTable-&#62;SeekRow(BOOKMARK_BEGINNING, 0, 0));</p>
<p>CORg(spTable-&#62;QueryRows(50, 0, ;pmrows));</p>
<p>std::wcout &#60;&#60; L"Found " &#60;&#60; pmrows-&#62;cRows &#60;&#60; L" stores in MAPI profile:" &#60;&#60; std::endl;<br />
for (UINT i=0; i != pmrows-&#62;cRows; i++)<br />
{<br />
&#160;&#160;&#160;&#160;&#160;&#160;SRow *prow = pmrows-&#62;aRow + i;<br />
&#160;&#160;&#160;&#160;&#160;&#160;LPCWSTR pwz = NULL;<br />
&#160;&#160;&#160;&#160;&#160;&#160;LPCSTR pwzA = NULL;<br />
&#160;&#160;&#160;&#160;&#160;&#160;if (PR_DISPLAY_NAME_W == prow-&#62;lpProps[COL_DISPLAYNAME_W].ulPropTag)<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;pwz = prow-&#62;lpProps[COL_DISPLAYNAME_W].Value.lpszW;<br />
&#160;&#160;&#160;&#160;&#160;&#160;if (PR_DISPLAY_NAME_A == prow-&#62;lpProps[COL_DISPLAYNAME_A].ulPropTag)<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;pwzA = prow-&#62;lpProps[COL_DISPLAYNAME_A].Value.lpszA;<br />
&#160;&#160;&#160;&#160;&#160;&#160;if (pwz)<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;std::wcout &#60;&#60; L" " &#60;&#60; std::setw(4) &#60;&#60; i &#60;&#60; ": " &#60;&#60; (pwz ? pwz : L"") &#60;&#60; std::endl;<br />
&#160;&#160;&#160;&#160;&#160;&#160;else<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;std::wcout &#60;&#60; L" " &#60;&#60; std::setw(4) &#60;&#60; i &#60;&#60; ": " &#60;&#60; (pwzA ? pwzA : "") &#60;&#60; std::endl;<br />
&#160;&#160;&#160;&#160;&#160;&#160;}</p>
<p>Error:<br />
&#160;&#160;&#160;&#160;&#160;&#160;FreeProws(pmrows);<br />
&#160;&#160;&#160;&#160;&#160;&#160;return 0;<br />
}</p>
<p>int TestSimpleMapi(string reName, string reAddress, string subj, string body)<br />
{<br />
&#160;&#160;&#160;&#160;&#160;&#160;MapiMessage msg = {0};<br />
&#160;&#160;&#160;&#160;&#160;&#160;MapiRecipDesc recip = {0};</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;recip.ulRecipClass = MAPI_TO;<br />
&#160;&#160;&#160;&#160;&#160;&#160;recip.lpszName = (LPSTR)reName.c_str();<br />
&#160;&#160;&#160;&#160;&#160;&#160;recip.lpszAddress = (LPSTR)reAddress.c_str();</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;msg.lpszSubject = (LPSTR)subj.c_str();<br />
&#160;&#160;&#160;&#160;&#160;&#160;msg.lpszNoteText = (LPSTR)body.c_str();<br />
&#160;&#160;&#160;&#160;&#160;&#160;msg.lpRecips = ;recip;<br />
&#160;&#160;&#160;&#160;&#160;&#160;msg.nRecipCount = 1;</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;MAPISendMail(NULL, 0, ;msg, MAPI_LOGON_UI, 0);</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;return 0;<br />
}</p>
<p>void ForceOutlookMAPI(bool fForce);</p>
<p>int __cdecl main(int argc, char** argv)<br />
{</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;string fName = argv[1];</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;HRESULT hr = S_OK;</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;MAPIINIT_0 MAPIINIT= { 0, MAPI_MULTITHREAD_NOTIFICATIONS};</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;ifstream fin(fName.c_str());</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;vectortotalMessages;<br />
&#160;&#160;&#160;&#160;&#160;&#160;vector&#60;string&#62; names;<br />
&#160;&#160;&#160;&#160;&#160;&#160;vector&#60;string&#62; addresses;<br />
&#160;&#160;&#160;&#160;&#160;&#160;vector&#60;string&#62; subjects;<br />
&#160;&#160;&#160;&#160;&#160;&#160;vector&#60;string&#62; bodies;</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;string s;<br />
&#160;&#160;&#160;&#160;&#160;&#160;while(getline(fin, s, '#')){<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;if(s.length() &#62; 3){<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;s+="#";<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;totalMessages.push_back(s);<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;}<br />
&#160;&#160;&#160;&#160;&#160;&#160;}<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;//cout &#60;&#60; totalMessages.size() &#60;&#60; "\n";<br />
&#160;&#160;&#160;&#160;&#160;&#160;int start, end;<br />
&#160;&#160;&#160;&#160;&#160;&#160;for(int j = 0; j &#60; totalMessages.size(); j++){</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;/*the name*/<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;start = 0;<br />
&#160;&#160;&#160;&#160;&#160;&#160;end = 0;</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;//email address<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;start = totalMessages[j].find_first_of('&#62;', 0);<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;end = totalMessages[j].find_first_of('\n', start+1);<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;addresses.push_back(totalMessages[j].substr(start+1, (end-start)));<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;names.push_back(totalMessages[j].substr(start+1, end-start));</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;//subject line<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;start = end;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;end = totalMessages[j].find_first_of('\n', start+1);<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;subjects.push_back(totalMessages[j].substr(start+1, end-start));</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;//message body<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;start = end;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;end = totalMessages[j].size();<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;bodies.push_back(totalMessages[j].substr(start+1, end-start));<br />
&#160;&#160;&#160;&#160;&#160;&#160;}</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;//trim newline characters.<br />
&#160;&#160;&#160;&#160;&#160;&#160;int endpos;<br />
&#160;&#160;&#160;&#160;&#160;&#160;for(int k = 0; k &#60; addresses.size(); k++){<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;endpos = addresses[k].find_last_not_of("\n");<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;if(string::npos != endpos){<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;addresses[k] = addresses[k].substr(0,endpos+1);<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;}<br />
&#160;&#160;&#160;&#160;&#160;&#160;}<br />
&#160;&#160;&#160;&#160;&#160;&#160;for(int k = 0; k &#60; subjects.size(); k++){<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;endpos = subjects[k].find_last_not_of("\n");<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;if(string::npos != endpos){<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;subjects[k] = subjects[k].substr(0,endpos+1);<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;}<br />
&#160;&#160;&#160;&#160;&#160;&#160;}</p>
<p>//ForceOutlookMAPI(true);</p>
<p>//assert(names.size() == addresses.size());<br />
//assert(names.size() == subjects.size());<br />
//assert(names.size() == bodies.size());<br />
//assert(names.size() == totalMessages.size());</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;string smtp = "SMTP:";</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;for(int i = 0; i &#60; names.size();i++){<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;cout &#60;&#60; totalMessages.size() - i &#60;&#60;"\n";<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;TestSimpleMapi(names[i],smtp + addresses[i],subjects[i],bodies[i]);<br />
&#160;&#160;&#160;&#160;&#160;&#160;}</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;CORg(MAPIInitialize (;MAPIINIT));</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;{ // IMAPISession Smart Pointer Context<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;CComPtr spSession;<br />
&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;CORg(MAPILogonEx(NULL, NULL, NULL, MAPI_UNICODE &#124; MAPI_LOGON_UI, ;spSession));</p>
<p>&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;&#160;ListStoresTable(spSession);<br />
&#160;&#160;&#160;&#160;&#160;&#160;}</p>
<p>MAPIUninitialize();</p>
<p>Error:<br />
&#160;&#160;&#160;&#160;&#160;&#160;return 0;<br />
}</p>
<p>The first thing you see is the #include list. There's only one item there that really merits attention, and that's atlbase.h. Atlbase.h is necessary for this file to work, since it works with the MAPI Stub Library; however, it's no longer included by Microsoft with the free version of Visual C++ (as of VC++ 2010 Express). It is included with the paid version, but we've already decided we're not paying for third-party software, so we're going to acquire it ourselves. The Microsoft Platform SDK for Server 2003 does come with atlbase.h, and it's available for download <a title="here" href="http://www.microsoft.com/download/en/details.aspx?id=6510" target="_blank">here</a>. Once you download and install that, you have to find atlbase.h and move it into Visual Studio's include folder (C:\Program Files\Microsoft Visual Studio 10.0\VC\include\ if you used the standard directory path to install VC++ 2010 Express). I'd recommend moving everything in atlbase.h's folder in the Platform SDK install into this new directory, since VC++ usually wants to compile atlbase.h itself and atlbase.h depends on several other files there.</p>
<p>Next we have a definition; that's part of the example file that I used that came with the Mapi Stub Library so I haven't touched it, nor would I recommend that you do so.</p>
<p>After that comes the listStoresTable function, which I also recommend against messing with - I didn't.</p>
<p>After that comes the interesting part. The function testSimpleMapi is where the email is actually being sent. What I did was make it take parameters (it originally was just sending to a dummy email address) and use them to send the message. This allows the function calling testSimpleMapi to choose the values for the Name, Address, Subject, and Body fields of the email, basically allowing just about any email to be sent. It also expresses them as strings, which makes passing them much easier compared to the LPSTR that Mapi expects. LPSTR is essentially a special type of string that Mapi uses - for our purposes we don't need to know anything other than that the cast is required.</p>
<p>Then we've got the main function of the program. Since for my particular purpose I needed to run it from the command line on a text file that contained all the emails I wanted to send formatted a particular way, I create a ifstream to read in the file, then split it into strings based on my delimiter: the #. The vector formed by these strings is totalMessages. Next, I used the fact that the text file included all the email addresses as the first line following the end of the last message, and the subject after that. For your purposes this will probably be different, so don't be afraid to fiddle with the code in this section - much of it is specific to my particular set of circumstances. However, I chose to leave it in so that you could see what I did, and hopefully then you could modify it to your own ends. After making vectors for each field that I intended to pass, I trimmed newline characters off (since they had a tendency to keep cropping up). Then, I added "SMTP:" to each email address, because Mapi expects the email addresses to have the type of protocol, a colon, and then the actual address; example@example.com needs to be "SMPT:example@example.com" for Mapi to accept it as legitimate. If your email system is using a different protocol than SMTP, you'd put that in instead. After that, I just used a for-loop to send all the emails.</p>
<p>The last series of instructions in the main function are there to un-initialize Mapi, since it can't be left running. Don't mess with them!</p>
<p>Basically, that's how to send out a bunch of email using Mapi.</p>
]]></content:encoded>
</item>

</channel>
</rss>
