How to set mail body as html in curl? - c++

I need to send html table as email body. I just did the below to mention content type as html, but it did not work.
headers = curl_slist_append(headers, "Content-Type: text/html");
/* pass our list of custom made headers */
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
I couldn't find an example from the library site.

CURLOPT_HTTPHEADER will not work with any of the SMTP options (CURLOPT_MAIL_FROM, CURLOPT_MAIL_RCPT, CURLOPT_MAIL_AUTH). Instead you need to use CURLOPT_READFUNCTION.
/* Disclaimer: untested code */
char *msg = "To: bob#example.com\r\n"
"From: alice#example.com\r\n"
"Content-Type: text/html; charset=us-ascii\r\n"
"Mime-version: 1.0\r\n"
"\r\n"
"<html><head>\r\n"
"<meta http-equiv=\"Content-Type\" content="text/html; charset=us-ascii\">\r\n"
"</head><body>\r\n"
"<p>Hi Bob</p>\r\n"
"</body></html>\r\n"
size_t callback(char *buffer, size_t size, size_t nitems, void *instream) {
/* you actually need to check that buffer <= size * nitems */
strcat(buffer, msg);
return strlen(buffer);
}
curl_easy_setopt(curl, CURLOPT_READFUNCTION, callback);
curl_easy_perform(curl);
The documentation for CURLOPT_READFUNCTION has more info. Although, if you're already sending plain text emails, you have been there.
The only real "trick" here that is not presented in Sending Mail Through Curl linked by sameerkn is that you simply dump the Content-Type header inside the email buffer. There is no clever header setting like with HTTP.
Also: i'm not sure whether you need a Content-Transfer-Encoding header, i've set the charset above to us-ascii but things like utf-8 might need transfer encoding.

curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); will set the HTTP Protocol Header in your request.
The header which you are showing applies to E-Mail Data (Header section).
E-Mail Data Format: (It has 2 sections, Header and Body separated by blank line)
Header: value
Header: value
Content-Type: text/html; charset="UTF-8"
//**********************// << this is a blank line between Header and Body
Body Of Mail
Does your email contains only HTML?
Try adding following header to Email Headers as well: Content-Transfer-Encoding
Content-Transfer-Encoding: quoted-printable
Content-Type: text/html; charset="UTF-8"
quoted-printable is an encoding done to your HTML data. You can encode data as base64 as well.
Content-Transfer-Encoding: base64
**EDIT: If you are trying to send mail using curl then please refer
Send Mail Through CURL

Related

Dropbox API Post API gives response Something went wrong

I'm trying to use Dropbox API to get some metadata info of a file inside my dropbox.
Here is my post code
std::ostringstream stream;
curl_slist* headers = NULL;
CURL* curl = curl_easy_init();
char data[50];
snprintf(data, sizeof(data), "{\"path\":\"%s\"}", "/3.png");
curl_easy_setopt(curl, CURLOPT_URL, "https://api.dropboxapi.com/2/files/get_metadata");
headers = curl_slist_append(headers, "Authorization: <MY TOKEN>");
headers = curl_slist_append(headers, "\"Content-Type\":\"application/json\"");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_data);
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &stream);
/* size of the POST data */
curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, 30L);
/* pass in a pointer to the data - libcurl will not copy */
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, R"({"path":"/3.png"})"); //Tried data char array it doesn't work too.
CURLcode res = curl_easy_perform(curl);
if (res != CURLE_OK)
return 0;
/* convert stream to string format */
std::string output = stream.str();
curl_easy_cleanup(curl);
It returns HTTP 400 code
Thats the error I get after http post with curllib
<!DOCTYPE html>
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Dropbox</title>
<link href="https://cfl.dropboxstatic.com/static/metaserver/static/css/error.css" rel="stylesheet" type="text/css"/>
<link rel="shortcut icon" href="https://cfl.dropboxstatic.com/static/metaserver/static/images/favicon.ico"/>
</head>
<body>
<div class="figure">
<img src="https://cfl.dropboxstatic.com/static/metaserver/static/images/illustration_catalog/sickbox-illo_m1.png" srcset="https://cfl.dropboxstatic.com/static/metaserver/static/images/illustration_catalog/sickbox-illo_m1#2x.png 2x" alt="Error: 5xx"/>
</div>
<div id="errorbox">
<h1>Error</h1>Something went wrong. Don't worry, your files are still safe and the Dropboxers have been notified. Check out our Help Center and forums for help, or head back to home.
</div>
On PostMan it gives good response but in my C++ code it gives me error as you can see on above
Http web request body should be something like this
{
"path": "/3.png"
}
Here is response that I get from PostMan
{
".tag": "file",
"name": "3.png",
"path_lower": "/3.png",
"path_display": "/3.png",
"id": "id:kVJQZOYYiMsAAAAAAAAABg",
"client_modified": "2023-02-01T18:54:24Z",
"server_modified": "2023-02-01T18:54:24Z",
"rev": "015f3a7fa16a9c100000002912dfcc0",
"size": 5160,
"is_downloadable": true,
"content_hash": "feb3516ea07bab6053eecc7367ee9c282846f7bc17751b2819b85aa0f3ddefb5"
}
This line:
headers = curl_slist_append(headers, "\"Content-Type\":\"application/json\"");
Looks suspicous with all the inlined quotes around it.
Shouldn't it just be:
headers = curl_slist_append(headers, "Content-Type: application/json");
What you should do is get a tool like Fiddler, Charles, or similar HTTP capture proxy tool and compare the request/response sent by your application and compare it to the one sent by Postman. I think you'll see a discrepancy or two if the above doesn't fix it.

How to remove Accept from the http header in libcurl

Libcurl is putting Accept on the http header with the default value Accept: */*.
I want to avoid libcurl putting Accept in the http header. How I can do that?
You set a header with no "contents" on the right of the colon to remove it from libcurl's request (see the CURLOPT_HTTPHEADER docs):
struct curl_slist *chunk = NULL;
chunk = curl_slist_append(chunk, "Accept:");
res = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, chunk);
res = curl_easy_perform(curl);
For a slightly more complete example in C using custom headers, see httpcustomheader.c

using libcurl to call Amazon s3 RESTful service

I am writing a piece of c++ code with libcurl to call Amazon s3 RESTful service as follows:
void SampleOfS3Get()
{
//Init curl
curl_global_init(CURL_GLOBAL_ALL);
CURL* curlHandle = curl_easy_init();
//Init var
char* curlErrStr = (char*)malloc(CURL_ERROR_SIZE);
curl_slist* httpHeaders = NULL;
const char* date = getDateForHeader();
httpHeaders = curl_slist_append(httpHeaders, "Host: s3.amazonaws.com");//Set Host
httpHeaders = curl_slist_append(httpHeaders, date);//Set Date
httpHeaders = curl_slist_append(httpHeaders, getAuthorizationForHeader("AKIAISZALBSY-----XGQ","tIzCC----------/Jsn5KqTfuCAWyD1eyeOKStx0",date));//Set authorization
//Execute
if(curlHandle)
{
curl_easy_setopt(curlHandle, CURLOPT_VERBOSE, CURLOPT_STDERR);//Set verbose mode
curl_easy_setopt(curlHandle, CURLOPT_FOLLOWLOCATION,1);//Set automaticallly redirection
curl_easy_setopt(curlHandle, CURLOPT_MAXREDIRS,1);//Set max redirection times
curl_easy_setopt(curlHandle, CURLOPT_ERRORBUFFER, curlErrStr);//Set error buffer
curl_easy_setopt(curlHandle, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);//Set http version 1.1
curl_easy_setopt(curlHandle, CURLOPT_HEADER, httpHeaders);//Set headers
curl_easy_setopt(curlHandle, CURLOPT_URL, "http://s3.amazonaws.com/");//Set URL
CURLcode curlErr = curl_easy_perform(curlHandle);//Perform
if(curlErr)
{
cout<<curl_easy_strerror(curlErr)<<endl;
}
//Output redirection url
if(CURLE_OK == curlErr)
{
char *url;
curlErr = curl_easy_getinfo(curlHandle, CURLINFO_EFFECTIVE_URL, &url);
if((CURLE_OK == curlErr) && url)
cout<<"CURLINFO_EFFECTIVE_URL: "<<url<<endl;
}
/* Clean-up libcurl */
curl_global_cleanup();
}
}
This function calls the "GET SERVICE" to get the list of all buckets for a specified user.But the HTTP response of this HTTP request turns out to be "a temporary redirect to http://aws.amazon.com/s3" with http state code 307.
Then I find it in the official document which implies that caller should handle the redirection himself,so I add CURLOPT_FOLLOWLOCATION attribute as well.Then the result turns out to be a webpage content of amazon s3.
More details:http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAuthentication.html?r=1821
When I use the example accessID and accessKey in the above link,i get the right signature as "Example List All My Buckets" shows.It confused me that the server redirect my request instead of returning the expected all bucket list of my own(using my own accessID and accessKey).
Somebody encounter the similar problem like mine?SOS...
You should really start by reading http://docs.aws.amazon.com/AmazonS3/latest/dev/RESTAPI.html first, as your current code contains many issues. Especially make sure you fully understand how Signing and Authenticating REST Requests work.
This small C++ project seems to do cURL based File PUTs to AWS S3.
with CMake, one can generate VC++ Project/solutions and build it into .LIB static library, or, use it as source code, in your VC++ Solution.
I used it in a VC++ 2013 MFC Project.
Hope it helps.
https://github.com/cedricve/AWS-S3-Cpp-REST-API

send http requests, keep session alive: C/C++ with cURL(axus camera)

Ive a problem and i cant figure at all how i can manage to solve the following problem:
I would like to send multiple http request to an axis camera.
Here's my code:
#include <stdio.h>
#include <curl/curl.h>
int main(void)
{
CURL *curl;
CURLcode res;
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_URL, "http:/root:309#IPADDRESS");
/* example.com is redirected, so we tell libcurl to follow redirection */
// curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
res=curl_easy_perform(curl);
curl_easy_setopt(curl, CURLOPT_URL, "http:/IPADDRESS/axis-cgi/com/ptz.cgi?move=left");
/* Perform the request, res will get the return code */
res = curl_easy_perform(curl);
/* Check for errors */
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
/* always cleanup */
curl_easy_cleanup(curl);
}
return 0;
}
All i want to do in this example, is to keep my session alive after being logged to the IPaddress, and then send the order "move=left" to this very ip address.
When i execute this program, i got those messages:
<HTML>
<HEAD>
<META HTTP-EQUIV="Expires" CONTENT="Tue, 01 Jan 1980 1:00:00 GMT">
<META HTTP-EQUIV="Pragma" CONTENT="no-cache">
<META HTTP-EQUIV="Cache-Control" CONTENT="no-cache">
<META HTTP-EQUIV="Refresh" CONTENT="0; URL=/view/index.shtml">
Your browser has JavaScript turned off.<br>For the user interface to work effectively, you must enable JavaScript in your browser and reload/refresh this page.
</noscript>
</HEAD>
<BODY>
</BODY>
</HTML>
<HTML><HEAD><TITLE>401 Unauthorized</TITLE></HEAD>
<BODY><H1>401 Unauthorized</H1>
Your client does not have permission to get URL /axis-cgi/com/ptz.cgi from this server.
</BODY></HTML>
I assume that i wasnt even logged to the ipaddress...
I never really used this kind of method before... Can you help me with this?
Thank you a lot.
You need to add these two options:
curl_easy_setopt(curl, CURLOPT_COOKIEFILE, "cookie.txt");
curl_easy_setopt(curl, CURLOPT_COOKIEJAR, "cookie.txt");
From documentation:
CURLOPT_COOKIEFILE
Pass a pointer to a zero terminated string as parameter. It should
contain the name of your file holding cookie data to read. The cookie
data may be in Netscape / Mozilla cookie data format or just regular
HTTP-style headers dumped to a file.
Given an empty or non-existing file or by passing the empty string
(""), this option will enable cookies for this curl handle, making it
understand and parse received cookies and then use matching cookies in
future requests.
If you use this option multiple times, you just add more files to
read. Subsequent files will add more cookies.
CURLOPT_COOKIEJAR
Pass a file name as char *, zero terminated. This will make libcurl
write all internally known cookies to the specified file when
curl_easy_cleanup(3) is called. If no cookies are known, no file will
be created. Specify "-" to instead have the cookies written to stdout.
Using this option also enables cookies for this session, so if you for
example follow a location it will make matching cookies get sent
accordingly.
If the cookie jar file can't be created or written to (when the
curl_easy_cleanup(3) is called), libcurl will not and cannot report an
error for this. Using CURLOPT_VERBOSE or CURLOPT_DEBUGFUNCTION will
get a warning to display, but that is the only visible feedback you
get about this possibly lethal situation
Read more at: http://curl.haxx.se/libcurl/c/curl_easy_setopt.html

how to parse HTTP POST(file upload) stream?

I am using actionscript engine to upload a file, the engine will select the file and send the file over network thru HTTP POST command, the document says the POST message is like:
POST /handler.cfm HTTP/1.1
Accept: text/*
Content-Type: multipart/form-data;
boundary=----------Ij5ae0ae0KM7GI3KM7ei4cH2ei4gL6
User-Agent: Shockwave Flash
Host: www.example.com
Content-Length: 421
Connection: Keep-Alive
Cache-Control: no-cache
------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
Content-Disposition: form-data; name="Filename"
MyFile.jpg
------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
Content-Disposition: form-data; name="photo"; filename="MyFile.jpg"
Content-Type: application/octet-stream
FileDataHere
------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7
Content-Disposition: form-data; name="Upload"
Submit Query
------------Ij5GI3GI3ei4GI3ei4KM7GI3KM7KM7--
In server side I have a C++ program listens on port 80 and parse the POST message. I only want the file name and file data. How to decode the file data using c++, is it base64 encoded and is there a library can do it for me? I want to decode the binary, and write it to the file, thanks!
No, there is no encoding. The body of each subpart of the multipart message is included as verbatim bytes. Consequently you have to be careful to choose a boundary string that doesn't occur anywhere in the file data.
To parse a multipart/form-data form submission you will enough of a MIME parser to parse the headers, pick out parameters you want like boundary and name, and split the received message by the boundary string. This is not completely trivial, so you may want to consider existing libraries.
(Unfortunately, what browsers actually do in HTTP differs a bit from the standard MIME rules outlined in RFC 1341. In particular, field name and filename parameters tend to include non-ASCII characters and unescaped quotes. But if you are generating the POST yourself hopefully you can steer clear of these areas of contention.)
In the absence of a "Content_Transfer_Encoding" header, it is assumed data is encoded in "7bit" (RFC 1521; RFC 1867; RFC 2616).
I don't know if tere's a C library to parse / decode HTTP POSTs. I'm pretty sure there are though :)
You can upload unlimited size of data/file. Try this solution
const char* ctype = "multipart/form-data; boundary=----WebKitFormBoundaryfm9qwXVLSbFKKR88";
size_t content_length = 1459606;
http_payload* hp = new http_payload(ctype, content_length);
if (hp->is_multipart()) {
int ret = hp->read_all("C:\\temp\\");
if (ret < 0) {
std::cout << hp->get_last_error() << std::endl;
hp->clear();
}
else {
std::string dir_str("C:\\upload_dir\\");
ret = hp->read_files([&dir_str](http_posted_file* file) {
std::string path(dir_str.c_str());
path.append(file->get_file_name());
file->save_as(path.c_str());
file->clear(); path.clear();
std::string().swap(path);
});
hp->clear();
std::cout << "Total file uploaded :" << ret << std::endl;
}
}
else {
int ret = hp->read_all();
if (ret < 0) {
std::cout << hp->get_last_error() << std::endl;
hp->clear();
}
else {
std::cout << "Posted data :" << hp->get_body() << std::endl;
hp->clear();
}
}
https://github.com/safeonlineworld/web_jsx/blob/0d08773c95f4ae8a9799dbd29e0a4cd84413d108/src/web_jsx/core/http_payload.cpp#L402