Click here to Skip to main content
15,880,469 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
 
Share this answer
 
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
 
Share this answer
 
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...
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;
}
 
Share this answer
 
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.
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
 
Share this answer
 
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;
}
 
Share this answer
 
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 );
   }

}
 
Share this answer
 
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