使用MAPI的MAPISendMail发送邮件碰到的巨大的坑
最近,使用MAPI32.DLL提供的MAPISendMail发送邮件,在Foxmail可以成功,在Outlook始终不成功,怎么看、反复尝试都没试出代码问题。这时一个细节吸引了我的注意,把程序填充的地址删掉,手动填上去尽然可以发送成功,这样我就怀疑我给MapiRecipDesc填充收件人地址是否有什么问题,检查了代码,很正常呀,XXX@xxx.com,这怎么不行呢?再去MSDN查了一下,https://msdn.microsoft.com/en-us/library/windows/desktop/dd296720(v=vs.85).aspx。原来需要加上SMTP:,比如刚才的正确地址是SMTP:XXX@xxx.com。MSDN原文解释如下:
MapiRecipDesc structure
lpszAddress
Optional pointer to the recipient or sender's address; this address is provider-specific message delivery data. Generally, the messaging system provides such addresses for inbound messages. For outbound messages, the lpszAddress member can point to an address entered by the user for a recipient not in an address book (that is, a custom recipient).
The format of the address is address type:email address. Examples of valid addresses are FAX:206-555-1212 and SMTP:M@X.COM.
fuck!太坑了。
附MAPI发送邮件代码:
#include <MAPI.h>
#include <atlstr.h>
#include <shellapi.h>#define UTILITY_DLL_DECLARRE DECLARE_EXPORT
#define OPERATE_OK 0
#define OPERATE_FAIL -1
#define OPERATE_INPUT_PARAM_ERROR -2/************************************
* @method: startProcess
* @brief: 启动进程
* @param: const chConstStringA& strAppPath 可执行程序全路径
* @param: const chConstStringA& strParams 参数
* @param: DWORD& exitCode 应用返回码
* @param: DWORD dwCreationFlag
* @param: bool bWaitProcessFinished 是否等待进程结束
* @return: extern int
* @retval: 没有找到则返回UC_ERROR_ID
*/
UTILITY_DLL_DECLARRE bool startProcess(const chConstStringA& strAppPath, const chConstStringA& strParams, DWORD& exitCode, DWORD dwCreationFlag = 0, bool bWaitProcessFinished = false);#define SEND_MAIL_LOAD_LIB_FAIL -3
#define SEND_MAIL_MEMORY_FAIL -4
#define SEND_MAIL_LOAD_FUNC_FAIL -5
#define SEND_MAIL_LOGON_FAIL -6//邮箱附件
struct MailAttachment
{chStringA sFileName; ///< 文件名chStringA sFileFullPath; ///< 文件全路径
};//邮件接收者类型
enum MailReciptType
{MAIL_TO = 1, ///< 收件人MAIL_CC ///< 抄送者 (copy recipt)
};//邮件接收者信息
struct MailRecipInfo
{chStringA sName; ///< 接收者名字 chStringA sAddress; ///< 接收者邮箱地址MailReciptType eType; ///< 接收者类型
};//邮件信息
struct MailInfo
{chStringA sSubject; ///< 主题chStringA sNoteText; ///< 正文chStringA sSenderAddr; ///< 发送者邮箱地址 (lpOriginator)chObjList<MailRecipInfo> lstRecips; ///< 接收者(含收件人和抄送者)chObjList<MailAttachment> lstAttachs; ///< 附件
};/************************************
* @method: sendMail
* @brief: 发送邮件
* @param: const MailInfo& mailInfo 邮件信息
* @return: int
* @retval: 操作结果 0--成功;其余值失败
*/
UTILITY_DLL_DECLARRE int sendMail(const MailInfo& mailInfo);bool startProcess(const chConstStringA& strAppPath, const chConstStringA& strParams, DWORD& exitCode, DWORD dwCreationFlag /* = 0*/, bool bWaitProcessFinished /*= false*/)
{STARTUPINFOW si;PROCESS_INFORMATION pi;bool bRet = false;ZeroMemory(&si, sizeof(si));si.cb = sizeof(si);ZeroMemory(&pi, sizeof(pi));chStringA strCmd;strCmd.Format("\"%s\" %s", strAppPath.c_str(), strParams.c_str());chStringW strCmdW = chUTF82W(strCmd);if (CreateProcessW(NULL, strCmdW.data(), NULL, NULL, FALSE, dwCreationFlag, NULL, NULL, &si, &pi) == TRUE){bRet = true;if (bWaitProcessFinished){HANDLE hProcess;CloseHandle(pi.hThread);hProcess = pi.hProcess;//等待进程返回;if (hProcess != 0){exitCode = 0;WaitForSingleObject(hProcess, INFINITE);if (!GetExitCodeProcess(hProcess, &exitCode)){exitCode = 1;}CloseHandle(hProcess);}}}else{chWARNINGx(false, "Fail create process [%s]", strAppPath.c_str());}return bRet;
}int sendMail(const MailInfo& mailInfo)
{int iRet = OPERATE_OK;if (!mailInfo.lstRecips.size()){return OPERATE_INPUT_PARAM_ERROR;}//装入MAPI32.DLL动态库HMODULE hMod = LoadLibrary("MAPI32.DLL");if (hMod == NULL){chWARNINGx(false, "LoadLibrary MAPI32.DLL fail");return SEND_MAIL_LOAD_LIB_FAIL;}//获取邮件相关的函数地址LPMAPILOGON lpMapiLogon = (LPMAPILOGON)::GetProcAddress(hMod, "MAPILogon");LPMAPISENDMAIL lpMapiSendMail = (LPMAPISENDMAIL)::GetProcAddress(hMod, "MAPISendMail");LPMAPILOGOFF lpMapiLogoff = (LPMAPILOGOFF)::GetProcAddress(hMod, "MAPILogoff");if (NULL == lpMapiLogon || NULL == lpMapiSendMail || NULL == lpMapiLogoff){chWARNINGx(false, "Fail get mail proc addr ");FreeLibrary(hMod);return SEND_MAIL_LOAD_FUNC_FAIL;}LHANDLE hMapiSession = 0;ULONG status = 0; status = lpMapiLogon(NULL, NULL, NULL, MAPI_LOGON_UI | MAPI_PASSWORD_UI, NULL, &hMapiSession);if (status != SUCCESS_SUCCESS){chWARNINGx(false, "Fail MAPILogon code:%X", status);FreeLibrary(hMod);return SEND_MAIL_LOGON_FAIL;}//分配内存保存附件信息MapiFileDesc* pAttachments = NULL;int nAttachments = mailInfo.lstAttachs.size();if (nAttachments > 0){pAttachments = new MapiFileDesc[nAttachments];if (!pAttachments){chWARNINGx(false, "Error allocating memory for pAttachments");FreeLibrary(hMod);return SEND_MAIL_MEMORY_FAIL;}}//添加附件int nIndex = 0;int nValidAttachments = 0;for (const chObjList<MailAttachment>::iterator it = mailInfo.lstAttachs.begin();it != mailInfo.lstAttachs.end() && it.hasData(); ++it, nIndex++){const MailAttachment& attach = *it;if (attach.sFileFullPath.empty()){chWARNINGx(false, "Empty attachment full path,skip");continue;}pAttachments[nIndex].ulReserved = 0;pAttachments[nIndex].flFlags = 0;pAttachments[nIndex].nPosition = 0xFFFFFFFF;pAttachments[nIndex].lpszPathName = (LPSTR)attach.sFileFullPath.c_ptr();pAttachments[nIndex].lpszFileName = (LPSTR)(attach.sFileName.empty() ? attach.sFileFullPath.c_ptr() : attach.sFileName.c_ptr());pAttachments[nIndex].lpFileType = NULL;nValidAttachments++;}//邮件发送者MapiRecipDesc* pSender = NULL;if (!mailInfo.sSenderAddr.empty()){pSender = new MapiRecipDesc;if (!pSender){chWARNINGx(false, "Error allocating memory for pSender");FreeLibrary(hMod);if (pAttachments){delete[] pAttachments;pAttachments = NULL;}return SEND_MAIL_MEMORY_FAIL;}pSender->ulReserved = 0;pSender->ulRecipClass = MAPI_ORIG;pSender->lpszAddress = (LPSTR)mailInfo.sSenderAddr.c_ptr();pSender->lpszName = (LPSTR)mailInfo.sSenderAddr.c_ptr();pSender->ulEIDSize = 0;pSender->lpEntryID = NULL;}//邮件接收者int nRecips = mailInfo.lstRecips.size();MapiRecipDesc* pRecipients = new MapiRecipDesc[nRecips];if (!pRecipients){chWARNINGx(false, "Error allocating memory for pRecipients");FreeLibrary(hMod);if (NULL == pAttachments){delete[] pAttachments;pAttachments = NULL;}if (NULL == pSender){delete pSender;pSender = NULL;}return SEND_MAIL_MEMORY_FAIL;}// 设置收件人int nValidRecips = 0;size_t i = 0;for (const chObjList<MailRecipInfo>::iterator recipIt = mailInfo.lstRecips.begin(); recipIt != mailInfo.lstRecips.end() && recipIt.hasData(); ++recipIt, i++){const MailRecipInfo& recipInfo = *recipIt;if (recipInfo.sAddress.empty()){chWARNINGx(false, "Empty recip address,skip");continue;}pRecipients[i].ulReserved = 0;pRecipients[i].ulRecipClass = (recipInfo.eType == MAIL_TO) ? MAPI_TO : MAPI_CC;pRecipients[i].lpszAddress = (LPSTR)recipInfo.sAddress.c_str();pRecipients[i].lpszName = (LPSTR)(recipInfo.sName.empty() ? recipInfo.sAddress.c_str() : recipInfo.sName.c_str());pRecipients[i].ulEIDSize = 0;pRecipients[i].lpEntryID = NULL;nValidRecips++;}//邮件结构信息MapiMessage message;memset(&message, 0, sizeof(message));message.lpszSubject = (LPSTR)mailInfo.sSubject.c_ptr(); //主题message.lpszNoteText = (LPSTR)mailInfo.sNoteText.c_ptr(); //正文内容if (NULL != pSender){message.lpOriginator = pSender; //发送者}message.nFileCount = nValidAttachments; //附件个数message.lpFiles = nValidAttachments ? pAttachments : NULL; //附件信息message.nRecipCount = nValidRecips; //接收者个数message.lpRecips = nValidRecips ? pRecipients : NULL; //接收者信息//发送邮件int nError = lpMapiSendMail(hMapiSession, 0, &message, MAPI_DIALOG, 0);if (nError != SUCCESS_SUCCESS){//错误提示信息WARNING_TRACE("SendMail failed:%d", nError);iRet = OPERATE_FAIL;}lpMapiLogoff(hMapiSession, NULL, 0, 0);//释放分配的内存if (pAttachments){delete[] pAttachments;pAttachments = NULL;}if (pSender){delete pSender;pSender = NULL;}if (pRecipients){delete[] pRecipients;pRecipients = NULL;}FreeLibrary(hMod);return iRet;
}
使用MAPI的MAPISendMail发送邮件碰到的巨大的坑相关推荐
- firefox 中碰到的一个小坑
情况描述: 在一个处于正常文档流的div中,里面有一部分文字,还有个有浮动的块, 上代码 HTML: <div class="container"> this i ...
- UiPath模拟浏览器登录qq邮箱并发送邮件方法与遇到的坑
首先简述要用到的组件和流程. 流程: 1.浏览器打开qq邮箱地址https://mail.qq.com 2.在输入框输入账号密码 3.点击登录 4.点击写信 5.输入标题 内容 收件人 点击发送 用到 ...
- php面试题遇到的坑,PHP面试题碰到的几个坑。面壁ing
PHP面试题遇到的几个坑....面壁ing 1.指针悬挂问题 $array = [1, 2, 3]; echo implode(',', $array), "\n"; foreac ...
- mapi java_使用 MAPI 实现邮件发送
使用 MAPI 实现邮件发送 原 作:deltacat 创 建:2004.09.16 最后更新:2004.11.01 版权声明:作者保留版权.转载时敬请保持文档及说明的完整性. 关键字: Visual ...
- 利用MAPI实现电子邮件功能
利用MAPI实现电子邮件功能 在VB.VC中进行面向Internet的开发应用,是近期许多程序员关注的热点. 随着办公自动化应用软件水平的提高和Intranet的流行,越来越多的办公自动化系统中都采用 ...
- linux下使用mail定时发送邮件-阿里企业邮箱发送
一 背景介绍 文章需求: 编写脚本从数仓里提取数据,并将数据表格通过阿里企业邮箱发送给指定人员,这里主要讲下,使用mail命令发送邮件时遇到的一些坑. 个人公众号:放纵的Coder 有疑问请联系我 二 ...
- [AX2012]发送广播邮件
AX 2012可以使用MAPI或者SMTP发送邮件,MAPI是客户端方法,需要outlook的协作,而SMTP则是服务器端方法,要求SMTP允许AOS服务器通过它中继.这里要讲的就是如何通过SMTP发 ...
- STM32单片机真的落后?
一般这样认为的,只能说对单片机这个行业一无所知. 我用STM32做过的产品超过13款,占据了大部分. 我从两个方面来分析下现在STM32到底落不落后,太学术化的东西我不讲,保证小白都能听懂! 1.市场 ...
- 老大吩咐的可重入分布式锁,终于完美的实现了~
重做永远比改造简单 最近在做一个项目,将一个其他公司的实现系统(下文称作旧系统),完整的整合到自己公司的系统(下文称作新系统)中,这其中需要将对方实现的功能完整在自己系统也实现一遍. 旧系统还有一批存 ...
最新文章
- Selenium的简单操作
- SQL Server 中关于 @@error 的一个小误区
- HTML语言怎么晋升,学会提问,对你的职场晋升有很大的帮助
- 026-微软Ajax异步组件
- java课后习题_【整理】java私塾教程课后习题
- 小白入坑 Web 渗透测试必备指南
- IIS6.0不支持ASP的解决办法
- JavaScript提高:006:ASP.NET使用easyUI TABS标签updatepanel
- Linux编程中 #define _XOPEN_SOURCE的作用
- C++11常用特性的使用经验总结-概述及目录
- fluentmigrator连接mysql_如何利用FluentMigrator实现数据库迁移
- 车金融|合同中心系统的前世今生
- “白嫖”时代进入最后倒计时,网盘行业到底是怎么由盛及衰的?
- hdu11601087
- 一键root+android+5.0,360一键rootv5.0.0最新版
- python爬取东方财富网资金流向数据(在本地生成csv文件)
- \t\t健康生活:20个健康小细节隐藏大危害!
- 国产内存真的来了:紫光可提供DDR3、DDR4内存芯片
- Android RxJava应用:优雅实现网络请求轮询(无条件)
- Python 一键获取全国市县级行政单元Shapefile文件