【问题标题】:Send email with attachment in C++用 C++ 发送带有附件的电子邮件
【发布时间】:2011-11-10 01:21:34
【问题描述】:

我正在开发一个 C++ 项目,其中包括将信息作为“电子邮件附件”发送给某人的功能。

除了这个“电子邮件”之外,一切都已完成。我不知道如何使这个程序能够发送电子邮件不使用任何电子邮件客户端或打开浏览器。我在互联网上搜索了很多,但找不到任何有效的东西(我对socketWinsock 等一无所知)。

【问题讨论】:

    标签: c++ email


    【解决方案1】:

    我不确定我是否同意你在监视用户所做的事情方面所做的事情,但无论如何这里有一些对发送电子邮件有用的 C++ 代码:

    #define WIN32_LEAN_AND_MEAN
    
    #include <stdio.h>
    #include <stdlib.h>
    #include <fstream.h>
    #include <iostream.h>
    #include <windows.h>
    #include <winsock2.h>
    
    #pragma comment(lib, "ws2_32.lib")
    
    // Insist on at least Winsock v1.1
    const VERSION_MAJOR = 1;
    const VERSION_MINOR = 1;
    
    #define CRLF "\r\n"                 // carriage-return/line feed pair
    
    void ShowUsage(void)
    {
      cout << "Usage: SENDMAIL mailserv to_addr from_addr messagefile" << endl
           << "Example: SENDMAIL smtp.myisp.com rcvr@elsewhere.com my_id@mydomain.com message.txt" << endl;
    
      exit(1);
    }
    
    // Basic error checking for send() and recv() functions
    void Check(int iStatus, char *szFunction)
    {
      if((iStatus != SOCKET_ERROR) && (iStatus))
        return;
    
      cerr << "Error during call to " << szFunction << ": " << iStatus << " - " << GetLastError() << endl;
    }
    
    int main(int argc, char *argv[])
    {
      int         iProtocolPort        = 0;
      char        szSmtpServerName[64] = "";
      char        szToAddr[64]         = "";
      char        szFromAddr[64]       = "";
      char        szBuffer[4096]       = "";
      char        szLine[255]          = "";
      char        szMsgLine[255]       = "";
      SOCKET      hServer;
      WSADATA     WSData;
      LPHOSTENT   lpHostEntry;
      LPSERVENT   lpServEntry;
      SOCKADDR_IN SockAddr;
    
      // Check for four command-line args
      if(argc != 5)
        ShowUsage();
    
      // Load command-line args
      lstrcpy(szSmtpServerName, argv[1]);
      lstrcpy(szToAddr, argv[2]);
      lstrcpy(szFromAddr, argv[3]);
    
      // Create input stream for reading email message file
      ifstream MsgFile(argv[4]);
    
      // Attempt to intialize WinSock (1.1 or later)
      if(WSAStartup(MAKEWORD(VERSION_MAJOR, VERSION_MINOR), &WSData))
      {
        cout << "Cannot find Winsock v" << VERSION_MAJOR << "." << VERSION_MINOR << " or later!" << endl;
    
        return 1;
      }
    
      // Lookup email server's IP address.
      lpHostEntry = gethostbyname(szSmtpServerName);
      if(!lpHostEntry)
      {
        cout << "Cannot find SMTP mail server " << szSmtpServerName << endl;
    
        return 1;
      }
    
      // Create a TCP/IP socket, no specific protocol
      hServer = socket(PF_INET, SOCK_STREAM, 0);
      if(hServer == INVALID_SOCKET)
      {
        cout << "Cannot open mail server socket" << endl;
    
        return 1;
      }
    
      // Get the mail service port
      lpServEntry = getservbyname("mail", 0);
    
      // Use the SMTP default port if no other port is specified
      if(!lpServEntry)
        iProtocolPort = htons(IPPORT_SMTP);
      else
        iProtocolPort = lpServEntry->s_port;
    
      // Setup a Socket Address structure
      SockAddr.sin_family = AF_INET;
      SockAddr.sin_port   = iProtocolPort;
      SockAddr.sin_addr   = *((LPIN_ADDR)*lpHostEntry->h_addr_list);
    
      // Connect the Socket
      if(connect(hServer, (PSOCKADDR) &SockAddr, sizeof(SockAddr)))
      {
        cout << "Error connecting to Server socket" << endl;
    
        return 1;
      }
    
      // Receive initial response from SMTP server
      Check(recv(hServer, szBuffer, sizeof(szBuffer), 0), "recv() Reply");
    
      // Send HELO server.com
      sprintf(szMsgLine, "HELO %s%s", szSmtpServerName, CRLF);
      Check(send(hServer, szMsgLine, strlen(szMsgLine), 0), "send() HELO");
      Check(recv(hServer, szBuffer, sizeof(szBuffer), 0), "recv() HELO");
    
      // Send MAIL FROM: <sender@mydomain.com>
      sprintf(szMsgLine, "MAIL FROM:<%s>%s", szFromAddr, CRLF);
      Check(send(hServer, szMsgLine, strlen(szMsgLine), 0), "send() MAIL FROM");
      Check(recv(hServer, szBuffer, sizeof(szBuffer), 0), "recv() MAIL FROM");
    
      // Send RCPT TO: <receiver@domain.com>
      sprintf(szMsgLine, "RCPT TO:<%s>%s", szToAddr, CRLF);
      Check(send(hServer, szMsgLine, strlen(szMsgLine), 0), "send() RCPT TO");
      Check(recv(hServer, szBuffer, sizeof(szBuffer), 0), "recv() RCPT TO");
    
      // Send DATA
      sprintf(szMsgLine, "DATA%s", CRLF);
      Check(send(hServer, szMsgLine, strlen(szMsgLine), 0), "send() DATA");
      Check(recv(hServer, szBuffer, sizeof(szBuffer), 0), "recv() DATA");
    
      // Send all lines of message body (using supplied text file)
      MsgFile.getline(szLine, sizeof(szLine));             // Get first line
    
      do         // for each line of message text...
      {
        sprintf(szMsgLine, "%s%s", szLine, CRLF);
        Check(send(hServer, szMsgLine, strlen(szMsgLine), 0), "send() message-line");
        MsgFile.getline(szLine, sizeof(szLine)); // get next line.
      } while(MsgFile.good());
    
      // Send blank line and a period
      sprintf(szMsgLine, "%s.%s", CRLF, CRLF);
      Check(send(hServer, szMsgLine, strlen(szMsgLine), 0), "send() end-message");
      Check(recv(hServer, szBuffer, sizeof(szBuffer), 0), "recv() end-message");
    
      // Send QUIT
      sprintf(szMsgLine, "QUIT%s", CRLF);
      Check(send(hServer, szMsgLine, strlen(szMsgLine), 0), "send() QUIT");
      Check(recv(hServer, szBuffer, sizeof(szBuffer), 0), "recv() QUIT");
    
      // Report message has been sent
      cout << "Sent " << argv[4] << " as email message to " << szToAddr << endl;
    
      // Close server socket and prepare to exit.
      closesocket(hServer);
    
      WSACleanup();
    
      return 0;
    }
    

    互联网上有很多类似问题的链接,我发现了这个:

    http://social.msdn.microsoft.com/Forums/en-US/vclanguage/thread/12345906-8a17-41c2-846f-fd3e1a135238/

    【讨论】:

    • 它给出了一个错误“从 project2.obj 引用的未解析的外部 _wmain”我不确定它是什么。
    【解决方案2】:

    感谢您尝试自己编写代码。这让你超越了普通的脚本小子。

    但对你的兄弟进行间谍​​活动感到羞耻。他的私事是他的事,与你无关。

    另外,如果你的兄弟只是有点聪明,他不会迷恋一些可执行的电子邮件附件。此外,大多数电子邮件程序和网络邮件程序都会警告不要执行此操作。如果你要做到这一点,你需要在使用的电子邮件客户端中找到漏洞,注入代码,最好的方法是攻击图像加载器和压缩例程,但理想情况下你必须找到一个 0day,否则,这些漏洞可能在您获取间谍软件之前已被修补。您可能想阅读的一些主题是

    • 堆栈溢出漏洞
    • 堆喷射
    • 基于返回的编程(用于对抗 W^X 保护和地址空间随机化的温和实现)

    发送电子邮件归结为实现http://www.faqs.org/rfcs/rfc821.html 中记录的 SMTP 协议

    从技术上讲,可以将电子邮件直接发送到目标服务器,但这些通常会拒绝直接来自拨号连接的邮件,因为这是一种廉价而有效的反垃圾邮件方法。因此,您最好检查具有正确 MX 记录的 MTA。 Freemailers 是你的朋友,Hotmail 在这方面很受欢迎。但是,您也必须实施 SMTP-Auth。记录在http://www.faqs.org/rfcs/rfc2554.html

    当然,您也可以在某处上传文件,而不是发送电子邮件。或者您可以实现 IMAP 并使用支持 IMAP 的 freemailer 将数据存储在 IMAP 草稿目录中。

    因此,如果您设法自己使用自己的代码实现这一目标,那么我认为您应该获得成功,但前提是这不涉及第三方恶意软件构建工具包库(是的,它们存在)。

    【讨论】:

    • 压缩文件通常是一种解决方法。电子邮件客户端通常不会抱怨,操作系统有时会自动解压缩。
    【解决方案3】:

    使用cURL 发送电子邮件的可行解决方案


    here下载cURL,然后解压。现在,使用来自windows.hWinExec() 从 C++ 代码运行可执行文件。

    这是 Gmail 的演示:

    #include <windows.h>
    
    int main(void){
        char* command = "curl smtp://smtp.gmail.com:587 -v --mail-from \"SENDER.EMAIL@gmail.com\" --mail-rcpt \"RECEIVER.EMAIL@gmail.com\" --ssl -u SENDER.EMAIL@gmail.com:PASSWORD -T \"ATTACHMENT.FILE\" -k --anyauth";
        WinExec(command, SW_HIDE);
        return 0;
    }
    

    curl.exe 放在同一目录中。在command 中输入您的电子邮件地址和密码。在这里,消息被保存在一个文本文件 (ATTACHMENT.FILE) 中。

    注意:command 可能不支持某些特殊字符(如-&amp;)。


    以上只是cURL的一个演示。对于实际使用,您应该选择 libcurl这是用于发送邮件的head-start(适用于 Windows 和 Linux)。

    【讨论】:

    • cURL 作为一个库存在:libCurl。并且还有一个 CPP 包装器 curlpp。
    【解决方案4】:

    indy 也有通过 SMTP 发送电子邮件的组件

    TIdSMTP *IdSMTP1 = new TIdSMTP(this);
    IdSMTP1->Host = "myhost";
    IdSMTP1->Port = 25;
    TIdMessage *MSG = new TIdMessage(this);
    MSG->Clear();
    MSG->From->Address = "someone@someone.com";
    MSG->From->Name = "Someone";
    MSG->Subject = "Spy Email";
    MSG->Recipients->EMailAddresses = "Watcher@watch.com";
    MSG->Body->Text = "your being watched ";
    IdSMTP1->Connect();
    IdSMTP1->Send(MSG);
    IdSMTP1->Disconnect(true);
    delete MSG;
    delete IdSMTP1;
    

    它现在随 Builder 一起安装

    【讨论】:

    • 不要忘记附件部分。为此,将TIdAttachmentFile 对象添加到TIdMessage::MessageParts 集合中。
    【解决方案5】:

    我应该推荐很好的VMime 库。这是一个真正的 C++ 库,可以处理所有电子邮件。

    我还听说cURL 支持 SMTP。

    【讨论】:

      【解决方案6】:

      [libcurl][1] 是免费的、好的并且容易上手的。除了其他数十种服务外,它还支持 SMTP 和 SMTPS。

      它有很多示例展示如何使用 libcurl 发送电子邮件,请参阅here

      【讨论】:

        猜你喜欢
        • 2015-09-09
        • 2012-11-28
        • 1970-01-01
        • 2015-08-28
        • 2013-11-26
        相关资源
        最近更新 更多