首页 > 代码库 > C++发送邮件方式之curl方式

C++发送邮件方式之curl方式

最近需要做一个跨IOS和android等移动平台的邮件方式,找了几个,有个是openssl和base64的,但是一直没编译通过OPENSSL的动态库,然后换了公司的一个内部方式,测试服务器超时(gmail),今天又得重新琢磨。
   网上看到一篇很不错的方法,转载下,因为里面有个小小bug,这次贴出来的代码是经测试通过的
 //CSendMail.h 
 /*
 * File:   CSendMail.h
 * Author: jaylong35
 *
 * Created on January 16, 2012, 6:14 PM
 */
#ifndef CSENDMAIL_H
#define CSENDMAIL_H
#include <string>
#include <list>
#include <vector>
#include <curl/curl.h>
#define MULTI_PERFORM_HANG_TIMEOUT 60 * 1000

class CSendMail {
public:
    CSendMail();
    CSendMail(  //create sendmail object with paremeter;
                const std::string & strUser,
                const std::string & strPsw,
                const std::string & strSmtpServer,
                int iPort,
                const std::string & strMailFrom
            );
    CSendMail(const CSendMail& orig);
    virtual ~CSendMail();
private:
    std::string m_strUser;   //邮箱用户名
    std::string m_strPsw;   //邮箱密码
    std::string m_strSmtpServer;  //邮箱SMTP服务器
    int         m_iPort;   //邮箱SMTP服务器端口
    std::list<std::string> m_RecipientList;   //接收者邮件list
    std::string m_strMailFrom;   //发送者邮箱
    std::vector<std::string> m_MailContent; //发送的内容队列,包括头和内容项
    int         m_iMailContentPos;  //用于发送数据时记录发送到第几个content
   
private:
    //发送内容回调函数
    static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *userp);
    //获取当前时间
    static struct timeval tvnow(void);
    //两个时间差
    static long tvdiff(struct timeval newer, struct timeval older);
    //创建邮件内容
    bool ConstructHead(const std::string & strSubject/*邮件主题*/, const std::string & strContent/*邮件内容*/);
   
public:
   
    bool SendMail(const std::string & strSubject, const char * pMailBody, int len);
    bool SendMail(const std::string & strSubject, const std::string & strMailBody);
    bool SendMail(  //create sendmail object with paremeter;
                    const std::string & strUser,
                    const std::string & strPsw,
                    const std::string & strSmtpServer,
                    int iPort,
                    std::list<std::string> & recipientList,
                    const std::string & strMailFrom,
                    const std::string & strSubject,
                    const char * pMailBody,
                    int len
                );
    bool SendMail(  //create sendmail object with paremeter;
                    const std::string & strUser,
                    const std::string & strPsw,
                    const std::string & strSmtpServer,
                    int iPort,
                    const std::string & strMailTo,
                    const std::string & strMailFrom,
                    const std::string & strSubject,
                    const char * pMailBody,
                    int len
                );
    bool SendMail(  //create sendmail object with paremeter;
                    const std::string & strUser,
                    const std::string & strPsw,
                    const std::string & strSmtpServer,
                    int iPort,
                    std::list<std::string> & recipientList,
                    const std::string & strMailFrom,
                    const std::string & strSubject,
                    const std::string & strMailBody
                );
    bool SendMail(  //create sendmail object with paremeter;
                    const std::string & strUser,
                    const std::string & strPsw,
                    const std::string & strSmtpServer,
                    int iPort,
                    const std::string & strMailTo,
                    const std::string & strMailFrom,
                    const std::string & strSubject,
                    const std::string & strMailBody
                );
   
    void SetUser(const std::string & strUser) { m_strUser = strUser; }
    std::string & GetUser() { return m_strUser; }
   
    void SetPsw(const std::string & strPsw) { m_strPsw = strPsw; }
    std::string & GetPsw() { return m_strPsw; }
   
    void SetSmtpServer(const std::string & strSmtpServer) { m_strSmtpServer = strSmtpServer; }
    std::string & GetSmtpServer() { return m_strSmtpServer; }
   
    void SetPort(int iPort) { m_iPort = iPort; }
    int GetPort() { return m_iPort; }
   
    void SetMailFrom(const std::string & strMailFrom) { m_strMailFrom = strMailFrom; }
    std::string & GetMailFrom() { return m_strMailFrom; }
   
    //添加接收者邮箱
    void AddRecipient(const std::string & strMailTo) { m_RecipientList.push_back(strMailTo); }
    void AddRecipient(std::list<std::string> recipientList)
    {
        std::copy(recipientList.begin(), recipientList.end(), m_RecipientList.begin());
    }
    void ClearRecipient() { m_RecipientList.clear(); }
   
};

 


#endif /* CSENDMAIL_H */

/*
 * File:   CSendMail.cpp
 * Author: root
 *
 * Created on January 16, 2012, 6:14 PM
 */
#include "stdafx.h"
#include "CSendMail.h"

CSendMail::CSendMail()
{
    m_strUser = "";
    m_strPsw = "";
    m_strSmtpServer = "";
    m_iPort = -1;
    m_RecipientList.clear();
    m_strMailFrom = "";
    m_MailContent.clear();
    m_iMailContentPos = 0;
}

CSendMail::CSendMail(  //create sendmail object with paremeter;
                const std::string & strUser,
                const std::string & strPsw,
                const std::string & strSmtpServer,
                int iPort,
                const std::string & strMailFrom
            )
{
    m_strUser = strUser;
    m_strPsw = strPsw;
    m_strSmtpServer = strSmtpServer;
    m_iPort = iPort;
    m_RecipientList.clear();
    m_strMailFrom = strMailFrom;
    m_MailContent.clear();
    m_iMailContentPos = 0;
}

CSendMail::CSendMail(const CSendMail& orig) {
}

CSendMail::~CSendMail() {
}

size_t CSendMail::read_callback(void* ptr, size_t size, size_t nmemb, void* userp)
{
    CSendMail * pSm = (CSendMail *)userp;

    if(size*nmemb < 1)
        return 0;
    if(pSm->m_iMailContentPos < pSm->m_MailContent.size())
    {
        size_t len;
        len = pSm->m_MailContent[pSm->m_iMailContentPos].length();

        memcpy(ptr, pSm->m_MailContent[pSm->m_iMailContentPos].c_str(), pSm->m_MailContent[pSm->m_iMailContentPos].length());
        pSm->m_iMailContentPos++; /* advance pointer */
        return len;
    }
    return 0;
}

struct timeval CSendMail::tvnow()
{
  /*
  ** time() returns the value of time in seconds since the Epoch.
  */
    struct timeval now;
    now.tv_sec = (long)time(NULL);
    now.tv_usec = 0;
    return now;
}

long CSendMail::tvdiff(timeval newer, timeval older)
{
    return (newer.tv_sec-older.tv_sec)*1000+
        (newer.tv_usec-older.tv_usec)/1000;
}

bool CSendMail::ConstructHead(const std::string & strSubject, const std::string & strContent)
{
    m_MailContent.push_back("MIME-Versioin: 1.0\n");
    std::string strTemp = "To: ";
    for(std::list<std::string >::iterator it = m_RecipientList.begin(); it != m_RecipientList.end();)
    {
        strTemp += *it;
        it++;
        if(it != m_RecipientList.end())
                strTemp += ",";
    }
    strTemp += "\n";
    m_MailContent.push_back(strTemp);
    if(strSubject != "")
    {
        strTemp = "Subject: ";
        strTemp += strSubject;
        strTemp += "\n";
        m_MailContent.push_back(strTemp);
    }
    m_MailContent.push_back("Content-Transfer-Encoding: 8bit\n");
    m_MailContent.push_back("Content-Type: text/html; \n Charset=\"UTF-8\"\n\n");
    if(strContent != "")
    {
        m_MailContent.push_back(strContent);
    }
   
    return true;
}

bool CSendMail::SendMail(const std::string& strSubject, const std::string& strMailBody)
{
    m_MailContent.clear();
    m_iMailContentPos = 0;
    ConstructHead(strSubject, strMailBody);
    bool bRet = true;
    CURL *curl;
    CURLM *mcurl;
    int still_running = 1;
    struct timeval mp_start;
    char mp_timedout = 0;
    struct curl_slist* rcpt_list = NULL;

    curl_global_init(CURL_GLOBAL_DEFAULT);

    curl = curl_easy_init();
    if (!curl)
    {
        printf("Init curl failed!\n");
        return false;
    }

    mcurl = curl_multi_init();
    if (!mcurl)
    {
        printf("Init mcurl failed!\n");
        return false;
    }
    for(std::list<std::string >::iterator it = m_RecipientList.begin(); it != m_RecipientList.end();it++)
    {
        rcpt_list = curl_slist_append(rcpt_list, it->c_str());
    }
   
    if(m_strSmtpServer == "" || m_iPort <= 0)
    {
        printf("smtp server couldn‘t be empty, or port must be large than 0!\n");
       
        curl_slist_free_all(rcpt_list);
        curl_multi_cleanup(mcurl);
        curl_easy_cleanup(curl);
        curl_global_cleanup();
        return false;
    }
    std::string strUrl = "smtp://" + m_strSmtpServer;
    strUrl += ":";
    char cPort[10];
    memset(cPort, 0, 10);
    sprintf(cPort, "%d", m_iPort);
    strUrl += cPort;
    curl_easy_setopt(curl, CURLOPT_URL, strUrl.c_str());
   
    if(m_strUser != "")
    {
        curl_easy_setopt(curl, CURLOPT_USERNAME, m_strUser.c_str());
    }
    if(m_strPsw != "")
    {
        curl_easy_setopt(curl, CURLOPT_PASSWORD, m_strPsw.c_str());
    }
   
    curl_easy_setopt(curl, CURLOPT_READFUNCTION, &CSendMail::read_callback);
   
    if(m_strMailFrom == "")
    {
        printf("Mail from address couldn‘t be empty!\n");
       
        curl_slist_free_all(rcpt_list);
        curl_multi_cleanup(mcurl);
        curl_easy_cleanup(curl);
        curl_global_cleanup();
        return false;
    }
    curl_easy_setopt(curl, CURLOPT_MAIL_FROM, m_strMailFrom.c_str());
    curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, rcpt_list);
    curl_easy_setopt(curl, CURLOPT_USE_SSL, (long) CURLUSESSL_ALL);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
    curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
    curl_easy_setopt(curl, CURLOPT_READDATA, this);
    curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
    curl_easy_setopt(curl, CURLOPT_SSLVERSION, 0L);
    curl_easy_setopt(curl, CURLOPT_SSL_SESSIONID_CACHE, 0L);
    curl_multi_add_handle(mcurl, curl);

    mp_timedout = 0;
    mp_start = tvnow();

    /* we start some action by calling perform right away */
    curl_multi_perform(mcurl, &still_running);

    while (still_running) {
        struct timeval timeout;
        int rc; /* select() return code */

        fd_set fdread;
        fd_set fdwrite;
        fd_set fdexcep;
        int maxfd = -1;

        long curl_timeo = -1;

        FD_ZERO(&fdread);
        FD_ZERO(&fdwrite);
        FD_ZERO(&fdexcep);

        /* set a suitable timeout to play around with */
        timeout.tv_sec = 1;
        timeout.tv_usec = 0;

        curl_multi_timeout(mcurl, &curl_timeo);
        if (curl_timeo >= 0) {
            timeout.tv_sec = curl_timeo / 1000;
            if (timeout.tv_sec > 1)
                timeout.tv_sec = 1;
            else
                timeout.tv_usec = (curl_timeo % 1000) * 1000;
        }

        /* get file descriptors from the transfers */
        curl_multi_fdset(mcurl, &fdread, &fdwrite, &fdexcep, &maxfd);

        /* In a real-world program you OF COURSE check the return code of the
           function calls.  On success, the value of maxfd is guaranteed to be
           greater or equal than -1.  We call select(maxfd + 1, ...), specially in
           case of (maxfd == -1), we call select(0, ...), which is basically equal
           to sleep. */

        rc = select(maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout);

        if (tvdiff(tvnow(), mp_start) > MULTI_PERFORM_HANG_TIMEOUT) {
            fprintf(stderr, "ABORTING TEST, since it seems "
                    "that it would have run forever.\n");
            bRet = false;
            break;
        }

        switch (rc) {
            case -1:
                /* select error */
                printf("select error\n");
                bRet = false;
                break;
            case 0: /* timeout */
                printf("time out, retry again!\n");
                curl_multi_perform(mcurl, &still_running);
                break;
            default: /* action */
                curl_multi_perform(mcurl, &still_running);
                break;
        }
    }

    curl_multi_remove_handle(mcurl, curl);
    curl_slist_free_all(rcpt_list);
    curl_multi_cleanup(mcurl);
    curl_easy_cleanup(curl);
    curl_global_cleanup();
    return bRet;
}

bool CSendMail::SendMail(const std::string & strSubject, const char* pMailBody, int len)
{
    std::string strMailContent;
    strMailContent.append(pMailBody, len);
   
    return SendMail(strSubject, strMailContent);
}

bool CSendMail::SendMail(const std::string& strUser, const std::string& strPsw, const std::string& strSmtpServer, int iPort, std::list<std::string>& recipientList, const std::string& strMailFrom, const std::string& strSubject, const std::string& strMailBody)
{
    m_strUser = strUser;
    m_strPsw = strPsw;
    m_strSmtpServer = strSmtpServer;
    m_iPort = iPort;
 m_RecipientList.resize(recipientList.size());
    std::copy(recipientList.begin(), recipientList.end(), m_RecipientList.begin());
    m_strMailFrom = strMailFrom;
   
    return SendMail(strSubject, strMailBody);
   
}

bool CSendMail::SendMail(const std::string& strUser, const std::string& strPsw, const std::string& strSmtpServer, int iPort, std::list<std::string>& recipientList, const std::string& strMailFrom, const std::string& strSubject, const char* pMailBody, int len)
{
    std::string strMailContent;
    strMailContent.append(pMailBody, len);
    return SendMail(strUser, strPsw, strSmtpServer, iPort, recipientList, strMailFrom, strSubject, strMailContent);
}

bool CSendMail::SendMail(const std::string& strUser, const std::string& strPsw, const std::string& strSmtpServer, int iPort, const std::string& strMailTo, const std::string& strMailFrom, const std::string& strSubject, const std::string& strMailBody)
{
    std::list<std::string> recipientList;
    recipientList.push_back(strMailTo);
   
    return SendMail(strUser, strPsw, strSmtpServer, iPort, recipientList, strMailFrom, strSubject, strMailBody);
}

bool CSendMail::SendMail(const std::string& strUser, const std::string& strPsw, const std::string& strSmtpServer, int iPort, const std::string& strMailTo, const std::string& strMailFrom, const std::string& strSubject, const char* pMailBody, int len)
{
    std::string strMailContent;
    strMailContent.append(pMailBody, len);
    return SendMail(strUser, strPsw, strSmtpServer, iPort, strMailTo, strMailFrom, strSubject, strMailContent);

}

在main函数调用如下:
 

 // sendmailCurl.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "CSendMail.h"
#include <iostream>


int _tmain(int argc, _TCHAR* argv[])
{
 CSendMail *sendmail = new CSendMail;
 bool s = sendmail->SendMail(
  "登录名",
  "密码",
  "smtp.126.com",
  25,
  "465991150@qq.com",
  "mytestmails@126.com",
  "fdsa",
  "fdsafa"
  );
 if (!s)
 {
  std::cout <<"fdaf" <<std::endl;
 }
 return 0;
}

技术分享

(注:此博文应该是我一年前写,之前全部写在了QQ空间,现在转到这里。)

C++发送邮件方式之curl方式