Click here to Skip to main content
15,358,440 members
Please Sign up or sign in to vote.
1.44/5 (2 votes)
I want to send an email with attachment from c++ using libcurl( http://curl.haxx.se/[^]).
I'm able to send an email successfully from gmail server but don't know how to send with attachment.
The code I'm using is as follows:

C++
#include <stdio.h>
#include <string.h>
#include <curl/curl.h>

#define FROM    "<xxxx@gmail.com>"
#define TO      "<xxxx@gmail.com>"

static const char *payload_text[] = {
  "To: " TO "\r\n",
  "From: " FROM "\r\n",
  "Subject: SMTP TLS example message\r\n",
  NULL
};

struct upload_status {
  int lines_read;
};

static size_t payload_source(void *ptr, size_t size, size_t nmemb, void *userp)
{
  struct upload_status *upload_ctx = (struct upload_status *)userp;
  const char *data;

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

  data = payload_text[upload_ctx->lines_read];

  if(data) {
    size_t len = strlen(data);
    memcpy(ptr, data, len);
    upload_ctx->lines_read++;

    return len;
  }

  return 0;
}

int main(void)
{
  CURL *curl;
  CURLcode res = CURLE_OK;
  struct curl_slist *recipients = NULL;
  struct upload_status upload_ctx;

  upload_ctx.lines_read = 0;

  curl = curl_easy_init();
  if(curl) {
    curl_easy_setopt(curl, CURLOPT_USERNAME, "xxxx");
    curl_easy_setopt(curl, CURLOPT_PASSWORD, "xxxx");
    curl_easy_setopt(curl, CURLOPT_URL, "smtp://smtp.gmail.com:587");
    curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL);
    curl_easy_setopt(curl, CURLOPT_CAINFO, "google.pem");
    curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM);
    recipients = curl_slist_append(recipients, TO);
    //curl_easy_setopt(curl, CURLOPT_FILE, "edgE0DF.tmp"); 
    curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
    curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source);
    curl_easy_setopt(curl, CURLOPT_READDATA, &upload_ctx);
    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);
  }
  system("pause");
  return (int)res;
}


Any suggestion is appreciated.
Posted
Updated 13-Jun-18 2:29am

The code bellow uses Imagemagick++http://www.imagemagick.org/Magick++/[^] to base64 encode the image.

C++
#include <Magick++.h>
#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
#include <string>

#define FROM    "<xxxx@gmail.com>"
#define TO      "<xxxx@gmail.com>"
#define FILENAME "pic.jpg"
 
static const int CHARS= 76;			//Sending 54 chararcters at a time with \r , \n and \0 it becomes 57 and its encoded length will be 76 by the formula string_length/3*4
static const int ADD_SIZE= 7;			// ADD_SIZE for TO,FROM,SUBJECT,CONTENT-TYPE,CONTENT-TRANSFER-ENCODING,CONETNT-DISPOSITION and \r\n
static const int SEND_BUF_SIZE= 54;
static char (*fileBuf)[CHARS] = NULL;
 
struct fileBuf_upload_status 
{
  int lines_read;
};
 
size_t read_file()
{
	Magick::Image img(FILENAME);
	Magick::Blob blob;
	img.write( &blob );
	std::string encoded_buf = blob.base64();
	
	size_t encoded_buf_len = encoded_buf.size();
	size_t len(0),buffer_size(0);
	int no_of_rows = (int)ceil((double)encoded_buf.size()/SEND_BUF_SIZE) ;
	int read(0);
	fileBuf = new char[ADD_SIZE + no_of_rows + 1][CHARS];	//Extra row for our special character to be used in conditional statements,here ""
											// ADD_SIZE for TO,FROM,SUBJECT,CONTENT-TYPE,CONTENT-TRANSFER-ENCODING,CONETNT-DISPOSITION and \r\n
 
	strcpy(fileBuf[len++],"To: " TO "\r\n");
	buffer_size += strlen(fileBuf[len-1]) + 1;	// 1 for \0
	strcpy(fileBuf[len++],"From: " FROM "\r\n");
	buffer_size += strlen(fileBuf[len-1]) + 1;
	strcpy(fileBuf[len++],"Subject: SMTP TLS example message\r\n");
	buffer_size += strlen(fileBuf[len-1]) + 1;
	strcpy(fileBuf[len++],"Content-Type: image/jpeg; name=\"" FILENAME "\"\r\n");
	buffer_size += strlen(fileBuf[len-1]) + 1;
	strcpy(fileBuf[len++],"Content-Transfer-Encoding: base64\r\n");
	buffer_size += strlen(fileBuf[len-1]) + 1;
	strcpy(fileBuf[len++],"Content-Disposition: attachment; filename=\"" FILENAME "\"\r\n");
	buffer_size += strlen(fileBuf[len-1]) + 1;
	strcpy(fileBuf[len++],"\r\n");
	buffer_size += strlen(fileBuf[len-1]) + 1;
	
	int pos = 0;
	std::string sub_encoded_buf;
	for (; len < no_of_rows + ADD_SIZE; ++len)
	{		
		if (pos*54 <= encoded_buf_len)
		{
			sub_encoded_buf = encoded_buf.substr(pos*54,54);
			pos++;
 		sub_encoded_buf += "\r\n";
		memcpy(fileBuf[len],sub_encoded_buf.c_str(),sub_encoded_buf.size());
                buffer_size += sub_encoded_buf.size() ;	// 1 for \0
		}
	}
        strcpy(fileBuf[len],"");

// The following code prints the structure of the email being sent.
//	
//	for (int i=0;i<no_of_rows + ADD_SIZE;++i)
//	{
//		printf("%s",fileBuf[i]);
//	}
	return buffer_size;
}
 

static size_t fileBuf_source(void *ptr, size_t size, size_t nmemb, void *userp)
{
	struct fileBuf_upload_status *upload_ctx = (struct fileBuf_upload_status *)userp;
	const char *fdata;
 
	if((size == 0) || (nmemb == 0) || ((size*nmemb) < 1)) 
	{
		return 0;
	}
 
	fdata = fileBuf[upload_ctx->lines_read];
 
	if(strcmp(fdata,"")) 
	{
		size_t len = strlen(fdata);
		memcpy(ptr, fdata, len);
		upload_ctx->lines_read++;
		return len;
	}
	return 0;
}
 
int main(void)
{
  CURL *curl;
  CURLcode res = CURLE_OK;
  struct curl_slist *recipients = NULL;
  struct fileBuf_upload_status file_upload_ctx;
  size_t file_size(0);
 
  file_upload_ctx.lines_read = 0;
 
  curl = curl_easy_init();
  file_size = read_file();
  if(curl) 
  {
    curl_easy_setopt(curl, CURLOPT_USERNAME, "xxxx");
    curl_easy_setopt(curl, CURLOPT_PASSWORD, "xxxx");
    curl_easy_setopt(curl, CURLOPT_URL, "smtp://smtp.gmail.com:587");
    curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL);
    //curl_easy_setopt(curl, CURLOPT_CAINFO, "google.pem");
    curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM);
    recipients = curl_slist_append(recipients, TO);
    curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
 
	curl_easy_setopt(curl, CURLOPT_INFILESIZE, file_size); 
	curl_easy_setopt(curl, CURLOPT_READFUNCTION, fileBuf_source);
    curl_easy_setopt(curl, CURLOPT_READDATA, &file_upload_ctx);
    curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
    curl_easy_setopt(curl, CURLOPT_VERBOSE, 0);
 
    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);
  }
  delete[] fileBuf;
  return (int)res;
}


Use the following command to compile
$ IM_CXXFLAGS=$(Magick++-config --cxxflags)
$ IM_LDFLAGS=$(Magick++-config --ldflags)
$ g++ $IM_CXXFLAGS $IM_LDFLAGS main.cpp -lcurl
   
v4
Comments
deepak2431 11-Mar-20 6:25am
   
I am unable to run this code. Getting reference error for MagicK library. Can you help me please?
I fixed up this code so you can send attachments of any file type. I have no problem sending a JPG thats 165kb @ 1280x1024 resolution. I compiled this in MSVS2010. This code only needs the libCurl library, it has its own Base64 encoding function, it does not require Magick++.


/* C++ TLS SMTP eMail File Send example using libCurl. This code demonstrates how to use libCurl to connect to GMail's TLS SMTP
   Server and send an eMail with a Base64 encoded attachment. I've used Microsoft Visual Studio 2010 to compile this code. You'll
   need to download and install the C++ libCurl library for this to compile correctly. I've uploaded a ready to use compiled cURL
   library here: https://docs.google.com/uc?id=0BzOJ0-XuaQSTU3RHQkRfbVpmcnM&export=download Download this ZIP and extract the
   contents anywhere on your computer. Quick How-To on using MSVS2010 to compile this:
   1. Open Visual Studio 2010, click File -> New -> Project.
   2. On the left side select Visual C++ -> General -> Empty Project (Type in a Name and click OK)
   3. In the Solution Explorer window Right Click 'Source Files' folder and select Add -> New Item
   4. Select 'C++ File (.cpp)' (Type in a Name and click OK)
   5. Copy and Paste this code into the newly created .cpp file and Click Into the int Main() function
   6. Click Project menu -> 'ProjectName Properties' (at the bottom)
   7. On the left select Configuration Properties -> VC++ Directories
   8. On the Right select Include Directories and add libCurl's include directory
   9. On the Right select Library Directories and add libCurl's Library directory (Static-Debug folder)
  10. On the left select C/C++ -> Preprocessor and add 'CURL_STATICLIB' (no quotes) to the Preprocessor Definitions
  11. Now you are ready to Compile, Click Build -> Build Solution
*/
 
#include <iostream>
#include <conio.h>
#include <curl/curl.h>
 
#ifdef _DEBUG
        #pragma comment(lib, "libcurl_a_debug.lib") //cURL Debug build
#else
        #pragma comment(lib, "libcurl_a.lib")
#endif
 
#pragma warning(disable: 4996)  //Disable Function or Variable may be unsafe warning
 
#define FROM    "<xxxxx@gmail.com>"
#define TO      "<xxxxx@gmail.com>"
#define FILENAME "c:/1.rar"
 
static const int CHARS= 76;     //Sending 54 chararcters at a time with \r , \n and \0 it becomes 57
static const int ADD_SIZE= 7;   // ADD_SIZE for TO,FROM,SUBJECT,CONTENT-TYPE,CONTENT-TRANSFER-ENCODING,CONETNT-DISPOSITION and \r\n
static const int SEND_BUF_SIZE= 54;
static char (*fileBuf)[CHARS] = NULL;
static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 
using namespace std;
 
bool LARGEFILE = false; /*For Percent*/
int status = 0;   /*For Percent*/
int percent2 = 0; /*For Percent*/
int percent3 = 0; /*For Percent*/
int percent4 = 0; /*For Percent*/
int percent5 = 0; /*For Percent*/
void LargeFilePercent(int rowcount)
{
        //This is for displaying the percentage
        //while encoding larger files
        int percent = rowcount/100;
 
        if(LARGEFILE == true) {
                status++;
                percent2++;
                if(percent2 == 18) {
                        percent3++;
                        percent2 = 0;
                }
                if(percent3 == percent){
                        percent4++;
                        percent3 = 0;
                }
                if(percent4 == 10){
                        system("cls");
                        cout << "Larger Files take longer to encode, Please be patient." << endl
                             << "Otherwise push X to exit program now." << endl << endl
                             << "(Push Anykey to Continue)" << endl
                             << endl << "Encoding " FILENAME " please be patient..." << endl;
                        cout << percent5 << "%";
                        percent5 += 10;
                        percent4 = 0;
                }
                if(status == 10000) {
                        if(percent5 == 0){cout << " 0%"; percent5 = 10;}
                        cout << ".";
                        status = 0;
                }
        }
}
 
void encodeblock(unsigned char in[3], unsigned char out[4], int len)
{
    out[0] = cb64[ in[0] >> 2 ];
    out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ];
    out[2] = (unsigned char) (len > 1 ? cb64[ ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '=');
    out[3] = (unsigned char) (len > 2 ? cb64[ in[2] & 0x3f ] : '=');
}
 
void encode(FILE *infile, unsigned char *output_buf, int rowcount/*For Percent*/)
{
    unsigned char in[3], out[4];
        int i, len;
        *output_buf = 0;
 
    while(!feof(infile)) {
        len = 0;
        for(i = 0; i < 3; i++) {
            in[i] = (unsigned char) getc(infile);
            if(!feof(infile) ) {
                len++;
            }
            else {
                in[i] = 0;
            }
        }
        if(len) {
            encodeblock(in, out, len);
            strncat((char*)output_buf, (char*)out, 4);
        }
            LargeFilePercent(rowcount); //Display encoded file percent /*For Percent*/
        }
}
 
 
struct fileBuf_upload_status
{
  int lines_read;
};
 
size_t read_file()
{
        FILE* hFile=NULL;
        size_t fileSize(0),len(0),buffer_size(0);
        char key = ' ';
 
        //Open the file and make sure it exsits
        hFile = fopen(FILENAME,"rb");
        if(!hFile) {
                cout << "File not found!!!" << endl;
                _getch();
                exit (EXIT_FAILURE);
        }
 
        //Get filesize
        fseek(hFile,0,SEEK_END);
        fileSize = ftell(hFile);
        fseek(hFile,0,SEEK_SET);
   
        //Check Filesize, if larger then 256kb prompt user
        if(fileSize > 256000/*bytes*/){
                cout << "Larger Files take longer to encode, Please be patient." << endl
                     << "Otherwise push X to exit program now." << endl << endl
                     << "(Push Anykey to Continue)" << endl;
                key = _getch();
                if(tolower(key) == 'x')
                        exit (EXIT_SUCCESS);
                LARGEFILE = true; /*For Percent*/
        }
        cout << endl << "Encoding " FILENAME " please be patient..." << endl;
 
        //Calculate the number of rows in Base64 encoded string
        //also calculate the size of the new char to be created
        //for the base64 encode string
        int no_of_rows = fileSize/SEND_BUF_SIZE + 1;
        int charsize = (no_of_rows*72)+(no_of_rows*2);
 
        //Base64 encode image and create encoded_buf string
        unsigned char* b64encode = new unsigned char[charsize];
        *b64encode = 0;
        encode(hFile, b64encode, no_of_rows /*For Percent*/);
        string encoded_buf = (char*)b64encode;
 
        if(LARGEFILE == true) cout << endl << endl; /*For Percent*/
 
        //Create structure of email to be sent
        fileBuf = new char[ADD_SIZE + no_of_rows][CHARS];  //ADD_SIZE for TO,FROM,SUBJECT,CONTENT-TYPE,CONTENT-TRANSFER-
                                                           //ENCODING,CONETNT-DISPOSITION and \r\n
        strcpy(fileBuf[len++],"To: " TO "\r\n");
        buffer_size += strlen(fileBuf[len-1]);
        strcpy(fileBuf[len++],"From: " FROM "\r\n");
        buffer_size += strlen(fileBuf[len-1]);
        strcpy(fileBuf[len++],"Subject: SMTP TLS example message\r\n");
        buffer_size += strlen(fileBuf[len-1]);
        strcpy(fileBuf[len++],"Content-Type: application/x-msdownload; name=\"" FILENAME "\"\r\n");
        buffer_size += strlen(fileBuf[len-1]);
        strcpy(fileBuf[len++],"Content-Transfer-Encoding: base64\r\n");
        buffer_size += strlen(fileBuf[len-1]);
        strcpy(fileBuf[len++],"Content-Disposition: attachment; filename=\"" FILENAME "\"\r\n");
        buffer_size += strlen(fileBuf[len-1]);
        strcpy(fileBuf[len++],"\r\n");
        buffer_size += strlen(fileBuf[len-1]);
   
        //This part attaches the Base64 encoded string and
        //sets the Base64 linesize to 72 characters + \r\n
        int pos = 0;
        string sub_encoded_buf;
        for(int i = 0; i <= no_of_rows-1; i++)
        {
                sub_encoded_buf = encoded_buf.substr(pos*72,72);  //Reads 72 characters at a time
                sub_encoded_buf += "\r\n";                        //and appends \r\n at the end
                strcpy(fileBuf[len++], sub_encoded_buf.c_str());  //copy the 72 characters & \r\n to email
                buffer_size += sub_encoded_buf.size();            //now increase the buffer_size  
                pos++;                                            //finally increase pos by 1
        }
//////////////////////////////////////////////////////////////////////
// The following code prints the structure of the email being sent.//
//    printf("Images Base64 encoded string:\n\n\t\t\t std::string" //
//         "encoded_buf\n%s\n",encoded_buf.c_str());               //
//    printf("\n\t\t\tStructure of Email being sent:\n");          //
//      for (int i=0;i<no_of_rows + ADD_SIZE;++i){                 //
//            printf("%s",fileBuf[i]); }                           //
//      printf("\nbuffer size: %d\n",buffer_size);                 //
/////////////////////////////////////////////////////////////////////
//    /* Push X to Exit the program after viewing                  //
//       the structure of the email */                             //
//    printf("Push X to exit program now, otherwise continue\n");  //
//       key = _getch();                                           //
//       if(tolower(key) == 'x')                                   //
//               exit (EXIT_SUCCESS);                              //
/////////////////////////////////////////////////////////////////////
 
        delete[] b64encode;
        return buffer_size;
}
 
 /*
  The fileBuf_source() is a function which CURL calls when it need to obtain data that will be uploaded to the server.
  Imagine that fileBuf_source() is something similar to fread(). When called it performs any voodoo-mumbo-jumbo that is needed,
  but in the end uploadable data must be stored in *ptr buffer, which is curl's internal buffer. For your in-memory buffer
  memcpy() will do just fine as body of fileBuf_source(), so you don't need real fread() at all.
 
  size * nmemb tells you how big buffer curl has reserved for a single chunk of data. The last void* is a pointer which was
  set by CURLOPT_READDATA option - it's a do-what-ever-you-need-with-it kind of pointer, so it can point to a structure
  containing data which you're uploading and a some additional info e.g. current progress.
  */
static size_t fileBuf_source(void *ptr, size_t size, size_t nmemb, void *userp)
{
        struct fileBuf_upload_status *upload_ctx = (struct fileBuf_upload_status *)userp;
        const char *fdata;
 
        if((size == 0) || (nmemb == 0) || ((size*nmemb) < 1))
        {
                return 0;
        }
 
        fdata = fileBuf[upload_ctx->lines_read];
 
        if(strcmp(fdata,""))
        {
                size_t len = strlen(fdata);
                memcpy(ptr, fdata, len);
                upload_ctx->lines_read++;
                return len;
        }
        return 0;
}
 
int main()
{
  CURL *curl;
  CURLcode res = CURLE_OK;
  struct curl_slist *recipients = NULL;
  struct fileBuf_upload_status file_upload_ctx;
  size_t file_size(0);
 
  file_upload_ctx.lines_read = 0;
 
  curl = curl_easy_init();
  file_size = read_file();
  if(curl)
  {
    curl_easy_setopt(curl, CURLOPT_USERNAME, "USERNAME@gmail.com");
    curl_easy_setopt(curl, CURLOPT_PASSWORD, "PASSWORD");
    curl_easy_setopt(curl, CURLOPT_URL, "smtp://smtp.gmail.com:587");
    curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL);
    //curl_easy_setopt(curl, CURLOPT_CAINFO, "google.pem");
    curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM);
    recipients = curl_slist_append(recipients, TO);
    curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
    curl_easy_setopt(curl, CURLOPT_INFILESIZE, file_size);
    curl_easy_setopt(curl, CURLOPT_READFUNCTION, fileBuf_source);
    curl_easy_setopt(curl, CURLOPT_READDATA, &file_upload_ctx);
    curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
    curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); //Dont display Curl Connection data Change 1L to 0
 
    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);
  }
  delete[] fileBuf;
  _getch();
  return (int)res;
}


Improved By:
-CellToolz
   
v9
Comments
CHill60 19-May-15 19:21pm
   
Only a year and a half late with what looks like spam
Member 11615836 21-May-15 9:27am
   
spam lol... Well the 2 solutions above this both didn't work very well. At least with my solution you can actually send attachments of any type or size. I figured I'd post it to help others out, i know it's a year and a half late but better late then never right? I truly hadn't meant for it to come off as spam, the code really does work now. I hope it helps someone out besides myself.
CHill60 21-May-15 9:43am
   
With the edits it doesn't look spammy any more. I agree it adds value
ansh_kumar 22-May-15 0:33am
   
Is the code working when you compile it as release version??
Member 11615836 27-May-15 14:31pm
   
Yeah it seems to be working fine for me when i compile it as a release. I've been able to send files of any size/type. Let me know if you have any problems...
ansh_kumar 27-May-15 23:08pm
   
The base64 method you are using is same as in solution 2. Moreover the no_of_rows in for loop in read_file is calculated before encoding the file whereas it has to be calculated after encoding the file so that all the encoded text is placed in fileBuf. See solution 3 how it is calculated after encoding the file. I think you were lucky with your file chosen.
Member 11615836 28-May-15 1:09am
   
No luck here, it works with every file I've thrown at it regardless of type or size. At 72 characters per line (b64 encoded linesize) you can calculate the number of rows by dividing the filesize by 54 + 1. In solution 7 the number of rows needs to be calculated beforehand so you can determine how large to allocate the b64encode buffer before loading it with the encoded text. The only reason I pass no_of_rows to the encode function is for displaying the encoded file percentage. I've checked to make sure all the encoded text is properly placed into fileBuf. Solution 7 works flawlessly, I've tested it thoroughly... Actually compare it to the other solutions, there are key differences.
the1russ 11-Feb-16 13:27pm
   
Hi,
I’ve been able to modify your example to include multiple attachments in an email but was trying to make it faster without much success. I have a couple questions…

1. Regarding SEND_BUF_SIZE = 54 Where does the “54” come from? I’ve tried larger numbers and the routine is much faster all the way to the end when it crashes.

2. When calculating the size of the char to use for the base64 encoded string, where does the number “72” come from? charsize = (no_of_rows*72)+(no_of_rows*2);
the1russ 11-Feb-16 13:34pm
   
never mind. I see 72 is the b64 encoded line size and just figured out the 72 comes from 54*(4/3). 4/3 being the expansion of encoded binary.
Member 11099894 24-Feb-16 10:41am
   
Hi, is it really necessary to encode to base64?

Can anyone help me to send email with text as well as attachment.

This code is not able to include text.

Please do help me asap..

And also help me with how to send multiple attachments...!!!

Thanx!!!
Lieven Samijn 27-Dec-16 8:00am
   
Hi, did you found the answer to your question? I am looking exactly the same (email with 5 jpg images as att. with CURL) So far using this example i can send 1 image but cannot find out how it works to send 5 images in 1 email. replay really appreciated.
Member 11134219 19-Dec-16 0:40am
   
I am getting problem while compiling above code getting fatal error: conio.h: No such file or directory #include <conio.h> is anybody tell me why this is so? and how to fix this?
ansh_kumar 19-Dec-16 7:21am
   
Don't include it. It no longer exists.
Member 11134219 20-Dec-16 1:12am
   
can we make the TO,FROM,CC dynamic?
ansh_kumar 20-Dec-16 2:43am
   
Of course you can. Just change the code accordingly.
Member 11134219 20-Dec-16 8:14am
   
can you help to make it dynamic? I tried to do it but failed to make the change.The *payload_text[] only takes the constant I tried to provide the String but is't work.can you help
ansh_kumar 20-Dec-16 8:22am
   
Put a scanf before `strcpy(fileBuf[len++],"To: " TO "\r\n");` now merge the two strings.
EdwardX2 19-May-17 20:53pm
   
Member 11615836 or anyone,
I'd like to use Solution 7 to send a PDF file, but it has no message body.

Adding lines to the 'Create structure of email to be sent' results in an error.

How can I add a text message body?
Member 13274757 23-Jun-17 0:48am
   
Did u find a way to add Message ?
Zeca do Pagode 15-May-21 10:26am
   
But how to include the body text?
After a very long observation and experimentation I finally found the solution.
It will be too long to give details of how this code work, so I'm simply putting the working code:

C++
#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
#include <math.h>

#define FROM    "<xxxx@gmail.com>"
#define TO      "<xxxx@gmail.com>"
#define FILENAME "pic.jpg"
 
static const int CHARS= 76;			//Sending 54 chararcters at a time with \r , \n and \0 it becomes 57 
static const int ADD_SIZE= 7;			// ADD_SIZE for TO,FROM,SUBJECT,CONTENT-TYPE,CONTENT-TRANSFER-ENCODING,CONETNT-DISPOSITION and \r\n
static const int SEND_BUF_SIZE= 54;
static char (*fileBuf)[CHARS] = NULL;
static const char b64_table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 
static void encodeblock( char *in, char *out, int len )
{
    out[0] = (unsigned char) b64_table[ (int)(in[0] >> 2) ];
    out[1] = (unsigned char) b64_table[ (int)(((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4)) ];
    out[2] = (unsigned char) (len > 1 ? b64_table[ (int)(((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6)) ] : '=');
    out[3] = (unsigned char) (len > 2 ? b64_table[ (int)(in[2] & 0x3f) ] : '=');
}

void base64_encode(char *input_buf, char *output_buf)
{
	char in[3], out[4];
	size_t len = strlen(input_buf);
	
	*output_buf = 0;
	for (size_t i=0; i<len; )
	{
		int buf3_len = 0;
		for (int j=0; j<3; ++j)
		{
			in[j] = input_buf[i++];
			if (i > len)
				in[j] = 0;
			else
				buf3_len++;
		}
		if (len>0)
		{
			encodeblock(in,out,buf3_len);
			strncat(output_buf, out, 4);
		}
	}
}
 
struct fileBuf_upload_status 
{
  int lines_read;
};
 
size_t read_file()
{
	FILE* hFile=NULL;
	size_t fileSize(0),len(0),buffer_size(0);
 
	//opening the file
	hFile = fopen(FILENAME,"rb");
	if (hFile == NULL)
		throw "File Does not exist.";
 
	//get file size
	fseek(hFile,0,SEEK_END);
	fileSize = ftell(hFile);
	fseek(hFile,0,SEEK_SET);
 
	//Checking file size
	if(fileSize > 1*1024)
	{}
 
	int no_of_rows = fileSize/SEND_BUF_SIZE + 1;
	int read(0);
	fileBuf = new char[ADD_SIZE + no_of_rows + 1][CHARS];	//Extra row for our special character to be used in conditional statements,here ""
											// ADD_SIZE for TO,FROM,SUBJECT,CONTENT-TYPE,CONTENT-TRANSFER-ENCODING,CONETNT-DISPOSITION and \r\n
 
	strcpy(fileBuf[len++],"To: " TO "\r\n");
	buffer_size += strlen(fileBuf[len-1]) + 1;	// 1 for \0
	strcpy(fileBuf[len++],"From: " FROM "\r\n");
	buffer_size += strlen(fileBuf[len-1]) + 1;
	strcpy(fileBuf[len++],"Subject: SMTP TLS example message\r\n");
	buffer_size += strlen(fileBuf[len-1]) + 1;
	strcpy(fileBuf[len++],"Content-Type: application/x-msdownload; name=\"" FILENAME "\"\r\n");
	buffer_size += strlen(fileBuf[len-1]) + 1;
	strcpy(fileBuf[len++],"Content-Transfer-Encoding: base64\r\n");
	buffer_size += strlen(fileBuf[len-1]) + 1;
	strcpy(fileBuf[len++],"Content-Disposition: attachment; filename=\"" FILENAME "\"\r\n");
	buffer_size += strlen(fileBuf[len-1]) + 1;
	strcpy(fileBuf[len++],"\r\n");
	buffer_size += strlen(fileBuf[len-1]) + 1;
 
	char* temp_buf = new char[SEND_BUF_SIZE + 4];	//taking extra size of 4 bytes
	size_t e_size = ceil(SEND_BUF_SIZE/3)*4 + 4;
	char* encoded_buf = new char[e_size];
	*encoded_buf = 0;
	
	for (; len < no_of_rows + ADD_SIZE; ++len)
	{
		read = fread(temp_buf,sizeof(char),SEND_BUF_SIZE,hFile);
		temp_buf[read] ='\0';
		base64_encode(temp_buf,encoded_buf);
		strcat(encoded_buf,"\r\n");
		memcpy(fileBuf[len],encoded_buf,strlen(encoded_buf)+1);
                buffer_size += strlen(encoded_buf) + 1;	// 1 for \0
	}
	strcpy(fileBuf[len],"");
        delete[] temp_buf;
	delete[] encoded_buf;
	return buffer_size;
}
 
 /*
  The fileBuf_source() is a function which CURL calls when it need to obtain data that will be uploaded to the server. 
  Imagine that fileBuf_source() is something similar to fread(). When called it performs any voodoo-mumbo-jumbo that is needed, 
  but in the end uploadable data must be stored in *ptr buffer, which is curl's internal buffer. For your in-memory buffer 
  memcpy() will do just fine as body of fileBuf_source(), so you don't need real fread() at all.

size * nmemb tells you how big buffer curl has reserved for a single chunk of data. The last void* is a pointer which was 
set by CURLOPT_READDATA option - it's a do-what-ever-you-need-with-it kind of pointer, so it can point to a structure 
containing data which you're uploading and a some additional info e.g. current progress.
  */
static size_t fileBuf_source(void *ptr, size_t size, size_t nmemb, void *userp)
{
	struct fileBuf_upload_status *upload_ctx = (struct fileBuf_upload_status *)userp;
	const char *fdata;
 
	if((size == 0) || (nmemb == 0) || ((size*nmemb) < 1)) 
	{
		return 0;
	}
 
	fdata = fileBuf[upload_ctx->lines_read];
 
	if(strcmp(fdata,"")) 
	{
		size_t len = strlen(fdata);
		memcpy(ptr, fdata, len);
		upload_ctx->lines_read++;
		return len;
	}
	return 0;
}
 
int main(void)
{
  CURL *curl;
  CURLcode res = CURLE_OK;
  struct curl_slist *recipients = NULL;
  struct fileBuf_upload_status file_upload_ctx;
  size_t file_size(0);
 
  file_upload_ctx.lines_read = 0;
 
  curl = curl_easy_init();
  file_size = read_file();
  if(curl) 
  {
    curl_easy_setopt(curl, CURLOPT_USERNAME, "xxxx");
    curl_easy_setopt(curl, CURLOPT_PASSWORD, "xxxx");
    curl_easy_setopt(curl, CURLOPT_URL, "smtp://smtp.gmail.com:587");
    curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL);
    //curl_easy_setopt(curl, CURLOPT_CAINFO, "google.pem");
    curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM);
    recipients = curl_slist_append(recipients, TO);
    curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
 
	curl_easy_setopt(curl, CURLOPT_INFILESIZE, file_size); 
	curl_easy_setopt(curl, CURLOPT_READFUNCTION, fileBuf_source);
    curl_easy_setopt(curl, CURLOPT_READDATA, &file_upload_ctx);
    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);
  }
  delete[] fileBuf;
  return (int)res;
}
   
v5
Comments
Member 11248359 20-Nov-14 21:59pm
   
Hi, can I ask if attachment of image is possible for this code?

I have tried to attachment image of different formats (.jpg, .png). It did manage to send the image attachment out. But the receiver is unable to open the image. Hope you can help. Thank you
ansh_kumar 21-Nov-14 0:39am
   
Can you tell me the size of the file you are trying to send perhaps send me the image file you are trying to email.
Member 11248359 21-Nov-14 1:36am
   
I tried to send an image which is around 40KB. I tried using any images I save from google. But it does not work.
ansh_kumar 21-Nov-14 9:03am
   
Actually this code is for sending text file only but I can modify it to send JPG file. Wait till tomorrow, I'll be coming with a solution. :)
ansh_kumar 22-Nov-14 3:42am
   
I changed the code to send jpeg file. See my next solution below.
Tran Toan 2-Feb-15 22:51pm
   
Hi @ansh_kumar!
I tested code in the Solution 2 part.
But when I sent a text file, I can receive and open it. But about Image file, I cant Open it when I received it on destination mail.
Can you help me some things about that?
Thanks!!!
ansh_kumar 3-Feb-15 2:01am
   
Can you give me the file you are trying to send ?
Tran Toan 3-Feb-15 3:57am
   
Thanks for your replied.
I dont know your email, whats your mail?
Its urgent for me.
Thanks
Tran Toan 4-Feb-15 1:50am
   
@ansh_kumar
I sent to you my file. Please check it.
Thanks!!!
ansh_kumar 4-Feb-15 2:08am
   
You are using the wrong code.
For sending the image file use the code above it, which uses Imagemagick++.
Tran Toan 4-Feb-15 2:19am
   
Problem is I tried download magick++.h before. But I cant find available magick++. Can you send me that?

Thanks!!!
ansh_kumar 4-Feb-15 3:10am
   
I've already provided the link to the official website. The website contains source code and instructions.
XKT 30-Mar-15 1:43am
   
hi, @ansh_kumar, can you give me a libcurl static lib file?
ansh_kumar 30-Mar-15 3:50am
   
What's your email address?
XKT 31-Mar-15 5:03am
   
xktproject@126.com
Thx so much.
And can i send a attachment gmail without Magick?
Member 11615836 19-May-15 11:38am
   
Check Solution 7, I've fixed the code for sending any file type of any size (Larger files will take longer to encode, also I'm not sure if there's a max file size limit when sending thru SMTP)... The updated code only requires libCurl, it has its own Base64 encoding function. I hope this helps everyone out.

-CellToolz
dmaxime 12-May-17 9:11am
   
Since base64 format is also used to transfer binary files, if you want to run the encodeblock function correctly, you should consider the bytes in "in" buffer as unsigned char, otherwise when the byte value is greater or equal to 0x80, you will address the table with a negative index. The base64_encode function is very useful for converting strings to base64, but if you wanted to encode binary data, you might want to use a function like this:

void bin_base64_encode(char *in_b, char *out_b, int in_len)
{
static int i, l;
for(i = 0, l = in_len / 3; i < l; i++)
encodeblock(&in_b[i * 3], &out_b[i * 4], 3);
if(i * 3 < in_len)
encodeblock(&in_b[i * 3], &out_b[i * 4], in_len - (i * 3));
}

Regards.
For Dynamic email sending you can use following c++ code:
C++
#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
#include <cstdlib>
#include <iostream>
#include <cstring>


	int flag=0;
	std::string TO;
	std::string FROM;
	std::string CC;
	std::string Date;
	std::string Message;
	

struct upload_status 
{
  int lines_read;
};

 size_t payload_source(void *ptr, size_t size, size_t nmemb, void *userp)
{
	
		
		std::string email;
		
		

	if(flag<1)
	{
	
		time_t rawtime;
		struct tm * timeinfo;

		time ( &rawtime );
		timeinfo = localtime ( &rawtime );
		std::string today = asctime (timeinfo);
		
		email ="Date: "+today+" \r\n"+"To: "+TO+"\r\n"+"From:"+FROM+"\r\n"+		 "Cc: "+CC+" \r\n"+		 "Message-ID: <dcd7cb36-11db-487a-9f3a-e652a9458efd@"+		 "rfcpedant.example.org>\r\n"+		 "Subject: Sample subject\r\n"+		 "\r\n"+		 "Dear "+Message+" \r\n"+		r\n"+		 "\r\n"+		 "\r\n"+		 "This is a computer generated email. DO NOT REPLY to this email.\r\n";		
		 
		  struct upload_status *upload_ctx = (struct upload_status *)userp;
		   char *data;

		  if((size == 0) || (nmemb == 0) || ((size*nmemb) < 1)) {
			return 0;
		  }		  
				
				data = &email[upload_ctx->lines_read];
					  				
				  if(data) 
				  {					  
					size_t len = strlen(data);					
					memcpy(ptr, data, len);					
					upload_ctx->lines_read++;
					flag++;
					return len;
				  } 
	  }
		 
	return 0;
}

int main(void)
{
		CURL *curl;
		CURLcode res = CURLE_OK;
		struct curl_slist *recipients = NULL;
		struct upload_status upload_ctx;

		upload_ctx.lines_read = 0;

		TO = "xxx.xxx@gmail.com"; 
		FROM = "xxx.xxx@gmail.com"; 
		CC = "xxx.xxx@gmail.com"; 
    	Message = "Hi whats up?"; 
		 
		
		curl = curl_easy_init();
		if(curl) 
		{
	   
			curl_easy_setopt(curl, CURLOPT_URL, "smtp://mail.example.com");
			
			
			curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM.c_str());
			recipients = curl_slist_append(recipients, TO.c_str());
			recipients = curl_slist_append(recipients, CC.c_str());
			curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);

			curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source);
			curl_easy_setopt(curl, CURLOPT_READDATA, &upload_ctx);
			curl_easy_setopt(curl, CURLOPT_UPLOAD, 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);
		}

		  return (int)res;
}




For Running this program you must install libcurl library on your system.
You simply can compile and run this program by using following command:
comipile:g++ TestSMTP.cpp -lcurl
Run: ./a.out
   
v3
Just a slight change to Solution 7, to allow the sending of the email body text and an attachment. The key is in the boundry

C++
#include <cstring> 
#include <iostream>
#include <stdlib.h>
#include <curses.h>
#include <curl/curl.h>

using namespace std;

#ifdef _DEBUG
        #pragma comment(lib, "libcurl_a_debug.lib")
#else
        #pragma comment(lib, "libcurl_a.lib")
#endif
 
#pragma warning(disable: 4996)
 
#define FROM    "<xxxxx@xxxx.com>"
#define TO      "<xxxxxx@gmail.com>"
#define FILENAME "temp.jpg"
//#define FILENAME "mail.txt"
 
static const int CHARS= 76;
static const int ADD_SIZE= 16;
static const int SEND_BUF_SIZE= 54;
static char (*fileBuf)[CHARS] = NULL;
static const char cb64[]="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
 
using namespace std;
 
bool LARGEFILE = false;
int status = 0;
int percent2 = 0;
int percent3 = 0;
int percent4 = 0;
int percent5 = 0;

void LargeFilePercent(int rowcount)
{
        int percent = rowcount/100;
        if(LARGEFILE == true) {
                status++;
                percent2++;
                if(percent2 == 18)
                {
                        percent3++;
                        percent2 = 0;
                }
                if(percent3 == percent)
                {
                        percent4++;
                        percent3 = 0;
                }
                if(percent4 == 10)
                {
                        cout << "Larger Files take longer to encode, Please be patient." << endl
                             << endl << "Encoding " FILENAME " please be patient..." << endl;
                        cout << percent5 << "%";
                        percent5 += 10;
                        percent4 = 0;
                }
                if(status == 10000) {
                        if(percent5 == 0){cout << " 0%"; percent5 = 10;}
                        cout << ".";
                        status = 0;
                }
        }
}
 
void encodeblock(unsigned char in[3], unsigned char out[4], int len)
{
    out[0] = cb64[ in[0] >> 2 ];
    out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ];
    out[2] = (unsigned char) (len > 1 ? cb64[ ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '=');
    out[3] = (unsigned char) (len > 2 ? cb64[ in[2] & 0x3f ] : '=');
}
 
void encode(FILE *infile, unsigned char *output_buf, int rowcount/*For Percent*/)
{
    unsigned char in[3], out[4];
        int i, len;
        *output_buf = 0;
 
    while(!feof(infile)) {
        len = 0;
        for(i = 0; i < 3; i++) {
            in[i] = (unsigned char) getc(infile);
            if(!feof(infile) ) {
                len++;
            }
            else {
                in[i] = 0;
            }
        }
        if(len)
        {
            encodeblock(in, out, len);
            strncat((char*)output_buf, (char*)out, 4);
        }
            LargeFilePercent(rowcount);
        }
}
 
 
struct fileBuf_upload_status
{
  int lines_read;
};
 
size_t read_file()
{
        FILE* hFile=NULL;
        size_t fileSize(0),len(0),buffer_size(0);
        hFile = fopen(FILENAME,"rb");
        if(!hFile)
        {
                cout << "File not found!!!" << endl;
                exit (EXIT_FAILURE);
        }
		fseek(hFile,0,SEEK_END);
        fileSize = ftell(hFile);
        fseek(hFile,0,SEEK_SET);
        if(fileSize > 256000)
        {
                cout << "Larger Files take longer to encode, Please be patient." << endl;
                LARGEFILE = true;
        }
        cout << endl << "Encoding " FILENAME " please be patient..." << endl;
        int no_of_rows = fileSize/SEND_BUF_SIZE + 1;
        int charsize = (no_of_rows*72)+(no_of_rows*2);
        unsigned char* b64encode = new unsigned char[charsize];
        *b64encode = 0;
        encode(hFile, b64encode, no_of_rows);
        string encoded_buf = (char*)b64encode;
        if(LARGEFILE == true) cout << endl << endl;
        fileBuf = new char[ADD_SIZE + no_of_rows][CHARS];
        strcpy(fileBuf[len++],"To: " TO "\r\n");
        buffer_size += strlen(fileBuf[len-1]);
        
        strcpy(fileBuf[len++],"From: " FROM "\r\n");
        buffer_size += strlen(fileBuf[len-1]);

        strcpy(fileBuf[len++],"Subject: gsimSecurity Photo\r\n");
        buffer_size += strlen(fileBuf[len-1]);

        strcpy(fileBuf[len++],"Content-Type: multipart/mixed;\r\n boundary=\"XXXXXMyBoundry\"\r\n");
        buffer_size += strlen(fileBuf[len-1]);

        strcpy(fileBuf[len++],"Mime-Version: 1.0\r\n\r\n");
        buffer_size += strlen(fileBuf[len-1]);

        strcpy(fileBuf[len++],"This is a multi-part message in MIME format.\r\n\r\n");
        buffer_size += strlen(fileBuf[len-1]);

		strcpy(fileBuf[len++],"--XXXXXMyBoundry\r\n");
		buffer_size += strlen(fileBuf[len-1]);
		
		strcpy(fileBuf[len++],"Content-Type: text/plain; charset=\"UTF-8\"\r\n");
		buffer_size += strlen(fileBuf[len-1]);
		
		strcpy(fileBuf[len++],"Content-Transfer-Encoding: quoted-printable\r\n\r\n");
		buffer_size += strlen(fileBuf[len-1]);

        strcpy(fileBuf[len++],"The body of the message starts here\r\nLet's add to the body!\r\n\r\n");
        buffer_size += strlen(fileBuf[len-1]);

		strcpy(fileBuf[len++],"--XXXXXMyBoundry\r\n");
		buffer_size += strlen(fileBuf[len-1]);
     
        strcpy(fileBuf[len++],"Content-Type: application/x-msdownload; name=\"" FILENAME "\"\r\n");
        buffer_size += strlen(fileBuf[len-1]);


        strcpy(fileBuf[len++],"Content-Transfer-Encoding: base64\r\n");
        buffer_size += strlen(fileBuf[len-1]);
        strcpy(fileBuf[len++],"Content-Disposition: attachment; filename=\"" FILENAME "\"\r\n");
        buffer_size += strlen(fileBuf[len-1]);
        strcpy(fileBuf[len++],"\r\n");
        buffer_size += strlen(fileBuf[len-1]);
   
        int pos = 0;
        string sub_encoded_buf;
        for(int i = 0; i <= no_of_rows-1; i++)
        {
                sub_encoded_buf = encoded_buf.substr(pos*72,72);
                sub_encoded_buf += "\r\n";
                strcpy(fileBuf[len++], sub_encoded_buf.c_str());
                buffer_size += sub_encoded_buf.size();
                pos++;
        }

		strcpy(fileBuf[len++],"\r\n--XXXXXMyBoundry--\r\n");
		buffer_size += strlen(fileBuf[len-1]);

        delete[] b64encode;
        return buffer_size;
}
static size_t fileBuf_source(void *ptr, size_t size, size_t nmemb, void *userp)
{
        struct fileBuf_upload_status *upload_ctx = (struct fileBuf_upload_status *)userp;
        const char *fdata;
 
        if((size == 0) || (nmemb == 0) || ((size*nmemb) < 1))
        {
                return 0;
        }
 
        fdata = fileBuf[upload_ctx->lines_read];
 
        if(strcmp(fdata,""))
        {
                size_t len = strlen(fdata);
                memcpy(ptr, fdata, len);
                upload_ctx->lines_read++;
                return len;
        }
        return 0;
}
 
int main()
{
  CURL *curl;
  CURLcode res = CURLE_OK;
  struct curl_slist *recipients = NULL;
  struct fileBuf_upload_status file_upload_ctx;
  size_t file_size(0);
 
  file_upload_ctx.lines_read = 0;
 
  curl = curl_easy_init();
  file_size = read_file();
  if(curl)
  {
    curl_easy_setopt(curl, CURLOPT_URL, "smtp://mail.xxxxxxxx.com");
    curl_easy_setopt(curl, CURLOPT_USE_SSL, (long) CURLUSESSL_ALL);
    curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM);
    recipients = curl_slist_append(recipients, TO);
    curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
    curl_easy_setopt(curl, CURLOPT_INFILESIZE, file_size);
    curl_easy_setopt(curl, CURLOPT_READFUNCTION, fileBuf_source);
    curl_easy_setopt(curl, CURLOPT_READDATA, &file_upload_ctx);
    curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
    curl_easy_setopt(curl, CURLOPT_VERBOSE, 0L);
 
    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);
  }
  delete[] fileBuf;
  return (int)res;
}
   
v4
C++
<pre>
// ---------------------------------------------------------
// Send text + n files attached
// 
// command line compile
//
// g++ -Wall -fexceptions -Wno-write-strings -DCURL_STATICLIB -I/usr/local/include -g  -c send_email.cpp -o send_email.o
// g++  -o send_email send_email.o  -lgthread-2.0 -pthread -lglib-2.0 -L/usr/local/lib -lcurl -lssh2 -lssl -lcrypto
//
// ---------------------------------------------------------



#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <curl/curl.h>

using namespace std;

#define __FILENAME 100
#define __BUFSIZ   512

static const int CHARS               = 256;  
static const int SEND_BUF_SIZE       = 54;
static       char (*fileBuf)[CHARS]  = NULL;
static const char cb64[]             ="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";


#define __MAIL_BUFSIZ 65536
typedef struct sMailFile sMAILFILE, *psMAILFILE;
struct sMailFile {
   FILE *pIn;
   char  szMailFile[ __FILENAME + 1 ];
   char  szBuffer  [ __BUFSIZ   + 1 ];
};

typedef class cSendMail cSENDMAIL, *pcSENDMAIL;
class cSendMail {
protected:
   char       *pszMailBuffer;
   psMAILFILE  psFile;
public:
   cSendMail( bool *pbInitStatus );
  ~cSendMail( void );

   char * MailBuffer( void ) {
      return( &pszMailBuffer[ 0 ] );
   }

   int SendMail( char *pszFrom,
                 char *pszPassword,
                 char *pszSMTP,
                 char *pszSender,
                 char *pszMailTo,
                 char *pszSubject,
                 char *pszText ... );
};

cSENDMAIL::cSendMail( bool *pbInitStatus ) {
   pszMailBuffer = NULL;
   psFile        = NULL;
   if (( pszMailBuffer = ( char * )malloc( __MAIL_BUFSIZ )) == NULL ) {
      *pbInitStatus = 0;
      return;
   }
   if (( psFile = ( psMAILFILE )malloc( sizeof( sMAILFILE ))) == NULL ) {
      *pbInitStatus = 0;
      return;
   }
   psFile->pIn = NULL;
   strcpy( psFile->szMailFile, "mail.txt" );
} // ***** Constructor cSENDMAIL::cSendMail ***** //

cSENDMAIL::~cSendMail( void ) {
   if ( pszMailBuffer != NULL ) free( pszMailBuffer );
   if ( psFile != NULL ) free( psFile );
} // ***** Destructor cSENDMAIL::cSendMail ***** //

static size_t my_payload_source( void   *ptr,
                                 size_t  size,
                                 size_t  nmemb,
                                 void   *userp ) {
  psMAILFILE psMailFile = ( psMAILFILE )userp;

  if ( psMailFile->pIn == NULL ) {
     if (( psMailFile->pIn = fopen( psMailFile->szMailFile, "rt" )) == NULL )
        return( 0 );
  }
  if ( fgets( psMailFile->szBuffer, __BUFSIZ, psMailFile->pIn ) != NULL ) {
     size_t len = strlen( psMailFile->szBuffer );

     memcpy( ptr, psMailFile->szBuffer, len );
     return( len );
  }
  fclose( psMailFile->pIn );
  return( 0 );
}

static void encodeblock( unsigned char in[ 3 ],
                         unsigned char out[ 4 ],
                         int len ) {
   out[0] = cb64[ in[0] >> 2 ];
   out[1] = cb64[ ((in[0] & 0x03) << 4) | ((in[1] & 0xf0) >> 4) ];
   out[2] = (unsigned char) (len > 1 ? cb64[ ((in[1] & 0x0f) << 2) | ((in[2] & 0xc0) >> 6) ] : '=');
   out[3] = (unsigned char) (len > 2 ? cb64[ in[2] & 0x3f ] : '=');
}

static void encode(          FILE *infile,
                    unsigned char *output_buf,
                             int rowcount ) {
    unsigned  char in[3], out[4];
              int i, len;
             *output_buf = 0;

    while( !feof( infile )) {
       len = 0;
       for ( i = 0; i < 3; i++ ) {
          in[i] = (unsigned char) getc(infile);
          if ( !feof( infile )) {
             len++;
          } else {
             in[i] = 0;
          }
      }
      if ( len ) {
         encodeblock(in, out, len);
         strncat((char*)output_buf, (char*)out, 4);
      }
   }
}

int cSENDMAIL::SendMail( char *pszFrom,
                         char *pszPassword,
                         char *pszSMTP,
                         char *pszSender,
                         char *pszMailTo,
                         char *pszSubject,
                         char *pszText ... ) {
            bool         bError = 0;
            CURL        *curl;
            CURLcode     res       = CURLE_OK;
     struct curl_slist *recipients = NULL;
            char        szFrom[ __BUFSIZ + 1 ];
            char        szTo  [ __BUFSIZ + 1 ];
            va_list     ArgsPointer;
            char       *file_name;
            FILE       *hFile;
            FILE       *hOut;
            size_t      fileSize(0);
            size_t      len(0);
            size_t      buffer_size(0);
            int         no_of_rows;
            int         charsize;
            int         j;
   unsigned char       *b64encode;
            string      encoded_buf;
            int         pos;
            string      sub_encoded_buf;

   va_start( ArgsPointer, pszText );
   file_name = ( char * )va_arg( ArgsPointer, char * );

   sprintf( szFrom, "<%s>", pszFrom );
   sprintf( szTo  , "<%s>", pszMailTo );

   hOut = fopen( psFile->szMailFile, "wt" );
   fprintf( hOut, "To: <%s>%s\r\n", pszMailTo, pszSender );
   fprintf( hOut, "From: <%s>\r\n", pszFrom );
   fprintf( hOut, "Sender_Email: <%s>\r\n", pszFrom );
   fprintf( hOut, "Return-Path: <%s>\r\n", pszFrom );
   fprintf( hOut, "Reply-To: <%s>\r\n", pszFrom );
   fprintf( hOut, "Subject: %s\r\n", pszSubject );
   if ( file_name != NULL ) {
      fprintf( hOut, "Content-Type: multipart/mixed; boundary=\"MyBoundaryString\"\r\n" );
      fprintf( hOut, "\r\n" );
      fprintf( hOut, "--MyBoundaryString\r\n" );
      fprintf( hOut, "Content-Type: text/plain; charset=UTF-8\r\n" );
      fprintf( hOut, "\r\n" );
   } else {
      fprintf( hOut, "Content-Type: text/plain; charset=UTF-8\r\n" );
      fprintf( hOut, "\r\n" );
   }
   fprintf( hOut, "%s\r\n", pszText );
   if ( file_name != NULL )
      do {
         fileSize    = 0;
         len         = 0;
         buffer_size = 0;

         fprintf( hOut, "--MyBoundaryString\r\n" );
         fprintf( hOut, "Content-Type: application/x-msdownload; name=\"%s\"\r\n", file_name );
         fprintf( hOut, "Content-Transfer-Encoding: base64\r\n" );
         fprintf( hOut, "Content-Disposition: attachment; filename=\"%s\"\r\n", file_name );
         fprintf( hOut, "\r\n" );

         if (( hFile = fopen( file_name, "rb" )) != NULL ) {
            fseek( hFile, 0, SEEK_END );
            fileSize = +ftell( hFile );
            fseek( hFile, 0, SEEK_SET );

            no_of_rows = fileSize / SEND_BUF_SIZE + 1;
            charsize   = ( no_of_rows*72 ) + ( no_of_rows*2 );
            b64encode  = new unsigned char[charsize];
            *b64encode = 0;
            encode( hFile, b64encode, no_of_rows );
            encoded_buf = ( char * )b64encode;

            fileBuf = new char[no_of_rows][CHARS];

            pos = 0;
            for ( j = 0; j <= no_of_rows - 1; j++ )  {
               sub_encoded_buf = encoded_buf.substr( pos*72, 72 );
               sub_encoded_buf += "\r\n";
               strcpy(fileBuf [len++ ], sub_encoded_buf.c_str());
               buffer_size += sub_encoded_buf.size();
               pos++;
            }
            for ( j = 0; j < no_of_rows; j++ )
               fprintf( hOut, "%s", fileBuf[ j ] );

            delete[] fileBuf;
            delete[] b64encode;
         } else {
            printf( "File not found: %s\n", file_name );
            bError = 1;
            break;
         }
      } while (( file_name = ( char * )va_arg( ArgsPointer, char * )) != NULL );
   va_end( ArgsPointer );
   if ( file_name != NULL )
      fprintf( hOut, "--MyBoundaryString--\r\n" );
   fclose( hOut );
   if ( !bError ) {
      curl = curl_easy_init();
      if(curl) {
         curl_easy_setopt(curl, CURLOPT_USERNAME, pszFrom );
         curl_easy_setopt(curl, CURLOPT_PASSWORD, pszPassword );
         curl_easy_setopt(curl, CURLOPT_URL, pszSMTP );
         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_CAINFO, "/path/to/certificate.pem");
         curl_easy_setopt(curl, CURLOPT_MAIL_FROM, szFrom );
         recipients = curl_slist_append( recipients, szTo );
         curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients );
         curl_easy_setopt(curl, CURLOPT_READFUNCTION, my_payload_source);
         curl_easy_setopt(curl, CURLOPT_READDATA, psFile );
         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);
   }
   return (int)res;
} // ***** Function cSENDMAIL::SendMail ***** //

char *pszFrom     = "sender_email@gmail.com";
char *pszPassword = "sender_pasword";
char *pszSMTP     = "smtp.gmail.com:587";
char *pszSender   = "Send by Me";
char *pszTo       = "send_to_e-mail";
char *pszSubject  = "Subject";


void main( void ) {
   bool      bInitStatus = 1;
   cSENDMAIL cSend( &bInitStatus );

   if ( bInitStatus ) {
      char *pszFormat = "Send by me: %s\r\n";

      sprintf( cSend.MailBuffer(), pszFormat, "My Name" );
      cSend.SendMail( pszFrom,
                      pszPassword,
                      pszSMTP,
                      pszSender,
                      pszTo,
                      pszSubject,
                      cSend.MailBuffer(),
/*
                      "file_1",
                      "file_2",
                        .
                        .
                        .
                      "file_n",
*/
                      NULL );
   }

}
   
Comments
Maciej Los 13-Jun-18 8:45am
   
4 years too late!
perosoft 14-Jun-18 0:07am
   
sorry, but now i needed this, and i was lucky to found gavinsimpson solution.
CHill60 14-Jun-18 4:17am
   
So why post your own code if you were lucky to find gavinsimpson's solution??
perosoft 15-Jun-18 3:11am
   
because of text + n files attachment

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