65.9K
CodeProject 正在变化。 阅读更多。
Home

发送邮件而不指定 SMTP 服务器

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.76/5 (38投票s)

2005年4月12日

Ms-PL

2分钟阅读

viewsIcon

1324506

downloadIcon

5443

一个从 CSMTPConnection 派生的类,它查询目标域的 MX 记录并使用该记录发送邮件

概述

您经常会听到人们询问如何从他们的应用程序向特定电子邮件地址发送电子邮件,而无需提示用户输入中继 SMTP 服务器。最常被建议的解决方案是使用 MAPI 并从用户的注册表中获取 SMTP 服务器列表,但这假定用户已在其机器上配置了兼容 MAPI 的电子邮件客户端。我总是用我的解决方案来回答:查询目标域的 MX 记录,然后直接与该服务器进行 SMTP 聊天 - 这样做很容易,它适用于任何机器,而且也是发送电子邮件的最快方式(最少的 SMTP 跃点)。

从 VC++ 7 开始,ATL 包含了 CSMTPConnection 类,它允许您发送邮件,前提是您为其提供一个要连接的 SMTP 服务器。我从 CSMTPConnection 派生了一个类 (CSMTPConnection2),它允许您直接传入目标域名,并且该类使用客户端机器上的默认 DNS 查询 MX 记录,获取 SMTP 服务器列表(取决于返回的 MX 记录数),并连接到第一个运行正常的 SMTP 服务器。唯一的可见更改是 Connect 方法,即使对于 Connect 方法,方法签名也保持不变。第一个参数(一个 LPCTSTR)现在代表目标域名,而不是 SMTP 主机名。因此,修改您现有的代码应该很容易。只需将代码中所有对 CSMTPConnection 的引用更改为 CSMTPConnection2,您就完成了。

使用该类

  • #include 包含该类的头文件

    #include "smtpconnection2.h"

    头文件包含一个 #pragma 链接器指令,以包含 Dnsapi.lib

  • 像使用 CSMTPConnection 类一样使用 CSMTPConnection2 类(假定在调用和使用该类之前已调用 CoInitialize

    CMimeMessage msg;
    msg.SetSender("nish@somedomain.com");
    msg.SetSenderName("Nishter");
    msg.AddRecipient("someone@vsnl.com");
    
    //Optional
    msg.SetSubject("Hello World");
    msg.AddText("Hmmm, this should work fine!");
    //msg.AttachFile("some file path");
    
    CSMTPConnection2 conn;
    //You need to specify the domain name of the recipient email address
    if(conn.Connect("vsnl.com"))
    {
        if( conn.SendMessage(msg) == TRUE )
            std::cout << "Mail sent successfully" << std::endl;
        conn.Disconnect();    
    }
    

类要求

  • 您需要 VC++ 7 或更高版本(用于 ATL 类)

  • 此代码仅在 Windows 2000 或更高版本上运行(因为使用了用于查询 MX 记录的 DNS API)

  • 您不需要 MFC(使用的 CString 在 MFC/ATL 之间共享,我专门使用了 CSimpleArray 而不是 MFC 数组类)

局限性

请注意,由于该类查找 MX 记录并直接 SMTP 到每个域名的邮件服务器,因此您不能使用此类一次性向多个域发送邮件。

源代码清单

头文件

/*
    Copyright(C) Nishant Sivakumar (nish#voidnish.com)
    Please maintain this copyright notice if you distribute this file
    in original or modified form.
*/

#pragma once
#include <atlsmtpconnection.h>
#include <Windns.h>

#pragma comment(lib,"Dnsapi.lib")

class CSMTPConnection2 : public CSMTPConnection
{
public:    
    BOOL Connect(LPCTSTR lpszHostDomain, DWORD dwTimeout = 10000) throw();
private:
    void _GetSMTPList(LPCTSTR lpszHostDomain, CSimpleArray<CString>& arrSMTP);
}; 

Cpp 文件

/*
    Copyright(C) Nishant Sivakumar (nish#voidnish.com)
    Please maintain this copyright notice if you distribute this file
    in original or modified form.
*/

#include "StdAfx.h"
#include "smtpconnection2.h"

BOOL CSMTPConnection2::Connect(LPCTSTR lpszHostDomain, 
                               DWORD dwTimeout /*= 10000*/) throw()
{
    CSimpleArray<CString> arrSMTP;
    _GetSMTPList(lpszHostDomain, arrSMTP);
    for(int i=0; i<arrSMTP.GetSize(); i++)
    {
        if(CSMTPConnection::Connect(arrSMTP[i], dwTimeout) == TRUE)
            return TRUE;
    }
    return FALSE;
}

void CSMTPConnection2::_GetSMTPList(LPCTSTR lpszHostDomain, 
                                   CSimpleArray<CString>& arrSMTP)
{
    PDNS_RECORD pRec = NULL;
    if(DnsQuery(lpszHostDomain, DNS_TYPE_MX, DNS_QUERY_STANDARD,
        NULL, &pRec, NULL) == ERROR_SUCCESS)
    {
        PDNS_RECORD pRecOrig = pRec;
        while(pRec)
        {
            if(pRec->wType == DNS_TYPE_MX)
                arrSMTP.Add(pRec->Data.MX.pNameExchange);
            pRec = pRec->pNext;
        }
        DnsRecordListFree(pRecOrig,DnsFreeRecordList);
    }
} 

结论

像往常一样,欢迎并感谢反馈,无论是否具有建设性。

© . All rights reserved.