zoukankan      html  css  js  c++  java
  • VC++编写电子邮件程序


    一、概述
    ---- 本文主要讲述如何使用Visual C++用MAPI编写E-mail程序。MAPI是包含在Windows之中的,
    因此不需要安装其他额外的部件。MAPI有以下三种形式:
    SMAPI,Simple MAPI,简单的MAPI
    CMC,Common Messaging Calls,一般通讯调用
    完整的MAPI
    ---- SMAPI和CMC都包含在完整的MAPI中,当用户想执行一些高级操作,比如编写自己的E-mail服务器的时候,
    必须使用完整的MAPI。本文主要阐述如何编写能够收发电子邮件的程序,因此使用SMAPI就足够了。
    二、编写电子邮件程序
    3-1 初始化MAPI
    ---- 要使用MAPI,必须首先对它进行初始化。初始化包括以下三个步骤:
    装载MAPI32.DLL动态链接库
    找到想要调用的MAPI函数地址
    登录到电子邮件对象
    3-1-1 装载MAPI32.DLL
    ---- 要装载MAPI,用户必须程序运行时动态的装载一个动态链接库。LoadLibrary函数提供了此功能,
    它定位一个动态链接库,并返回HINSTANCE局柄(需要保存该句柄)。
    LoadLibrary的语法如下:
    LoadLibrary ( lpLibFileName );
    其中lpLibFileName为LPCTSTR结构变量,
    是所要调用的库的路径和名称。
    程序示例:
    // 调用MAPI32.DLL并计算函数地址
    HINSTANCE hInstMail;
    hInstMail = ::LoadLibrary ( “MAPI32.DLL” );
    if ( hInstMail == NULL )
    {
    // 错误处理
    // 受篇幅限制,下面的错误处理部分省略
    }
    3-1-2 确定函数地址
    ---- 由于MAPI32.DLL是被动态装载的,因此不知道所要调用的函数地址,也就不能一开始就调用它们,
    而要通过函数名获得函数的地址,并在动态链接库中查找每一个函数并核实。因此首先必须为这些函数声明指针

    程序示例:
    // 为MAPI32.DLL中的函数声明函数指针
    ULONG (PASCAL *lpfnMAPISendMail) (LHANDLE lhSession,
    ULONG ulUIParam, lpMapiMessage lpMessage,
    FLAGS flFlags, ULONG ulReserved);
    ULONG (PASCAL *lpfnMAPIResolveName) (LHANDLE lhSession,
    ULONG ulUIParam, LPTSTR lpszName,
    FLAGS ulFlags, ULONG ulReserved,
    lpMapiRecipDesc FAR *lppRecip);
    ULONG (FAR PASCAL *lpfnMAPILogon)(ULONG ulUIParam,
    LPSTR lpszProfileName, LPSTR lpszPassword,
    FLAGS flFlags, ULONG ulReserved,
    LPLHANDLE lplhSession);
    ULONG (FAR PASCAL *lpfnMAPILogoff)(LHANDLE lhSession,
    ULONG ulUIParam, FLAGS flFlags,
    ULONG ulReserved);
    ULONG (FAR PASCAL *lpfnMAPIFreeBuffer)(LPVOID lpBuffer);
    ULONG (FAR PASCAL *lpfnMAPIAddress)(LHANDLE lhSession,
    ULONG ulUIParam, LPSTR lpszCaption,
    ULONG nEditFields, LPSTR lpszLabels,
    ULONG nRecips, lpMapiRecipDesc lpRecips,
    FLAGS flFlags, ULONG ulReserved,
    LPULONG lpnNewRecips,
    lpMapiRecipDesc FAR *lppNewRecips);
    ULONG (FAR PASCAL *lpfnMAPIFindNext)(LHANDLE lhSession,
    ULONG ulUIParam, LPSTR lpszMessageType,
    LPSTR lpszSeedMessageID, FLAGS flFlags,
    ULONG ulReserved, LPSTR lpszMessageID);
    ULONG (FAR PASCAL *lpfnMAPIReadMail)(LHANDLE lhSession,
    ULONG ulUIParam, LPSTR lpszMessageID,
    FLAGS flFlags, ULONG ulReserved,
    lpMapiMessage FAR *lppMessage);
    ---- 为了决定每一个函数的地址,必须为每一个函数调用GetProcAddress。
    GetProcAddress的语法为:
    GetProcAddress (hModule, lpProcName);
    其中,hModule为HMODULE结构,是所调用DLL模块的句柄;
    lpProcName为LPCSTR结构,是函数名称。
    程序示例:
    // 找到MAPI32.DLL函数的地址,并将它们保存在函数指针变量里
    (FARPROC&) lpfnMAPISendMail = GetProcAddress(hInstMail,
    “MAPISendMail”);
    (FARPROC&) lpfnMAPIResolveName = GetProcAddress(
    hInstMail, “MAPIResolveName”);
    (FARPROC&) lpfnMAPILogon = GetProcAddress(hInstMail,
    “MAPILogon”);

    (FARPROC&) lpfnMAPILogoff = GetProcAddress(hInstMail,
    “MAPILogoff”);
    (FARPROC&) lpfnMAPIFreeBuffer = GetProcAddress(
    hInstMail, “MAPIFreeBuffer”);
    (FARPROC&) lpfnMAPIAddress = GetProcAddress(hInstMail,
    “MAPIAddress”);
    (FARPROC&) lpfnMAPIFindNext = GetProcAddress(hInstMail,
    “MAPIFindNext”);
    (FARPROC&) lpfnMAPIReadMail = GetProcAddress(hInstMail,
    “MAPIReadMail”);
    3-1-3 登录到电子邮件对象
    ---- 用户必须在电子邮件系统中登录,才能实现MAPI的各种功能。MAPI提供了登录的三种选择:
    登录到一个已经存在的对象。
    登录到一个新对象,用编程的方法确定解释新信息。
    使用对话框提示用户登录。
    ---- 我们通常选择登录到一个已经存在的电子邮件对象,因为网络合作用户通常会保持自己的
    电子邮件程序处于激活状态。登录通常使用MAPI提供的函数lpfnMAPILogon。
    lpfnMAPILogon的语法为:
    lpfnMAPILogon (lpszProfileName, lpszPassword, flFlags,
    ulReserved, lplhSession );
    ---- 其中,lpszProfileName指向一个256字符以内的登录名称,lpszPassword指向密码,它们均
    为LPTSTR结构。flFlags为FLAGS结构,其值详见表1。ulReserved必须为0。lplhSession为输出SMAPI的句柄。
    表1:lpfnMAPILogon函数中flFlags的值
    值 意义
    MAPI_FORCE_DOWNLOAD
    在函数调用返回之前下载用户的所有邮件。
    如果MAPI_FORCE_DOWNLOAD没有被设置,
    那么信件能够在函数调用返回后在后台被下载。
    MAPI_NEW_SESSION 建立一个新会话,
    而不是获得环境的共享会话。如果MAPI_NEW_SESSION没有被设置,
    MAPILogon使用现有的共享会话。
    MAPI_LOGON_UI 显示一个登录对话框来提示用户输入登录信息。
    例如Outlook检查用户电子邮件时便是如此。
    MAPI_PASSWORD_UI MAPILogon只允许用户输入电子邮件的密码,
    而不许改动账号。
    程序示例:
    LHANDLE lhSession;
    ULONG lResult = lpfnMAPILogon(0, NULL, NULL, 0, 0,

    &lhSession);
    if (lResult != SUCCESS_SUCCESS)
    //SUCCESS_SUCCESS在MAPI.H中被定义
    {
    // 错误处理
    }
    3-2 阅读电子邮件
    ---- MAPIFindNext和MAPIReadMail使用与阅读E-mail的两个基本函数。MAPIFindNext用于定位第一
    封或下一封电子邮件并返回标识号,MAPIReadMail返回以该标识号为基础的电子邮件的内容。另外,
    一个常用的函数是MAPIFreeBuffer,用于释放内存。
    3-2-1 定位到第一封信
    ---- 要找到第一封信,需要使用MAPIFindNext函数,其函数声明如下:
    ULONG FAR PASCAL MAPIFindNext(LHANDLE lhSession,
    ULONG ulUIParam, LPTSTR lpszMessageType,
    LPTSTR lpszSeedMessageID, FLAGS flFlags,
    ULONG ulReserved, LPTSTR lpszMessageID )
    ---- 其中,lhSession为提交SMAPI的会话句柄 ;ulUIParam为父窗体的句柄;lpszMessageType
    指向一个字符串,用来鉴别邮件类型,并加以查找;lpszSeedMessageID为指向起始信息ID的指针,
    其值为0时,MAPIFindNext获得第一封电子邮件;flFlags的值见表2;ulReserved必须为0;
    lpszMessageID为输出值,它是指向信息ID地址的指针。
    ---- 表2:MAPIFindNext函数中flFlags的值
    值 意义
    MAPI_GUARANTEE_FIFO 按邮件发送的时间顺序接受电子邮件。
    MAPI_LONG_MSGID 返回信件标识符可达512字符。
    MAPI_UNREAD_ONLY 只列举没有阅读过的电子邮件。
    程序示例:
    // 找到第一条没有阅读的电子邮件
    char pMessageID [513];
    ULONG lResult = lpfnMAPIFindNext(lhSession, NULL, NULL,
    NULL, MAPI_LONG_MSGID | MAPI_UNREAD_ONLY,
    0, pMessageID);
    3-2-2 阅读信息
    当信件ID被获取后,就可以调用MAPIReadMail
    阅读实际的E-mail信息了。MAPIReadMail的函数声明如下:
    ULONG FAR PASCAL MAPIReadMail(LHANDLE lhSession,
    ULONG ulUIParam, LPTSTR lpszMessageID,
    FLAGS flFlags, ULONG ulReserved,
    lpMapiMessage FAR * lppMessage);

    其中,lppMessage为指向MapiMessage的指针;
    除flFlags外的其他参数与lpfnFindNext函数的同名参数意义相同,
    flFlags参数的值见表3:
    表3:MAPIReadMail函数中flFlags的值:
    值 意义
    MAPI_BODY_AS_FILE 将邮件信息写到一个临时文件中,
    并且将它作为第一个附件添加到附件列表中。
    MAPI_ENVELOPE_ONLY 只读取邮件标题。
    MAPI_PEEK 读完邮件之后不把它标记为“已读”。
    MAPI_SUPPRESS_ATTACH MAPIReadMail函数不拷贝附件,
    但是将邮件文本写入MapiMessage结构中。
    程序示例:
    // 读取电子邮件
    long nFlags = MAPI_SUPPRESS_ATTACH;
    if (!bMarkAsRead)
    nFlags = nFlags | MAPI_PEEK;
    lResult = lpfnMAPIReadMail(lhSession, NULL, pMessageID,
    nFlags, 0, &pMessage);
    if (lResult != SUCCESS_SUCCESS);
    return false;
    如果调用成功,就可以访问MapiMessage结构了(使用pMessage):
    pMessage- >ulReserved:0
    pMessage- >lpszSubject:邮件标题
    pMessage- >lpszNoteText:邮件信息
    pMessage- >lpszMessageType:邮件类型
    pMessage- >DateReceived:接收时间
    pMessage- >lpszConversationID:邮件所属的会话线程ID
    pMessage- >flFlags:其值见表4
    表4:MapiMessage结构中的flFlags
    值 意义
    MAPI_RECEIPT_REQUESTED 接收通知被申请。
    客户端应用程序在发送消息时设置该项。
    MAPI_SENT 邮件已被发送。
    MAPI_UNREAD 邮件是“未读”状态。
    pMessage- >lpOriginator:指向MapiRecipDesc结构,包含发件人信息。
    pMessage- >nRecipCount:信件者数目。
    pMessage- >lpRecips:指向MapiRecipDesc结构数组,包含接收者信息。
    pMessage- >nFileCount:附件数量。
    pMessage- >lpFiles:指向MapiFileDesc结构数组,
    每一个结构包含一个文件附件。

    3-2-3 释放内存
    ---- 在访问另一条信件以前应当释放内存,否则会出现内存泄漏。
    程序示例:
    // 释放内存
    lpfnMAPIFreeBuffer(pMessage);
    3-2-4 定位到下一条信件
    定位到下一条信件依然使用MAPIFindNext函数,
    该函数声明及参数意义详见3-2-1节。下面示范如何定位到下一条信件。 程序示例:
    // 定位到下一条没有阅读的信件
    ULONG lResult = lpfnMAPIFindNext(lhSession, NULL, NULL,
    pMessageID, MAPI_LONG_MSGID|MAPI_UNREAD_ONLY,
    0, pMessageID);
    3-3 发送电子邮件
    ---- 发送电子邮件的一般步骤:
    ---- 1. 建立MapiMessage结构对象
    ---- 2. 调用MAPIResolveName使发送者名称合法
    ---- 3. 添加附件
    ---- 4. 调用MAPISendMail发送电子邮件
    ---- 5. 调用MAPIFreeBuffer释放内存
    ---- 下面详细分别详细阐述。
    3-3-1 建立MapiMessage结构对象
    ---- 对于MapiMessage结构,3-2-2节已经做过介绍,下面一步步介绍如何设置其中的值:
    ---- 1. 为MapiMessage对象分配内存:
    MapiMessage message;
    Memset(&message, 0, sizeof(message));
    ---- 2. 将ulReserved设置为0:
    message.ulReserved = 0;
    ---- 3. 设置信息类型指针lpszMessageType,可以为NULL:
    message.lpszMessageType = NULL;

    ---- 4. 设置信件标题(lpszSubject):
    char subject[512];
    strcpy(subject, sSubject);
    message.lpszSubject = subject;
    ---- 5. 设置信件内容:
    char text[5000];
    strcpy(text, sMessage);
    message.lpszNoteText = text;
    ---- 6. 设置flFlags标识,详见3-2-2节中表4:
    message.flFlags = MAPI_SENT;
    ---- 7. 用一个指向MapiRecipDesc结构的指针设置发送者信息(lpOriginator),或将其设置为NULL:
    message.lpOriginator = NULL;
    ---- 8. 设置接收者数目(nRecipCount),可以是1或更多:
    message.nRecipCount = 1;
    ---- 9. 设置接收者信息(lpRecips),详见3-3-2节
    ---- 10. 设置附件数量(nFileCount)
    ---- 11. 设置附件信息,详见3-3-3节
    b3-3-2 正确设置接收者信息
    ---- 设置接收者信息时,应当使用MAPIResolveName函数来为MapiRecipDesc结构对象分配内存,
    并返回一个指针,该指针将被保存在MapiMessage结构的lpRecips中。MAPIResolveName的函数声明如下:
    ULONG FAR PASCAL MAPIResolveName(LHANDLE lhSession,
    ULONG ulUIParam, LPTSTR lpszName,
    FLAGS flFlags, ULONG ulReserved,
    lpMapiRecipDesc FAR * lppRecip )
    ---- 其中lppRecip即为前面提到的返回的指针。除flFlags外其余参数与前几个函数意义相同。
    flFlags的值详见表5。
    表5:MAPIResolveName中flFlags的值
    值 意义
    MAPI_AB_NOMODIFY 对话框为只读。如果MAPI_DIALOG被设置,
    那么该项将被忽略。

    MAPI_DIALOG 显示一个名称解决方案的对话框
    MAPI_LOGON_UI 如果需要的话,将会显示仪个对话框让用户登录
    MAPI_NEW_SESSION 新建一个会话
    程序示例:
    char recipient[512];
    strcpy(recipient, sTo);
    lResult = lpfnMAPIResolveName(lhSession, 0, recipient,
    0, 0, &message.lpRecips);
    3-3-3 添加附件
    ---- 下面的程序示例将演示如何在电子邮件中包含附件。
    只有一点需要说明:MapiFileDesc结构中flFlags的值,详见表6。
    表6:MapiFileDesc结构中flFlags的值
    值 意义
    MAPI_OLE 附件是OLE对象。
    MAPI_OLE_STATIC 附件是静态OLE对象。
    0 附件将被视为数据文件
    程序示例:
    // 设置附件信息
    CString sPath, sFileName;
    MapiFileDesc FileInfo;
    char path[512];
    char filename[512];
    if (sAttachment == “”)
    message.nFileCount = 0;
    else
    {
    int nPos = sAttachment.ReverseFind(‘\\');
    if (nPos == -1)
    {
    sPath = sAttachment;
    }
    else
    {
    sPath = sAttachment;
    sFilename = sAttachment.Mid(nPos +1);
    }
    strcpy(path, sPath);
    strcpy(filename, sFilename);
    message.nFileCount = 1;
    FileInfo.ulReserved = 0;
    FileInfo.flFlags = 0;
    FileInfo.nPosition = sMessage.GetLength() –1;
    FileInfo.lpszPathName = path;
    FileInfo.lpszFileName = filename;
    FileInfo.lpFileType = NULL;
    message.lpFiles = & m_FileInfo;
    }
    3-3-4 发送电子邮件
    ---- 使用MAPISendMail发送电子邮件,其声明如下:
    ULONG FAR PASCAL MAPISendMail (LHANDLE lhSession,
    ULONG ulUIParam, lpMapiMessage lpMessage,
    FLAGS flFlags, ULONG ulReserved )
    ---- 其中,flFlags的允许值为MAPI_DIALOG、MAPI_LOGON_UI和MAPI_NEW_SESSION,
    其意义与前几个函数中同名标识意义相同。
    程序示例:
    lResult = lpfnMAPISendMail(0, 0, &m_message, 0, 0);
    3-3-5 释放内存
    程序示例:
    lpfnMAPIFreeBuffer(m_message.lpRecips);
    四、小结
    ---- 本文比较具体的介绍并演示了编写一个电子邮件程序的核心部分,
    如果读者要编写电子邮件程序,还需要进行的处理:
    ---- 1. 加上错误处理代码。受篇幅限制,本文的程序示例中只有两处为错误处理留空,
    比较它们的异同。电子邮件程序是非常容易出错的,因此除这两处外要在主要函数
    调用完成后都加上错误处理,或使用try throw catch块处理例外。
    ---- 2. 加上UI处理。
    ---- 另外,本文所阐述的方法比较简单易行,事实上,有关电子邮件的程序远比这复杂得多,
    因此读者若需要编写一个功能强大的电子邮件程序,需要精通MAPI和SMTP/POP3等协议;
    如果读者要编写一个电子邮件服务器,那么不妨在精通MAPI和SMTP/POP3之后,
    阅读一些有关Exchange Server的资料

    人生有三宝:终身运动,终身学习,终身反醒.吸收新知,提高效率,懂得相处,成就自己,也成就他人,创造最高价值。
  • 相关阅读:
    eclipse export runnable jar(导出可执行jar包) runnable jar可以执行的
    mave常用指令
    771. Jewels and Stones珠宝数组和石头数组中的字母对应
    624. Maximum Distance in Arrays二重数组中的最大差值距离
    724. Find Pivot Index 找到中轴下标
    605. Can Place Flowers零一间隔种花
    581. Shortest Unsorted Continuous Subarray连续数组中的递增异常情况
    747. Largest Number At Least Twice of Others比所有数字都大两倍的最大数
    643. Maximum Average Subarray I 最大子数组的平均值
    414. Third Maximum Number数组中第三大的数字
  • 原文地址:https://www.cnblogs.com/jimeper/p/304715.html
Copyright © 2011-2022 走看看