当你需要在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组件的工作过程

#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异常没有两样,在这里稍加描述只是提高本文的完整性,请看如下代码:

try
{
...
... 发送代码
...
}
catch( _com_error & e)
{
cerr << "错误号: 0x" << hex << e.Error() << endl;
cerr << "错误信息: " << e.ErrorMessage() << endl;
cerr << "错误描述: " << e.Description() << endl;
}

二、邮件发送篇

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

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

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 = "邮件正文/r/n";
// 如有必要,可以再添加一些正文
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">这种方式
来引用该图像,请看如下代码片断:

......
// 这里添加Body是为了使邮件浏览者在没有切换到HTML时给予提醒
pMessage->Body = "邮件采用HTML格式,请切换到HTML模式。/r/n";
// 添加附件
_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

// 标准邮件头
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");         // 随便加点定制信息

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

pMessage->AddNativeHeader("Disposition-Notification-To", "sender@domain.com");

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

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

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

pMessage->Send("username:password@mailserver.com")

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

在发信时我们一般把信件提交给SMTP中继服务器,SMTP中继服务器负责和目标邮局联系,并最终将信件提交到收件人所在的邮件服务器。
在没有可利用的SMTP中继服务器时,我们可以将服务器名设置为空,例如:

pMessage->Send("", VARIANT_FALSE);

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

2.6 经代理网关发送邮件

上文所说的SMTP中继服务器上的邮件传输代理程序(MTA),与WINGATE,CPROXY等代理软件提供的SMTP代理工作原理是一样的,
所以具体的发送过程也一样,例如:
代理网关地址 192.16.10.11, 要往yourmail@yourdomain.com发信,代码如下:

......
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

VC中JMail组件的应用(上)相关推荐

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

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

  2. 来总结一下在VC中调用COM组件的方法

    来总结一下在VC中调用COM组件的方法(大家来补充) [问题点数:50分,结帖人_foo] http://bbs.csdn.net/topics/50319093 发表于: 2004-04-17 16 ...

  3. 在Sql Server 中调用Jmail组件发送邮件

    在Sql Server 中调用Jmail组件发送邮件 预备知识 1.OLE自动化函数 OLE自动化使应用程序能够对另一个应用程序中实现的对象进行操作,或者将对象公开以便可以对其进行操作.自动化客户端是 ...

  4. 转:vc中如何通过http的post方式上传文件

    文章引自:http://blog.myspace.cn/e/404248359.htm vc中如何通过http的post方式上传文件 HTTP响应     在接收和解释请求消息后,服务器会返回一个HT ...

  5. VC中自定义打印调试信息函数,打印调试信息到DebugView上

    该文档参考了以下网友的文章,在此表示感谢. 1. (更新)OutputDebugString函数简单封装,实现格式化打印输出(VC++) 链接:http://blog.csdn.net/sunflov ...

  6. 利用JMail组件快速构建邮件程序

    当你需要在VC程序中提供邮件支持功能的时候,你有许多种选择: 1)根据SMTP,POP3,MIME等协议从零开始实现.这要求熟悉RFC 821,RFC 822,RFC 1123, RFC 1652, ...

  7. VC中GetLastError()获取错误信息的使用,以及错误代码的含义

    在VC中编写应用程序时,经常需要涉及到错误处理问题.许多函数调用只用TRUE和FALSE来表明函数的运行结果.一旦出现错误,MSDN中往往会指出请用GetLastError()函数来获得错误原因 可问 ...

  8. 接触VC之四:COM组件模型基础

    From: http://daimajishu.iteye.com/blog/1081292 一年又一年,已经又过了一年了.我VC的生涯已经两岁了.可以相当地庆贺一下哟.回顾这一年的学习(唉,还没有工 ...

  9. VC++中忽略所有默认库纯Win32 API编译及链接 - 计算机软件编程 - Wangye's Space

    原始链接: VC++中忽略所有默认库纯Win32 API编译及链接 - 计算机软件编程 - Wangye's Space 我们在用VC++编写Windows程序的时候可能会发现一般可执行体(.EXE) ...

最新文章

  1. 2020年春季信号与系统试卷批改
  2. MongoDB[mark]总忘记它们是干啥的
  3. python学习笔记之迭代器
  4. onclick 传参,用转义符进行转义。
  5. android重置系统,安卓手机越用越卡,恢复出厂设置真有用?别瞎搞,看完就明白了!...
  6. 在linux 5上配置戴尔MD3220i
  7. 电脑老是弹出vrvedp_m_出现三个可疑进程vrvedp_m.exe vrvrf_c.exe vrvsafec.exe
  8. Apache JMeter 字体、字体大小修改
  9. java个人中心修改界面怎么整_怎么对个人中心页面访问进行控制
  10. 亲情可以冷酷到什么地步?大家有亲身经历的吗?
  11. 千方科技的中场战事:选择、进化与野望
  12. Android ListView 获取Item的值和得到每一个Item的view对象以及得到他们所对应的控件值
  13. Unity的lua项目为Tolua# 编译云风版protobuf
  14. MongoDB从入门到高级的实战操作
  15. 将VSCode设置成中文
  16. 统计学习方法详解之第十三章 无监督学习概论
  17. 【STM32学习笔记】(6)—— 跑马灯实验详解
  18. PTA PAT排名汇总(25 分)
  19. 六、全局锁和表锁 :给表加个字段怎么有这么 多阻碍?
  20. 什么是短视频电商,短视频电商的商业模式标题】

热门文章

  1. 视频教程-SAS数据分析:从入门到企业实战-数据挖掘
  2. VASP+FDM+Phonopy 计算声子过程
  3. html的冒号有什么作用,vb中冒号和分号有什么作用
  4. nginx三种发行版本的选择
  5. css 科技 边框_一篇文章带你学习CSS3图片边框
  6. 【译】使用内容安全策略(CSP)加固应用
  7. 这是什么啊(初学MySQL时一些疑问解答,不断更新....)
  8. 海康威视面试经验总结
  9. 商旅专业名词中英文对照
  10. 2019百越杯初赛——哈尔的移动城堡