您的位置:首页 > 其它

使用 MAPI 实现邮件发送

2008-03-19 17:50 253 查看
一、简述
  实际上,本文的设计,所使用的只是 simple mapi,可以把它看作是mapi(messaging application programming interface)的一个子集。不过大多数时候,simple 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 等均定义在 <mapi.h>
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);

  lhsession、uluiparam和ulreserved这三个参数,简单地设置为0就可以了。
  flflags有三个有效位,分别是 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() 会调用系统默认的邮件客户程序来发送邮件。对于弹出编辑窗的方式,它的行为和另一个函数mapisendmail()差不多,只是可以定制标题、收件人等等,而mapisenddocuments()只是简单地准备一个空白的邮件(包含附件),有关mapisenddocuments()的介绍参见msdn。
  对于自动发送。需要在outlook express的安全设置中,取消“当有其他应用程序试图发送邮件时警告”这个选项。对于outlook,还没有找到方法。

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

五、遗留问题

  我的开发环境是 windows xp sp2 chs,有如下几个问题,希望有高手可以解决。

  1、自动发送时的警告问题。
  2、默认outlook express为系统邮件客户端,可以立即发送,如果是outlook,是先放到outlook的发送队列了,这时如果outlook未运行,就一直不会发送。怎样可以保证无论邮件客户软件是否在运行,我的程序都可以立即将邮件发送出去呢?
  3、对于默认是“hotmail”的情况,只有以 @hotmail.com 结尾的帐号可以正常发送,而 @msn.com 的则不行。同时,在发送时,hotmail会将硬盘上的附件改名(末尾添加“^”符号)并将文件属性改为只读
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: