当你需要在VC程序中提供邮件支持功能的时候,你有许多种选择:

  1)根据SMTP,POP3,MIME等协议从零开始实现。这要求熟悉RFC 821,RFC 822,RFC 1123, RFC 1652, RFC 1939, RFC2045-2049等一系列协议, 您可以实现一切可能实现的功能,但同时需要花大量的时间。

  2)利用一些免费的封装类,比如CSMTP,CPOP3。虽然可以达到快速实现的目的,但功能非常有限。

  3)利用MAPI调用支持MAPI的邮件发送程序( 例如:Outlook )发送邮件,这种实现方式需要客户端安装指定的邮件发送程序,不够灵活

  4)利用现成的组件例如:w3 JMail组件来构建您的系统,JMail组件功能强大,可以轻松完成邮件发送、接收、加密、集群传输等工作。

  虽然JMail用得最多的是ASP下的应用,但它在其它语言中都能够很好地工作,本文将针对w3 JMail 4.3在VC中的使用展开讨论。

  一、准备篇

  1.1 组件的安装

  因为JMail4.3与以前的版本相比接口有了变动,所以推荐您使用4.3版本,您可以到以下网址下载JMail 4.3

  DIMAC公司 http://www.dimac.net/

  VC知识库 http://www.vckbase.com/tools

  1.2 快速邮件发送程序MINI版

  我们从这个小例子大致了解一下JMail组件的工作过程

双击代码全选
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#import "jmail.dll"     // 导入jmail.dll, 假如jmail.dll不在工程目录下,您需要写上完整路径
void main()
{
  CoInitialize(NULL);   // COM的初始化
  {
    // 创建SpeedMailer实例
    jmail::ISpeedMailerPtr pSpeedMailer("JMail.SpeedMailer");  
    
    // 发送邮件
    pSpeedMailer->SendMail("yourmail@163.com",    // 发件人邮箱
          "webmaster@163.com",    // 收件人邮箱
          "主题:你好!",        // 主题
          "正文:大家好才是真的好!",  // 正文
          "smtp.163.com");      // SMTP服务器
  }
  CoUninitialize();
}

看了上述代码您肯定会说真的很容易,这个例子是利用了ISpeedMailer接口来发送简单的邮件,我想大家一看就清楚。

  为了使这个流程看起来不至于令人生畏,我把异常捕捉省略了,在实际使用中应该加入异常捕捉,具体方法请见下文。

  1.3 异常捕捉

  这里的异常捕捉与我们所使用的捕获COM异常没有两样,在这里稍加描述只是提高本文的完整性,请看如下代码:

双击代码全选
1
2
3
4
5
6
7
8
9
10
11
12
try
{
  ...
  ... 发送代码
  ...
}
catch( _com_error & e)
{
  cerr << "错误号: 0x" << hex << e.Error() << endl;
  cerr << "错误信息: " << e.ErrorMessage() << endl;
  cerr << "错误描述: " << e.Description() << endl;
}

  二、邮件发送篇

下图是本文附带的邮件发送程序运行效果图:

  2.1 利用IMessage接口发送带附件的邮件

  在前面我们用ISpeedMailer接口来发送邮件,但功能有限,IMessage接口为我们提供了功能完备的发送功能,请看下面的例子:

双击代码全选
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
jmail::IMessagePtr pMessage("JMail.Message");
// 发件人邮箱
pMessage->From = "mymail@mydomain.com";
// 发件人姓名
pMessage->FromName = "我的名字";
// 添加收件人1, 无收件人姓名与PGP KEY
pMessage->AddRecipient("yourmail1@yourdomain.com","","");
// 添加收件人2, 无PGP KEY
pMessage->AddRecipient("yourmail2@yourdomain.com","收件人名字","");
// 添加收件人3,这里的PGP KEY只是作为示例,实际中需要用PGP软件生成
pMessage->AddRecipient("yourmail3@yourdomain.com","收件人名字","R9Rb7decrQWINuce3uFc0xDG");
// 优先级设置,1-5逐次降低, 3为中级
pMessage->Priority = 3;
// 编码方式设置, 默认是iso-8859-1
pMessage->Charset = "GB2312";
// 主题
pMessage->Subject = "邮件主题";
// 正文
pMessage->Body = "邮件正文rn";
// 如有必要,可以再添加一些正文
pMessage->AppendText("VC知识库www.VCKBASE.com欢迎您! 祝您身体健康!");
// 添加附件
pMessage->AddAttachment("C:\CONFIG.SYS", VARIANT_FALSE, "application/octet-stream");
pMessage->AddAttachment("C:\test.gif", VARIANT_TRUE, "image/gif");
// 开始发送
pMessage->Send("mailserver.com", VARIANT_FALSE);

2.2 发送HTML格式的邮件

 在这里我们需要完成的功能是发送一封带图像的HTML邮件,图像存储在本地邮件附件里,而不是通过远地链接,实现的关键是如何引用

  附件中的图像:

  在调用AddAttachment时它会返回一个称为content id的字串,比如它返回的是"AABBCCDD",则我们用<IMG SRC="cid:AABBCCDD">这种方式

  来引用该图像,请看如下代码片断:

双击代码全选
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
......
// 这里添加Body是为了使邮件浏览者在没有切换到HTML时给予提醒
pMessage->Body = "邮件采用HTML格式,请切换到HTML模式。rn";
// 添加附件
_bstr_t bstrCID = pMessage->AddAttachment("D:\logo.gif", VARIANT_TRUE, "image/gif"); // 返回content id
// 根据content id 生成IMG HTML标记
char pImgHTML[200];
strcpy(pImgHTML, "<IMG SRC=''cid:");
strcat(pImgHTML, (char*)bstrCID);
strcat(pImgHTML, "''>");
// 添加HTML正文内容
pMessage->HTMLBody = "<H2>VC知识库</H2>";
pMessage->AppendHTML("<BR>www.VCKBASE.com ");
pMessage->AppendHTML(pImgHTML);
// 开始发送
pMessage->Send("", VARIANT_FALSE);

关于content id更详细的内容请阅读MIME协议

  2.3 特殊邮件头的构造

  To,From,Subject,Message-ID,Date,Received等是标准的邮件头,自定义邮件头会自动在前面加X, 例如X-Originating-IP

双击代码全选
1
2
3
4
5
6
7
// 标准邮件头
pMessage->AddNativeHeader("Message-ID", "VCKBASE:ABCDEFG1234567");
pMessage->AddNativeHeader("Date", "1800-1-1");
// 自定义邮件头
pMessage->AddHeader("Originating-IP", "123.345.567.789");   // 给它个假冒伪劣IP
pMessage->AddHeader("Mailer", "MyMailBox 1.0");       // 邮件发送器名称
pMessage->AddHeader("Company", "MyCompany");      // 随便加点定制信息

有时收到邮件的时候会提示:发件人请求一个收条以表示你已经阅读过这封邮件,您愿意发送一个收条吗?

  发送这样的信,我们只需要:

双击代码全选
1
pMessage->AddNativeHeader("Disposition-Notification-To", "sender@domain.com");

sender@domain.com是回复收条的邮箱。

  2.4 邮件服务器需要发信认证的处理

  一些SMTP服务器需要认证信息,您需要在Send时提供用户名与密码,例如:

  

双击代码全选
1
pMessage->Send("username:password@mailserver.com")

  2.5 不通过SMTP中继服务器发送邮件

  在发信时我们一般把信件提交给SMTP中继服务器,SMTP中继服务器负责和目标邮局联系,并最终将信件提交到收件人所在的邮件服务器。

  在没有可利用的SMTP中继服务器时,我们可以将服务器名设置为空,例如:

双击代码全选
1
pMessage->Send("", VARIANT_FALSE);

这样,组件会通过DNS查询目标域(例如:163.com)中的MX记录,直接将信件提交到MX记录中所指定的邮件服务器中。

  2.6 经代理网关发送邮件

  上文所说的SMTP中继服务器上的邮件传输代理程序(MTA),与WINGATE,CPROXY等代理软件提供的SMTP代理工作原理是一样的,

  所以具体的发送过程也一样,例如:

  代理网关地址 192.16.10.11, 要往yourmail@yourdomain.com发信,代码如下:

双击代码全选
1
2
3
......
pMessage->AddRecipient("yourmail@yourdomain.com","","");
pMessage->Send("192.16.10.11", VARIANT_FALSE);

2.7 关于邮件的加密传输与集群发送

  JMail的免费版本并没有提供加密传输与集群发送功能,要想使用这些功能,您需要安装无限制的JMail标准版或专业版。

  对于加密传输,您还需要安装PGP软件,例如:PGPFreeware

  集群发送功能在拥有成千上万个客户时是非常有用的,定制好模板后,数据库中的记录自动填入模板生成信件发送。

  由于笔者只有免费版本的JMail,所以这一功能未能尝试。

  虽然免费版未提供集群发送功能,但我们可以只使用IMessage接口结合数据库来实现集群发送功能.

  2.8 邮件发送时的常见错误

  当所设置的SMTP服务器不存在,错误信息:

  The message was undeliverable. All servers failed to receive the message

  如果没有设置SMTP服务器时,试图发送一封错误邮件地址的信,

  例如:webmaster@sohusohu.com 将返回如下错误信息:

  WSAGetLastError() returned 11001, Host not found

  许多SMTP服务器不支持转发,或支持转发但不转发MAIL FROM不是本地帐号的信,错误信息:

  The message was undeliverable. All servers failed to receive the message

  许多SMTP服务器不接收外部的邮件,例如smtp.sohu.com,所以想要向SOHU发信你可以不设邮件服务器, 而是通过

  DNS查询邮件交换服务器,或者直接将邮件服务器设置为sohumx.sohu.com。

  像SOHU信箱会对一些发件人信箱进行过滤,例如您将发件人信箱设为test@163.com,或者发件人信箱与收件人信箱一致,

  发信时将返回:554<test@163.com>:Sender address rejected:Access denied

  (未完待续...)



 上文《利用JMail组件快速构建邮件程序(上)》中介绍了邮件的发送,本文将介绍邮件的接收过程,示例代码运行效果图如下:

  三、邮件接收篇

  3.1 利用IPOP3接收邮件

  接收邮件时用到的接口是IPOP3, 首先连接上邮件服务器,从Messages中得到邮件信息集合,然后就可以通过遍历集合取得每条Message中的具体内容。

  请看如下代码:

双击代码全选
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
jmail::IPOP3Ptr pPOP3("JMail.POP3");
// 非必须,设置超时时间为60秒,默认为120秒
pPOP3->Timeout = 60;
// 连接邮件服务器
pPOP3->Connect("webmaster",    // 用户帐号
    "password",    // 密码
    "pop3.163.com",    // POP3服务器
    110);      // POP3端口
jmail::IMessagesPtr pMessages;
jmail::IMessagePtr pMessage;
pMessages = pPOP3->Messages;    // 取得集合
// 已下载的邮件的实际个数(因为第0个ITEM是未用的,所以-1)
long lCount = pMessages->Count - 1;
// 遍历每封信
for(long i = 1; i <= lCount; i++)
{
  pMessage = pMessages->Item[i];
      
  _bstr_t bstrSubject = pMessage->Subject;
  _bstr_t bstrFrom = pMessage->From;
  _bstr_t bstrBody = pMessage->Body;
  printf("(%d)Subject:%s, From:%s, Body:%srn",
    i,
    (const char*)bstrSubject,
    (const char*)bstrFrom,
    (const char*)bstrBody);
  pMessage.Release();
}
pMessages->Clear();  // 这里的Clear并不是清除邮件服务器上的邮件
pMessages.Release();
// 断开连接
pPOP3->Disconnect();

  3.2、实现类似Foxmail的远程管理功能

  Foxmail的远程管理功能非常好用,特别是面对垃圾邮件成灾的时候,如果直接收取全部邮件内容无疑会浪费宝贵的时间,所以只要读取邮件头的信息我们就可以进行取舍,我们可以利用JMail提供的DownloadHeaders方法来实现这样的功能,请参考如下代码:

双击代码全选
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
......
pPOP3->Connect("webmaster","password","pop3.163.com",110);
// 只下载邮件头信息
pPOP3->DownloadHeaders();
pMessages = pPOP3->Messages;
long lCount = pMessages->Count - 1;
// 遍历每个邮件头,遇到不愿意收的立刻删除
for(long i = 1; i <= lCount; i++)
{
  pMessage = pMessages->Item[i];
      
  _bstr_t bstrSubject = pMessage->Subject;
  _bstr_t bstrFrom = pMessage->From;
  // 因为中文主题可能被编码, 所以不能直接判断,在这里只是演示删除的功能
  if(strstr((const char*)bstrSubject, "成人") != NULL)
    pPOP3->DeleteSingleMessage(i);    // 删除被认为非法的信息
  else
    printf("(%d)Subject:%s, From:%srn",
      i,
      (const char*)bstrSubject,
      (const char*)bstrFrom);
  pMessage.Release();
}
......

  3.3、邮件头详细信息的读取

  通过IMessage::Headers得到邮件头对象,然后用IHeaders::GetText()得到全部头部信息,或者用IHeaders::GetHeader()得到指定的头部信息,例如:

双击代码全选
1
2
3
4
5
6
7
jmail::IHeadersPtr pHeaders;
pHeaders = pMessage->Headers;
_bstr_t bstrHeaderText = pHeaders->GetText(); // 得到全部头部信息
printf("%srn", (const char*)bstrHeaderText);
_bstr_t bstrContentType = pHeaders->GetHeader("Content-Type"); // 得到数据类型
printf("%srn", (const char*)bstrContentType);
pHeaders.Release();

  3.4、通过代理接收邮件

  通过POP3代理收邮件,程序代码不需要变动,只需将邮件服务器设置为代理服务器地址,帐号后面加上真实POP3主机的地址即可,例如:代理服务器地址192.16.10.1,需要收取test@163.com中的信, 则设置如下:

  邮件服务器: 192.16.10.1

  帐号: test#pop3.163.com

  3.5、邮件的删除

  在上面我们曾经讲到删除单个邮件的方法:DeleteSingleMessage(long MessageID),如果想清空邮箱则只需要执行DeleteMessages(), 详细请参考3.2中的代码。

  3.6、一点说明

  IPOP3的DownloadMessages方法可以收取所有邮件中的所有数据,当我们通过Connect连接上服务器后,如果不执行DownloadMessages或者DownloadHeaders,则在执行pMessages->Item[i];时它会动态从服务器读取当前该封邮件的全部数据。

  四、关于程序的分发

  在发行你的程序时不需安装整个JMail,只需将jmail.dll注册一下即可。

  例如:regsvr32.exe c:windowssystem32jmail.dll

  (全文完)

2.2 发送HTML格式的邮件

利用JMail组件快速构建邮件程序相关推荐

  1. 发送邮件现在应用得最多的两种情况就是利用.NET自带的发送邮件和利用jmail组件来发送邮件。...

    .NET自带的邮件发送利用了System.Web.Mail.MailMessage这个类,这是在VS2003的情况下,在VS2005下更多的是利用System.Net.Mail.MailMessage ...

  2. 使用 SCons 代替 Makefile 快速构建应用程序

    使用 SCons 代替 Makefile 快速构建应用程序 2012-03-22 01:37 2971人阅读 评论(5) 收藏 举报 makefilefilegccpython工具build 目录(? ...

  3. 【实战演练】两种方法让 Docker 帮您快速构建应用程序

    写在前面 在这篇文章中,Deni Bertovic将向我们展示如何使用Docker来快速构建Haskell应用程序并生成Docker镜像. 备注: Haskell 是一种标准化的,通用的纯函数编程语言 ...

  4. 利用Jmail发送和接收邮件

    private void Button1_Click(object sender, System.EventArgs e)             {                 SendMail ...

  5. vc++ 利用jmail组件收发邮件

    A:收邮件步骤: 一:下载jmail.dll文件放到C:\Windows\System32文件夹中 二:以管理员的身份注册jmail.dll组件,即执行命令:regsvr32 jmail.dll 三: ...

  6. 结合Delphi和Python的优势:使用Delphi VCL组件快速构建超现代的Python本机Windows GUI桌面酷炫用户界面应用

    Delphi开发Pyhron GUI 有时您的应用程序需要一个用户界面,但是为Python应用程序制作用户界面最好的方法是什么?输入用于Python的DelphiVCL.VCL是成熟的Windows本 ...

  7. 利用jmail qq邮箱发邮件 报错 解决方法

    利用java的jmail,登录qq邮箱发邮件时遇到下面几个问题,分享一下解决方法. 1. qq需要使用ssl  解决方法:使用有ssl安全认证的代码 <span style="font ...

  8. 如何利用GitHub Pages快速构建免费网站?

    无需编程,零成本!只需挑选一个主题,经过配置,加入内容即可. 作者 | Stephen Vinouze 译者 | 弯月,责编 | 郭芮 头图 | CSDN 下载自东方IC 出品 | CSDN(ID:C ...

  9. 利用T-SQL语句快速清理ZBLOG程序的SQL SERVER2012数据库内容

    2019独角兽企业重金招聘Python工程师标准>>> 最近使用了ZBLOG+SQL SERVER搭建了一个博客系统,采用的是ASP程序,因为我数据量很小,使用插件生成HTML文件的 ...

最新文章

  1. zynq学习02 新建一个Helloworld工程
  2. mysql命令技巧_Mysql命令行技巧汇总
  3. Firefox, IE等不同浏览器对JavaScript,CSS不同解析问题 (转备以后使用)
  4. 如果去掉数学前后的空格_数学家们是怎么玩趣味拼图游戏的?
  5. MySQL04WHERE关键字
  6. 4月23日云栖精选夜读:阿里AI新物种!设计机器人两年赶上资深员工水平
  7. call指令和ret指令(1001)
  8. Android 比SwipeRefreshLayout更漂亮和强大的下拉刷新控件:Android-MaterialRefreshLayout
  9. uni-app 167将某人踢出群聊(二)
  10. 微信小程序自定义tabbar以及闪烁问题
  11. 如何分辨iphone 的冷屏与暖屏
  12. 不可不知的10款3dMax展UV插件
  13. 解决谷歌浏览器的 DNS_PROBE_FINISHED_NXDOMAIN
  14. ASP.NET Form Authentication - Membership Authentication
  15. lect02_codes02_pandas
  16. BIOS设置nbsp;翻译中文图文教程(一)
  17. 【Unity】3D坦克大战入门级别开发
  18. vue影院在线选座--可拖拽、缩放--A/B/C三级座位
  19. 像个专业人士一样去调试Bug
  20. php openssl支持的加密算法和加密模式及加密解密示范实例

热门文章

  1. MySql数据库存储pdf文件
  2. 游戏建模手绘角色模型制作教程
  3. 粒子的散射模拟matlab程序,非常好的球粒子Mie散射matlab仿真
  4. 浅谈医疗器械的工频磁场抗扰度试验
  5. 软件测试之测试经理篇
  6. label 跟 label for 的区别
  7. 基于WxPusher实现微信消息推送
  8. 安装mysql时默认分配的端口是_安装 MySQL时默认端口号是:_学小易找答案
  9. 三种事件模型是什么?
  10. excel 问题,vba