cURL / Mailing Lists / curl-library / Single Mail

curl-library

libcurl >= 7.34.0 break prev working smtp code

From: Avery Fay <avery_at_mixpanel.com>
Date: Wed, 16 Apr 2014 15:16:23 -0700

Hello,

I just tried upgrading to 7.36.0 from 7.33.0 and previously working smtp
code has stopped working. I tried all version in between and it looks like
it broke in 7.34.0. The actual error from curl_easy_perform is not very
revealing:

E0416 22:00:39.329601 19934 mail.cpp:112] curl_easy_perform: Failure when
receiving data from the peer

Here's the relevant code:

std::string create_to_address()
{
    std::ostringstream oss;
    oss << "<" << config::get().error_mail_address() << ">";
    return oss.str();
}

std::string create_from_address()
{
    char host[128];
    if (::gethostname(host, sizeof(host)) != 0) {
        throw errno_error("gethostname");
    }
    std::ostringstream oss;
    oss << "<live@" << host << ".mixpanel.com>";
    return oss.str();
}

struct mail_context
{
    std::string message;
    size_t written;
};

size_t mail_read(void *ptr, size_t size, size_t nmemb, void *userdata)
{
    mail_context& ctx = *reinterpret_cast<mail_context *>(userdata);
    size_t n = std::min(ctx.message.length() - ctx.written, size * nmemb);
    std::memcpy(ptr, ctx.message.c_str() + ctx.written, n);
    ctx.written += n;
    return n;
}

void deliver_mail(const std::string& subject, const std::string& message)
{
    auto to_address = create_to_address();
    auto from_address = create_from_address();

    mail_context ctx;
    std::ostringstream oss;
    oss << "To: " << to_address << "\r\n"
        << "From: " << from_address << "\r\n"
        << "Subject: " << subject << "\r\n"
        << "\r\n"
        << message;
    ctx.message = oss.str();

    auto cleanup = [](CURL *curl) { if (curl != 0) curl_easy_cleanup(curl);
};
    std::unique_ptr<CURL, decltype(cleanup)> curl(curl_easy_init(),
cleanup);
    if (!curl) {
        throw std::runtime_error("curl_easy_init failed");
    }

    CURLcode rc;
    if ((rc = curl_easy_setopt(curl.get(), CURLOPT_NOSIGNAL, 1)) !=
CURLE_OK) { // necessary in multithreaded code
        throw std::runtime_error(curl_easy_strerror(rc));
    }

    if ((rc = curl_easy_setopt(curl.get(), CURLOPT_MAIL_FROM,
from_address.c_str())) != CURLE_OK) {
        throw std::runtime_error(curl_easy_strerror(rc));
    }

    auto cleanup_recipients = [](struct curl_slist *slist) { if (slist)
curl_slist_free_all(slist); };
    std::unique_ptr<struct curl_slist, decltype(cleanup_recipients)>
recipients(
        curl_slist_append(0, to_address.c_str()), cleanup_recipients);
    if (!recipients) {
        throw std::runtime_error("curl_slist_append failed");
    }

    if ((rc = curl_easy_setopt(curl.get(), CURLOPT_MAIL_RCPT,
recipients.get())) != CURLE_OK) {
        throw std::runtime_error(curl_easy_strerror(rc));
    }

    if ((rc = curl_easy_setopt(curl.get(), CURLOPT_READFUNCTION,
&mail_read)) != CURLE_OK) {
        throw std::runtime_error(curl_easy_strerror(rc));
    }

    if ((rc = curl_easy_setopt(curl.get(), CURLOPT_READDATA, &ctx)) !=
CURLE_OK) {
        throw std::runtime_error(curl_easy_strerror(rc));
    }

    std::vector<std::string> servers;
    if (is_live()) {
        servers = {"10.4.44.87", "10.61.29.135"};
    } else {
        servers = {"127.0.0.1"};
    }

    for (auto& server : servers) {
        auto url = "smtp://" + server;
        if ((rc = curl_easy_setopt(curl.get(), CURLOPT_URL, url.c_str()))
!= CURLE_OK) {
            throw std::runtime_error(curl_easy_strerror(rc));
        }
        ctx.written = 0;
        if ((rc = curl_easy_perform(curl.get())) != CURLE_OK) {
            LOG(ERROR) << "curl_easy_perform: " << curl_easy_strerror(rc);
        } else {
            break;
        }
    }
}

Avery

-------------------------------------------------------------------
List admin: http://cool.haxx.se/list/listinfo/curl-library
Etiquette: http://curl.haxx.se/mail/etiquette.html
Received on 2014-04-17