Click here to Skip to main content
15,891,529 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
I am new to CURL and I am trying to send a dynamic message body. But I receive only an empty subject and message body when I attempt to use CURL lib in visual c++.
Please help.

What I have tried:

C++
<pre>    size_t Process::processmail(void *ptr, size_t size, size_t nmemb, void *userp)
    {
	std::string a, b, c, d;
	std::string arr[MAXSPACE];
	std::string search = ",";
	int spacePos;
	int currPos = 0;
	int k = 0;
	int prevPos = 0;
	std::string &statistics = *(static_cast<std::string*>(userp));
	do
	{
		spacePos = statistics.find(search, currPos);
		if (spacePos >= 0)
		{

			currPos = spacePos;
			arr[k] = statistics.substr(prevPos, currPos - prevPos);
			currPos++;
			prevPos = currPos;
			k++;
		}
	} while (spacePos >= 0);

	arr[k] = statistics.substr(prevPos, statistics.length());

	for (int i = 0; i < k; i++)
	{
		std::cout << arr[i] << std::endl;
	}
	a = arr[3];
	b = arr[2];
	c = arr[1];
	d = arr[0];
	const char *data;
	time_t now = time(0);
	char* dt = ctime(&now);
	const char *payload_text[] = {
		"Date: ", dt, "\r\n",
		"To: ",mail.c_str(), "\r\n",
		"From: " FROM "\r\n",
		"Subject: Analysis\r\n",
		"\r\n",
		"This is just a test message.\r\n",
		"\r\n",
		"A:", a.c_str(), "\r\n",
		"B:", b.c_str(), "\r\n",
		"C:", c.c_str(), "\r\n",
		NULL
	};

		if ((size == 0) || (nmemb == 0) || ((size*nmemb) < 1)) {
		return 0;
	}

	data = payload_text[lines_read];

	if (data) {
		size_t len = strlen(data);
		memcpy(ptr, data, len);
		lines_read++;
		return len;
	}
	return 0;
    }

     void Process::sendmail(std::string mail)
    {
	CURL *curl;
	CURLcode res = CURLE_OK;
	struct curl_slist *recipients = NULL;
	curl = curl_easy_init();
	if (curl) {
	
		curl_easy_setopt(curl, CURLOPT_USERNAME, "User Name");
		curl_easy_setopt(curl, CURLOPT_PASSWORD, "Password");
		curl_easy_setopt(curl, CURLOPT_URL, "smtp.hushmail.com:587");
		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);
		recipients = curl_slist_append(recipients, mail.c_str());
		curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
		curl_easy_setopt(curl, CURLOPT_READFUNCTION, &Process::processmail);
		curl_easy_setopt(curl, CURLOPT_READDATA, lines_read);
		curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);

		
		curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);

		
		res = curl_easy_perform(curl);

		
		if (res != CURLE_OK)
			fprintf(stderr, "curl_easy_perform() failed: %s\n",
			curl_easy_strerror(res));

		
		curl_slist_free_all(recipients);

		curl_easy_cleanup(curl);
	 }
    }
Posted
Updated 11-Jan-17 0:14am

1 solution

So you have adopted the example from libcurl example - smtp-mail.c[^] and modified it.

One of your modifications is related to the mail content which is created by the callback function. So the problem is obviously located there. A candidate would be the lines_read variable. But you did not show the definition of that variable and where it is initialised with which value.

Callback functions must be static and support therefore usually an pointer argument to allow access to non-static parts of your application. And so it is here. But you did not use this mechanism (removed the corresponding handling provided by the example code). So setting the CURLOPT_READDATA option is useless in your code and also wrong (the argument must be a pointer but you are passing lines_read which is probably an int).

With C++ classes, usually a pointer to the class intance is passed to the callback function. Then you have access to the class members from within the static callback function. Adopting the example code for your case might be done in this way:

C++
class Process
{
    // ...
protected:
    int lines_read;
    static size_t processmail(void *ptr, size_t size, size_t nmemb, void *userp);
};


size_t Process::processmail(void *ptr, size_t size, size_t nmemb, void *userp)
{
    // Must pass 'this' pointer when setting CURLOPT_READDATA
    Process *self = reinterpret_cast<Process*>(userp);
    // ...
    const char *data = payload_text[self->lines_read];
    size_t len = data ? strlen(data) : 0;
    // Check for sufficient buffer size
    // This is missing in the libcurl example
    if (len > nmemb * size)
        len = 0;
    if (len)
    {
        memcpy(ptr, data, len);
        self->lines_read++;
    }
    return len;
}

void Process::sendmail(std::string mail)
{
    lines_read = 0;
    // ...
    curl_easy_setopt(curl, CURLOPT_READDATA, this);
    // ...
}


[EDIT]
Answering below comment and extending solution about an additional bug I did not recognised initially.

The line
std::string &statistics = *(static_cast<std::string*>(userp));
is not working with the above solution and wasn't working with the initial code. The casting must be according to the type passed with CURLOPT_READDATA.

When using my solution passing the class pointer it should be something like:
std::string &statistics = self->statistics;
when statistics is a Process class member of type string.

[/EDIT]
 
Share this answer
 
v2
Comments
Member 12890589 11-Jan-17 9:37am    
@Jochen Arndt - Thanks for your solution. After I implement your solution, I receive an exception "(msvcr120d.dll) in SampleApp.exe: 0xC0000005: Access violation reading location 0x0000000000000000.". It redirects to iosfwd.h file. static const _Elem *__CLRCALL_OR_CDECL find(const _Elem *_First, size_t _Count,
const _Elem& _Ch)
{ // look for _Ch in [_First, _First + _Count)
return (_Count == 0 ? (const _Elem *)0
: (const _Elem *)_CSTD memchr(_First, _Ch, _Count));
}
Please help.
Jochen Arndt 11-Jan-17 9:49am    
See my updated solution.
Member 12890589 11-Jan-17 10:36am    
@Jochen Arndt. Thank you so much for your kind response. I receive the mail body like follows.

To: sampleuser1@hushmail.com
From: sampleuser@hushmail.com
Subject: Analysis

This is just a test message.

A:14%
B:89%
C:124.

But the subject is still missing. All the content displayed only on mail body.
Jochen Arndt 11-Jan-17 10:56am    
You are welcome.

What is missing?
Your above output looks fine (the subject is there).

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900