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






4.76/5 (38投票s)
一个从 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); } }
结论
像往常一样,欢迎并感谢反馈,无论是否具有建设性。