使用 MAPI 实现邮件发送

原  作:deltacat

创  建:2004.09.16

最后更新:2004.11.01

版权声明:作者保留版权。转载时敬请保持文档及说明的完整性。

关键字: Visual C++ 邮件发送 Simple MAPI

一、问题提出

我们经常需要在自己的应用程序中添加邮件支持,主要是发送邮件。目前,常用的方法有调用外部程序,直接对SMTP协议编程,或者使用 MAPI 接口。MAPI 是微软提供的一套用于邮件收发的接口。打开 MSDN Library,你可以在 Messaging and Collaboration Services 下面找到它。

MAPI 使用比较复杂,于是微软提供了几个比较简单的解决方案,这里包括 CMC(Common Messaging Calls)和 Simple MAPI。

本文主要阐述使用 Simple MAPI 进行开发一个简单的,用于发送一个带附件的邮件的功能实现。文章后面有一小块简单讲述了使用完整 MAPI 的开发,出于某些原因,并不推荐使用,如果需要更复杂的功能,我认为还是老老实实封装SMTP和POP3比较好。

二、Simple MAPI 介绍

Simple MAPI 包括一组很容易使用的函数以及相关的数据结构,可以在C/C++、VB等多种语言中使用。本文是基于VC设计的。

实现一个完整的邮件发送过程,实际上只需要一个函数“MAPISendMail()”,完整函数表及相关介绍参查阅MSDN Library->Platform SDK->Messaging and Collaboration Services。

MAPI 与邮件系统关系密切,要能够使用MAPI的功能,系统必须安装有支持 MAPI 的邮件系统,比如Outlook、Outlook Express、Eudora、Netscape等. 在这里不得不提一下,使用非常广泛的 FoxMail (5.0版本)似乎并不支持 MAPI,不过并没有深入研究,如果有哪位高手发现实际上是支持的,麻烦告知我如何做。

Windows提供了一个文件 MAPI.H,包含所有的相关数据类型的定义。

三、功能的设计

我需要实现如下功能:可定制一封邮件,包括至少一个收件人,可选项目有标题、正文、若干抄送人、密件抄送人、附件。能够根据需要选择自动发送(无用户干预),或弹出邮件编写窗口。

为了便于使用和扩展,我用了一个class来实现。

1、MAPI库的初始化

包括两个步骤:装载MAPI库、得到函数入口地址。

//-------------------------------------------------------------------------------------

m_hLibrary = ::LoadLibrary(_T("MAPI32.DLL"));

if(NULL == m_hLibrary)

{

return ::GetLastError();

}

// LPMAPISENDMAIL 等均定义在

m_lpfnMAPISendMail = (LPMAPISENDMAIL)::GetProcAddress(m_hLibrary, _T("MAPISendMail"));

// 可以根据需要添加其他函数入口。我的做法是用了一个 InitMapi() 函数,一次性将所有函数入口得出,作为类的成员变量保存。随时可以使用

//-------------------------------------------------------------------------------------

2、发送邮件 MAPISendMail()

发送邮件功能就是对MAPISendMail()的封装。下面解释这个API函数的参数定义。

ULONG FAR PASCAL MAPISendMail(LHANDLE lhSession, ULONG ulUIParam, lpMapiMessage lpMessage, FLAGS flFlags, ULONG ulReserved);

ulUIParam 可以为 0,如果设置了 MAPI_DIALOG 标志,则最好传给它父窗口句柄。

lhSession和ulReserved这两个参数,简单地设置为0就可以了。

flFlags有三个有效位,分别是 MAPI_DIALOG,MAPI_LOGON_UI,MAPI_NEW_SESSION。如果希望程序弹出一个标准的邮件撰写对话框,请设置 MAPI_DIALOG,建议不要设置 MAPI_LOGON_UI 和 MAPI_NEW_SESSION。

重点是 lpMessage 这个参数,它指向一个MapiMessage类型的结构,详细地定义了一个邮件的全部信息。

3、结构 MapiMessage

使用时首先定义一个MapiMessage类型的变量,将其清零。现在我们只要简单地设定lpszSubject(标题)、lpszNoteText(正文)、lpOriginator(发件人)、nRecipCount(收件人计数,包含TO、CC、GCC),lpRecips(一个包含全部收件人的数组),nFileCount(附件计数)、lpFiles(包含每个附件信息的数组)。

nRecipCount 和 nFileCount 的值一定要与实际的收件人和附件数目相符。

4、结构 MapiRecipDesc

必须设置 ulRecipClass、lpszName、lpszAddress

5、结构 MapiFileDesc

必须设置的有 lpszPathName、nPosiotion 两个参数

这里有个地方需要特别注意。我在实际编码过程中,有几次 Outlook 不能正确弹出窗口(自动发送也不行),但是同样的过程,将邮件客户设为 OutlookExpress 就没有问题。十分头痛。经过反复检查,发现 nPosiotion 这个参数十分重要。它指示附件在邮件中的位置。

对于一些邮件客户端,比如OutlookExpress,也许忽略了这个参数,由客户端自动安排。所以没有问题。对于另一些客户端,比如Outlook,总是按照这个值的指示来安排的。如果附件数多于一个,这个值如果相同,那么就会造成错误。但是自行计算挺麻烦而且没什么意义。解决的方法是,将其设为 -1,指示客户软件自行安排。:)

四、如何工作?

MAPISendMail() 会调用系统默认的邮件客户程序来发送邮件。对于弹出编辑窗的方式,它的行为和另一个函数  MAPISendDocuments() 差不多,但是可以定制标题、收件人等等。而 MAPISendDocuments() 只是简单地准备一个空白的邮件(包含附件),有关 MAPISendDocuments() 的介绍参见 MSDN。

对于自动发送。需要在 Outlook Express 的安全设置中,取消“当有其他应用程序试图发送邮件时警告”这个选项。对于 Outlook,似乎使用 Simple MAPI 还没有禁止安全警告的方法。

我设计的类包括三个接口函数,Send(), AddFiles(), AddRecips(),其中只有 Send() 是必须的。使用时声明一个对象,然后就直接调用 Send() 函数发送邮件。两个 Add 函数只要根据需要在 Send() 之前调用即可。

五、遗留问题

我的开发环境是 Windows Xp Sp2 CHS,有如下几个问题,希望有高手可以解决。

1、自动发送时的警告问题。使用 Simple MAPI 能否解决?

2、默认Outlook Express为系统邮件客户端,可以立即发送,如果是Outlook,是先放到Outlook的发送队列了,这时如果Outlook未运行,就一直不会发送。怎样可以保证无论邮件客户软件是否在运行,我的程序都可以立即将邮件发送出去呢?

3、对于默认是“Hotmail”的情况,只有以 @hotmail.com 结尾的帐号可以正常发送,而 @msn.com 的则不行。同时,在发送时,hotmail会将硬盘上的附件改名(末尾添加“^”符号)并将文件属性改为只读,不过如果它正常上传了附件,会将文件复原。

六、使用 MAPI

之所以使用 MAPI,起初是为了取得系统的地址本以及结局上面第五节的问题2。

MAPI 相对于 Simple MAPI 要复杂的多。具体的使用方法可以参考 MSDN 文档“Handling an Outgoing Message”、“Handling the Address Book”以及“Sending or Receiving a Message on Demand”。这里只对几个关键的问题加以说明。

1、仅 Microsoft Outloook 比较好地支持了 MAPI,包括 Microsoft Outlook Express 均不支持 MAPI 调用。

2、MAPI 看似复杂,实际上,他的几乎所有数据存储和访问,都是一个关键的接口:IMAPITable。也就是说,所有的数据存储都是类似表的结构。搞清楚了这个,再编码就很顺了,不管是发送接收邮件还是操作地址本,存取数据流程都是搞表格。:P

3、上面的问题2仍然不能解决。根据“Sending or Receiving a Message on Demand”的说明,关键的是 FlushQueues() 函数,但是我尝试了各种方法,均无法使它生效。若干天对自己的痛苦反思之后,终于怀疑微软有问题。于是我在网上翻出了一篇问答,中间有这么一段话:

“The IMAPIStatus::FlushQueues method appears not to work at all any more. Call it and you'll get a successful return code but nothing happens as a result. ” --Pete Maclean.

于是我彻底放弃。:(

七、结束语

本文是在给应用程序中添加邮件发送功能的心得。过程中遇到了很多问题,将他写出来,主要是给自己一个记录,也是我第一次将自己的编程过程整理成文档。

若本文还能帮到有同样需要的朋友,会令我很开心。也希望有这方面经验的朋友可以解决我的遗留问题。

欢迎发送邮件至 catking@163.com 共同探讨编程中的各种问题,分享乐趣。

mapi java_使用 MAPI 实现邮件发送相关推荐

  1. Powershell 邮件发送

    目录 目录 前言 Send-MailMessage NETMail 使用OutLook发送邮件 前言 最近领导想在winServer2012上搞个自动发送邮件的计划任务,下面有几种发送邮件的方式. 如 ...

  2. exchange无法收发邮件_MAPI session超过Exchange最大限制,邮件发送失败的终极解决方法...

    前言:1.当今世界,Email已经成为一种通用的办公方式,并且是沟通地球村的一座重要桥梁.在使用Email,特别是Outlook收发邮件时,我们经常会碰到邮件发送失败的问题.在这种情况下,我们一般首先 ...

  3. ESMTP邮件发送程序

    用汇编语言写ESMTP邮件发送程序 下载本节例子程序和源代码 (9.67 KB) 最近在CSDN论坛上看到许多人问着同一个问题--如何编写带服务器验证的 ESMTP 邮件发送程序,回答的人还真不少:有 ...

  4. 邮件发送类,支持HTML格式,支持优先级设置

    www.chinacs.net  2002-5-9  中文C#技术站 邮件发送类,支持HTML格式,支持优先级设置.通过SOCKET类实现的 using System; using System.Te ...

  5. 使用Spring实现邮件发送

    2019独角兽企业重金招聘Python工程师标准>>> 这两天写个小程序需要使用邮件发送的功能,在网上搜索了一帮子文章,感觉还是使用Spring的邮件发送功能比较方便,哈哈,懒人就这 ...

  6. python邮件发送哪个好_最全总结!聊聊 Python 发送邮件的几种方式

    1. 前言 邮件,作为最正式规范的沟通方式,在日常办公过程中经常被用到 我们都知道 Python内置了对 SMTP 的支持,可以发送纯文本.富文本.HTML 等格式的邮件 本文将聊聊利用 Python ...

  7. CentOS搭建msmtp+mutt实现邮件发送

    1:搭建配置msmtp 下载msmtp包: 官方地址:http://msmtp.sourceforge.net/download.html 编译,安装(官方下载的包为tar.xz格式): #xz -d ...

  8. 利用phpmailer类邮件发送

    <?phprequire("class.phpmailer.php"); //下载的文件必须放在该文件所在目录$mail = new PHPMailer(); //建立邮件发 ...

  9. python 数据库查询结果邮件提醒_Python实现的查询mysql数据库并通过邮件发送信息功能...

    本文实例讲述了Python实现的查询mysql数据库并通过邮件发送信息功能.分享给大家供大家参考,具体如下: 这里使用Python查询mysql数据库,并通过邮件发送宕机信息. Python代码如下: ...

最新文章

  1. Go语言之并发示例-Pool(二)
  2. 第六届全国大学生智能汽车竞赛获奖名单
  3. throws和throw抛出异常的使用规则
  4. suparc服务器没信号,[SupARC平台常见问题帮助](2012-09-19更新)
  5. Java获取各种常用时间方法
  6. 论理想中的技术团队——领导力
  7. [UWP]用画中画模式(CompactOverlay Mode)让用总在最前端显示
  8. Window中的Docker 拉取Mysql镜像 并在本地Navicate链接
  9. java 交集怎么写_Java里面如何求两个集合的交集
  10. 1000道Python题库系列分享20(43道填空与判断题)
  11. ELK收集docker日志
  12. \r,\n,\r\n的问题分析
  13. Linux下安装Java环境
  14. 万字精选长文,深入解读房地产土地投资测算路径(附下载)
  15. 如何根据地理位置获取城市编码 / (高德地图) 获取城市编码API / 经纬度获取城市or城市编码
  16. 关于永洪BI Kerberos机制的详细介绍
  17. FRP内网穿透访问家中的NAS和路由器后台
  18. 郑码输入法 字根记忆表 一般根变通处理
  19. 前端视觉测试工具:Applitools Eyes
  20. Sen2Cor对哨兵2号L1C数据的预处理

热门文章

  1. 基于单片机的超市储物柜设计_一种基于at89c51单片机的超市寄存装置的制造方法...
  2. 建行找不到服务器或DNS错误,企业网上银行常见问题解答
  3. Coffee and Coursework
  4. 10 款优雅的 Go 语言开发工具
  5. FastReport批量打印
  6. APAD 7'“谷歌Android操作系统1.5无线触摸屏
  7. CSS的两种盒子模型
  8. 嵌入式linux 无线网卡,一种基于嵌入式Linux的无线网卡的制作方法
  9. 【每日一读】High-order Proximity Preserving Information Network Hashing
  10. 原创有关年华,无关风月