Fixed issue #2504: Problems with MS Outlook and generated emails
[TortoiseGit.git] / src / Utils / MailMsg.cpp
blob20a71e85f5f90bc11504b55af78034e9b6dcf0b7
1 /*************************************************************************************
2 This file is a part of CrashRpt library.
4 Copyright (c) 2003, Michael Carruth
5 All rights reserved.
7 Adjusted by Sven Strickroth <email@cs-ware.de>, 2011, 2015
8 * make it work with no attachments
9 * added flag to show mail compose dialog
10 * make it work with 32-64bit inconsistencies (http://msdn.microsoft.com/en-us/library/dd941355.aspx)
11 * auto extract filenames of attachments
12 * make work with multiple recipients (to|cc)
14 Redistribution and use in source and binary forms, with or without modification,
15 are permitted provided that the following conditions are met:
17 * Redistributions of source code must retain the above copyright notice, this
18 list of conditions and the following disclaimer.
20 * Redistributions in binary form must reproduce the above copyright notice,
21 this list of conditions and the following disclaimer in the documentation
22 and/or other materials provided with the distribution.
24 * Neither the name of the author nor the names of its contributors
25 may be used to endorse or promote products derived from this software without
26 specific prior written permission.
29 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
30 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
31 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
32 SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
33 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
34 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
35 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
36 STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
37 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 ***************************************************************************************/
40 ///////////////////////////////////////////////////////////////////////////////
42 // Module: MailMsg.cpp
44 // Desc: See MailMsg.h
46 // Copyright (c) 2003 Michael Carruth
48 ///////////////////////////////////////////////////////////////////////////////
50 #include "stdafx.h"
51 #include "MailMsg.h"
52 #include "UnicodeUtils.h"
54 CMailMsg::CMailMsg()
56 m_hMapi = NULL;
57 m_lpMapiSendMail = NULL;
58 m_bReady = FALSE;
59 m_bShowComposeDialog = FALSE;
62 CMailMsg::~CMailMsg()
64 if (m_bReady)
65 MAPIFinalize();
69 void CMailMsg::SetFrom(const CString& sAddress, const CString& sName)
71 m_from = CUnicodeUtils::GetUTF8(L"SMTP:" + sAddress);
72 m_fromname = CUnicodeUtils::GetUTF8(sName);
75 static void addAdresses(std::vector<std::string>& recipients, const CString& sAddresses)
77 int start = 0;
78 while (start >= 0)
80 CString address = sAddresses.Tokenize(_T(";"), start);
81 address = address.Trim();
82 if (address.IsEmpty())
83 continue;
84 recipients.push_back((std::string)CUnicodeUtils::GetUTF8(L"SMTP:" + address));
88 void CMailMsg::SetTo(const CString& sAddresses)
90 addAdresses(m_to, sAddresses);
93 void CMailMsg::SetSubject(CString sSubject)
95 m_sSubject = CUnicodeUtils::GetUTF8(sSubject);
98 void CMailMsg::SetMessage(CString sMessage)
100 m_sMessage = CUnicodeUtils::GetUTF8(sMessage);
103 void CMailMsg::SetShowComposeDialog(BOOL showComposeDialog)
105 m_bShowComposeDialog = showComposeDialog;
108 void CMailMsg::SetCC(const CString& sAddresses)
110 addAdresses(m_cc, sAddresses);
113 void CMailMsg::AddAttachment(CString sAttachment, CString sTitle)
115 if (sTitle.IsEmpty())
117 int position = sAttachment.ReverseFind(_T('\\'));
118 if(position >=0)
120 sTitle = sAttachment.Mid(position+1);
122 else
124 sTitle = sAttachment;
127 m_attachments[(LPCSTR)CUnicodeUtils::GetUTF8(sAttachment)] = CUnicodeUtils::GetUTF8(sTitle);
130 BOOL CMailMsg::DetectMailClient(CString& sMailClientName)
132 CRegKey regKey;
133 TCHAR buf[1024] = _T("");
134 ULONG buf_size = 0;
135 LONG lResult;
137 lResult = regKey.Open(HKEY_CURRENT_USER, _T("SOFTWARE\\Clients\\Mail"), KEY_READ);
138 if(lResult!=ERROR_SUCCESS)
140 lResult = regKey.Open(HKEY_LOCAL_MACHINE, _T("SOFTWARE\\Clients\\Mail"), KEY_READ);
143 if(lResult==ERROR_SUCCESS)
145 buf_size = 1023;
146 #pragma warning(disable:4996)
147 LONG result = regKey.QueryValue(buf, _T(""), &buf_size);
148 #pragma warning(default:4996)
149 if(result==ERROR_SUCCESS)
151 sMailClientName = buf;
152 return TRUE;
154 regKey.Close();
156 else
158 sMailClientName = "Not Detected";
161 return FALSE;
164 BOOL CMailMsg::MAPIInitialize()
166 // Determine if there is default email program
168 CString sMailClientName;
169 if(!DetectMailClient(sMailClientName))
171 m_sErrorMsg = _T("Error detecting E-mail client");
172 return FALSE;
174 else
176 m_sErrorMsg = _T("Detected E-mail client ") + sMailClientName;
179 // Load MAPI.dll
181 m_hMapi = AtlLoadSystemLibraryUsingFullPath(_T("mapi32.dll"));
182 if (!m_hMapi)
184 m_sErrorMsg = _T("Error loading mapi32.dll");
185 return FALSE;
188 m_lpMapiSendMail = (LPMAPISENDMAIL)::GetProcAddress(m_hMapi, "MAPISendMail");
190 m_bReady = !!m_lpMapiSendMail;
192 if(!m_bReady)
194 m_sErrorMsg = _T("Not found required function entries in mapi32.dll");
197 return m_bReady;
200 void CMailMsg::MAPIFinalize()
202 ::FreeLibrary(m_hMapi);
205 CString CMailMsg::GetEmailClientName()
207 return m_sEmailClientName;
210 BOOL CMailMsg::Send()
212 if(m_lpMapiSendMail==NULL)
213 return FALSE;
215 TStrStrMap::iterator p;
216 int nIndex = 0;
217 MapiRecipDesc* pRecipients = NULL;
218 int nAttachments = 0;
219 MapiFileDesc* pAttachments = NULL;
220 ULONG status = 0;
221 MapiMessage message;
223 if(!m_bReady && !MAPIInitialize())
224 return FALSE;
226 pRecipients = new MapiRecipDesc[1 + m_to.size() + m_cc.size()];
227 if(!pRecipients)
229 m_sErrorMsg = _T("Error allocating memory");
230 return FALSE;
233 nAttachments = (int)m_attachments.size();
234 if (nAttachments)
236 pAttachments = new MapiFileDesc[nAttachments];
237 if(!pAttachments)
239 m_sErrorMsg = _T("Error allocating memory");
240 delete[] pRecipients;
241 return FALSE;
245 // set from
246 pRecipients[0].ulReserved = 0;
247 pRecipients[0].ulRecipClass = MAPI_ORIG;
248 pRecipients[0].lpszAddress = (LPSTR)m_from.c_str();
249 pRecipients[0].lpszName = (LPSTR)m_fromname.c_str();
250 pRecipients[0].ulEIDSize = 0;
251 pRecipients[0].lpEntryID = NULL;
253 // add to recipients
254 for (size_t i = 0; i < m_to.size(); ++i)
256 ++nIndex;
257 pRecipients[nIndex].ulReserved = 0;
258 pRecipients[nIndex].ulRecipClass = MAPI_TO;
259 pRecipients[nIndex].lpszAddress = (LPSTR)m_to.at(i).c_str();
260 pRecipients[nIndex].lpszName = (LPSTR)m_to.at(i).c_str() + 5;
261 pRecipients[nIndex].ulEIDSize = 0;
262 pRecipients[nIndex].lpEntryID = NULL;
265 // add cc receipients
266 for (size_t i = 0; i < m_cc.size(); ++i)
268 ++nIndex;
269 pRecipients[nIndex].ulReserved = 0;
270 pRecipients[nIndex].ulRecipClass = MAPI_CC;
271 pRecipients[nIndex].lpszAddress = (LPSTR)m_cc.at(i).c_str();
272 pRecipients[nIndex].lpszName = (LPSTR)m_cc.at(i).c_str() + 5;
273 pRecipients[nIndex].ulEIDSize = 0;
274 pRecipients[nIndex].lpEntryID = NULL;
277 nIndex=0;
278 // add attachments
279 for (p = m_attachments.begin(), nIndex = 0;
280 p != m_attachments.end(); p++, nIndex++)
282 pAttachments[nIndex].ulReserved = 0;
283 pAttachments[nIndex].flFlags = 0;
284 pAttachments[nIndex].nPosition = 0xFFFFFFFF;
285 pAttachments[nIndex].lpszPathName = (LPSTR)p->first.c_str();
286 pAttachments[nIndex].lpszFileName = (LPSTR)p->second.c_str();
287 pAttachments[nIndex].lpFileType = NULL;
290 message.ulReserved = 0;
291 message.lpszSubject = (LPSTR)m_sSubject.c_str();
292 message.lpszNoteText = (LPSTR)m_sMessage.c_str();
293 message.lpszMessageType = NULL;
294 message.lpszDateReceived = NULL;
295 message.lpszConversationID = NULL;
296 message.flFlags = 0;
297 message.lpOriginator = pRecipients;
298 message.nRecipCount = (ULONG)(m_to.size() + m_cc.size());
299 message.lpRecips = &pRecipients[1];
300 message.nFileCount = nAttachments;
301 message.lpFiles = nAttachments ? pAttachments : NULL;
303 status = m_lpMapiSendMail(NULL, 0, &message, (m_bShowComposeDialog?MAPI_DIALOG:0)|MAPI_LOGON_UI, 0);
305 if(status!=SUCCESS_SUCCESS)
307 m_sErrorMsg.Format(_T("MAPISendMail has failed with code %lu."), status);
310 if (pRecipients)
311 delete [] pRecipients;
313 if (nAttachments)
314 delete [] pAttachments;
316 return (SUCCESS_SUCCESS == status);