C ++和curl,发送电子邮件时的奇怪字符编码

时间:2017-09-07 10:41:33

标签: c++ email curl

我在Linux上发送带有c ++的电子邮件。为此,我使用curl库,但是我对字符的表征有点奇怪。当我发送(作为主题或信息正文)“áéíóú”或“Móviláéíóú”时,电子邮件被正确查看“áéíóú”或“Móviláéíóú”。但是当我发送“Móvil”时,编码不正确被视为“Móvil”。

我已经更改了卷曲编码的标题,但它似乎根本不起作用。 我不知道该怎么办,所以感谢任何帮助。

可能我的错误接近

    headers = curl_slist_append(headers, "Content-Type: text/html");
    headers = curl_slist_append(headers, "charset: utf-8");

类代码如下:

.h

        class SendEmail {
            public:
            SendEmail( std::string to,
                     std::string from,
                     std::string nameFrom,
                     std::string subject,
                     std::string body,
                     std::string cc );
            virtual ~SendEmail();
            CURLcode send(const std::string &url,
                              const std::string &userName,
                              const std::string &password);
            private:
            struct StringData {
                    std::string msg;
                    size_t bytesleft;
                    StringData(std::string &&m) : msg{ m }, bytesleft{ msg.size() } {}
                    StringData(std::string  &m) = delete;
                };
            static std::string _dateTimeNow();
            std::string _generateMessageId() const;
            static size_t _payloadSource(void *ptr, size_t size, size_t nmemb, void *userp);
            std::string _setPayloadText();
            std::vector<std::string> split(std::string &text, char sep);
            std::string _to, _from, _cc, _nameFrom, _subject, _body;};

.cpp
    SendEmail::SendEmail( std::string to,
                  std::string from,
                  std::string nameFrom,
                  std::string subject,
                  std::string body,
                  std::string cc)
    {
        _to       = to;
        _from     = from;
        _nameFrom = nameFrom;
        _subject  = subject;
        _body     = body;
        _cc       = cc.empty() ? to : cc;
    }
    SendEmail::~SendEmail() {

    }
    CURLcode SendEmail::send(const std::string &url,
                         const std::string &userName,
                         const std::string &password)
    {

        std::vector<std::string> vectorTo;
        std::vector<std::string> vectorCC;

        CURLcode ret = CURLE_OK;

        struct curl_slist *recipients = NULL;

        CURL *curl = curl_easy_init();

        StringData textData { _setPayloadText() };

        if (curl) {
            curl_easy_setopt(curl, CURLOPT_USERNAME,     userName.c_str());
            curl_easy_setopt(curl, CURLOPT_PASSWORD,     password.c_str());
            curl_easy_setopt(curl, CURLOPT_URL,          url     .c_str());

           // curl_easy_setopt(curl, CURLOPT_USE_SSL,      (long)CURLUSESSL_ALL);
            //curl_easy_setopt(curl, CURLOPT_CAINFO, "/path/to/certificate.pem");
            curl_easy_setopt(curl, CURLOPT_MAIL_FROM,    ("<" + _from + ">").c_str());
            vectorTo = split(_to, ';');
            vectorCC = split(_cc, ';');

            struct curl_slist *headers=NULL;
            headers = curl_slist_append(headers, "Content-Type: text/html");
            headers = curl_slist_append(headers, "charset: utf-8");
            headers = curl_slist_append(headers, "charsets: utf-8");

             /* pass our list of custom made headers */
             curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);

            for(string to : vectorTo){
                if(to.empty()==false){
                    recipients = curl_slist_append(recipients,   ("<" + to   + ">").c_str());
                }
            }
            for(string cc : vectorCC){
                if(cc.empty()==false){
                    recipients = curl_slist_append(recipients,   ("<" + cc   + ">").c_str());
                }
            }
            curl_easy_setopt(curl, CURLOPT_MAIL_RCPT,    recipients);
            curl_easy_setopt(curl, CURLOPT_READFUNCTION, _payloadSource);
            curl_easy_setopt(curl, CURLOPT_READDATA,     &textData);
            curl_easy_setopt(curl, CURLOPT_UPLOAD,       1L);
            curl_easy_setopt(curl, CURLOPT_VERBOSE,      1L);

            ret = curl_easy_perform(curl);

            if (ret != CURLE_OK) {
                std::cerr << "curl_easy_perform() failed: " << curl_easy_strerror(ret) << "\n";
            }
            curl_slist_free_all(recipients);
            curl_slist_free_all(headers); /* free the header list */
            curl_easy_cleanup(curl);
        }
        vectorTo.clear();
        vectorCC.clear();

        return ret;
    }
    std::string SendEmail::_dateTimeNow()
    {
        const int RFC5322_TIME_LEN = 32;

        std::string ret;
        ret.resize(RFC5322_TIME_LEN);

        time_t tt;

    #ifdef _MSC_VER
        time(&tt);
        tm *t = localtime(&tt);
    #else
        tm tv, *t = &tv;
        tt = time(&tt);
        localtime_r(&tt, t);
    #endif

        strftime(&ret[0], RFC5322_TIME_LEN, "%a, %d %b %Y %H:%M:%S %z", t);

        return ret;
    }
    std::string SendEmail::_generateMessageId() const
    {
        const int MESSAGE_ID_LEN = 37;

        tm t;
        time_t tt;
        time(&tt);

        std::string ret;
        ret.resize(15);

    #ifdef _MSC_VER
        gmtime_s(&t, &tt);
    #else
        gmtime_r(&tt, &t);
    #endif

        strftime(const_cast<char *>(ret.c_str()),
                 MESSAGE_ID_LEN,
                 "%Y%m%d%H%M%S.",
                 &t);

        ret.reserve(MESSAGE_ID_LEN);

        static const char alphaNum[] =
            "0123456789"
            "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
            "abcdefghijklmnopqrstuvwxyz";

        while (ret.size() < MESSAGE_ID_LEN) {
            ret += alphaNum[rand() % (sizeof(alphaNum) - 1)];
        }

        return ret;
    }
    size_t SendEmail::_payloadSource(void *ptr, size_t size, size_t nmemb, void *userp)
    {
        StringData *text = reinterpret_cast<StringData *>(userp);

        if ((size == 0) || (nmemb == 0) || ((size*nmemb) < 1) || (text->bytesleft == 0)) {
            return 0;
        }

        if ((nmemb * size) >= text->msg.size()) {
            text->bytesleft = 0;
            return text->msg.copy(reinterpret_cast<char *>(ptr), text->msg.size());
        }

        return 0;
    }
    std::string SendEmail::_setPayloadText()
    {
        std::string ret;

        ret += "Date: "  + _dateTimeNow() + ">\r\n";
        ret += "To: <"   + _to            + ">\r\n";
        ret += "From: <" + _from          + "> (" + _nameFrom + ")\r\n";
        ret += "Cc: <"   + _cc            + "> (" + _nameFrom + ")\r\n";

        ret += "Message-ID: <"  + _generateMessageId() + "@" + _from.substr(_from.find('@') + 1) + ">\r\n";
        ret += "Subject: "      + _subject + "\r\n";
        ret += "\r\n";

        ret += _body + "\r\n";

        ret += "\r\n";
        ret += "\r\n"; // "It could be a lot of lines, could be MIME encoded, whatever.\r\n";
        ret += "\r\n"; // "Check RFC5322.\r\n";

        return ret;
    }

    std::vector<std::string> SendEmail::split(std::string &text, char sep) {
      std::vector<std::string> tokens;
      std::size_t start = 0, end = 0;
      while ((end = text.find(sep, start)) != std::string::npos) {
        tokens.push_back(text.substr(start, end - start));
        start = end + 1;
      }
      tokens.push_back(text.substr(start));
      return tokens;
    }

1 个答案:

答案 0 :(得分:0)

我终于解决了这个问题。这是电子邮件标题的编码。只需要修改以下功能:

std::string SendEmail::_setPayloadText()
{
    std::string ret;
    ret += "Content-Type: text/plain; charset=utf-8; \r\n";
    ret += "Date: "  + _dateTimeNow() + ">\r\n";
    ret += "To: <"   + _to            + ">\r\n";
    ret += "From: <" + _from          + "> (" + _nameFrom + ")\r\n";
    ret += "Cc: <"   + _cc            + "> (" + _nameFrom + ")\r\n";

    ret += "Message-ID: <"  + _generateMessageId() + "@" + _from.substr(_from.find('@') + 1) + ">\r\n";
    ret += "Subject: "      + _subject + "\r\n";
    ret += "\r\n";

    ret += _body + "\r\n";

    ret += "\r\n";
    ret += "\r\n"; // "It could be a lot of lines, could be MIME encoded, whatever.\r\n";
    ret += "\r\n"; // "Check RFC5322.\r\n";

    cout<<ret<<endl;

    return ret;
}

添加以下行:

"Content-Type: text/plain; charset=utf-8; \r\n";