Using libcurl to send an email in C++ - c++

I'm following a libcurl sample code and trying to use it to send an email to myself, but there's a few things I'm not quite understanding...
#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
/*
* For an SMTP example using the multi interface please see smtp-multi.c.
*/
/* The libcurl options want plain addresses, the viewable headers in the mail
* can very well get a full name as well.
*/
#define FROM_ADDR "<sender#example.org>"
#define TO_ADDR "<addressee#example.net>"
#define CC_ADDR "<info#example.org>"
#define FROM_MAIL "Sender Person " FROM_ADDR
#define TO_MAIL "A Receiver " TO_ADDR
#define CC_MAIL "John CC Smith " CC_ADDR
static const char *payload_text[] = {
"Date: Mon, 29 Nov 2010 21:54:29 +1100\r\n",
"To: " TO_MAIL "\r\n",
"From: " FROM_MAIL "\r\n",
"Cc: " CC_MAIL "\r\n",
"Message-ID: <dcd7cb36-11db-487a-9f3a-e652a9458efd#"
"rfcpedant.example.org>\r\n",
"Subject: SMTP example message\r\n",
"\r\n", /* empty line to divide headers from body, see RFC5322 */
"The body of the message starts here.\r\n",
"\r\n",
"It could be a lot of lines, could be MIME encoded, whatever.\r\n",
"Check RFC5322.\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) {
/* This is the URL for your mailserver */
curl_easy_setopt(curl, CURLOPT_URL, "smtp://mail.example.com");
/* Note that this option isn't strictly required, omitting it will result
* in libcurl sending the MAIL FROM command with empty sender data. All
* autoresponses should have an empty reverse-path, and should be directed
* to the address in the reverse-path which triggered them. Otherwise,
* they could cause an endless loop. See RFC 5321 Section 4.5.5 for more
* details.
*/
curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM_ADDR);
/* Add two recipients, in this particular case they correspond to the
* To: and Cc: addressees in the header, but they could be any kind of
* recipient. */
recipients = curl_slist_append(recipients, TO_ADDR);
recipients = curl_slist_append(recipients, CC_ADDR);
curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
/* We're using a callback function to specify the payload (the headers and
* body of the message). You could just use the CURLOPT_READDATA option to
* specify a FILE pointer to read from. */
curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source);
curl_easy_setopt(curl, CURLOPT_READDATA, &upload_ctx);
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
/* Send the message */
res = curl_easy_perform(curl);
/* Check for errors */
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
/* Free the list of recipients */
curl_slist_free_all(recipients);
/* curl won't send the QUIT command until you call cleanup, so you should
* be able to re-use this connection for additional messages (setting
* CURLOPT_MAIL_FROM and CURLOPT_MAIL_RCPT as required, and calling
* curl_easy_perform() again. It may not be a good idea to keep the
* connection open for a very long time though (more than a few minutes
* may result in the server timing out the connection), and you do want to
* clean up in the end.
*/
curl_easy_cleanup(curl);
}
return (int)res;
}
Now it looks like for the first curl_easy line, I'd need to change it to
curl_easy_setopt(curl, CURLOPT_URL, "smtp.gmail.com");
If I was using gmail, right? And since this is for outgoing mail, I don't need to worry about what the user is using as long as my outgoing mail address is a gmail address?
Going a little out of order...
recipients = curl_slist_append(recipients, useremail);
In this case, it would be my email. All I need to do is replace this with the receiving email correct? Well what about the sender?
curl_easy_setopt(curl, CURLOPT_MAIL_FROM, myemail);
I'm guessing that likewise, I would need to change this to my email. But it feels like it's missing something. Surely I can't just tell this program to send an email with my address without some sort of authorization, right? But I don't see anywhere on the code where I would need to supply my password (obviously I wouldn't want it hard coded, but that's an issue for later), so how would this work?
For the time being, these are the only lines I would need to change (besides a specific message), right? Am I going about this the right way? Is there more I would need to do for this to work? And how does the authorization work?
EDIT: I have made updates based on what I think would work, as well as the suggestion given for a username and password. I currently have this error:
curl_easy_perform() failed: Failed sending data to the peer
Unfortunately, it's not too specific on what went wrong. This is the new version:
#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
/*
* For an SMTP example using the multi interface please see smtp-multi.c.
*/
/* The libcurl options want plain addresses, the viewable headers in the mail
* can very well get a full name as well.
*/
#define FROM_ADDR "<sender#example.org>"
#define TO_ADDR "<addressee#example.net>"
#define CC_ADDR "<info#example.org>"
#define FROM_MAIL "Sender Person " FROM_ADDR
#define TO_MAIL "A Receiver " TO_ADDR
#define CC_MAIL "John CC Smith " CC_ADDR
static const char *payload_text[] = {
"Date: Mon, 29 Nov 2010 21:54:29 +1100\r\n",
"To: " TO_MAIL "\r\n",
"From: " FROM_MAIL "\r\n",
"Cc: " CC_MAIL "\r\n",
"Message-ID: <dcd7cb36-11db-487a-9f3a-e652a9458efd#"
"rfcpedant.example.org>\r\n",
"Subject: SMTP example message\r\n",
"\r\n", /* empty line to divide headers from body, see RFC5322 */
"The body of the message starts here.\r\n",
"\r\n",
"It could be a lot of lines, could be MIME encoded, whatever.\r\n",
"Check RFC5322.\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) {
/* This is the URL for your mailserver */
curl_easy_setopt(curl, CURLOPT_URL, "smtp.gmail.com");
/* Note that this option isn't strictly required, omitting it will result
* in libcurl sending the MAIL FROM command with empty sender data. All
* autoresponses should have an empty reverse-path, and should be directed
* to the address in the reverse-path which triggered them. Otherwise,
* they could cause an endless loop. See RFC 5321 Section 4.5.5 for more
* details.
*/
curl_easy_setopt(curl, CURLOPT_MAIL_FROM, "myemail#gmail.com");
/* Add two recipients, in this particular case they correspond to the
* To: and Cc: addressees in the header, but they could be any kind of
* recipient. */
recipients = curl_slist_append(recipients, "myemail#gmail.com");
recipients = curl_slist_append(recipients, CC_ADDR);
curl_easy_setopt(curl, CURLOPT_USERNAME, "myemail#gmail.com");
curl_easy_setopt(curl, CURLOPT_PASSWORD, "mypassword");
curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
/* We're using a callback function to specify the payload (the headers and
* body of the message). You could just use the CURLOPT_READDATA option to
* specify a FILE pointer to read from. */
curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source);
curl_easy_setopt(curl, CURLOPT_READDATA, &upload_ctx);
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
/* Send the message */
res = curl_easy_perform(curl);
/* Check for errors */
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
/* Free the list of recipients */
curl_slist_free_all(recipients);
/* curl won't send the QUIT command until you call cleanup, so you should
* be able to re-use this connection for additional messages (setting
* CURLOPT_MAIL_FROM and CURLOPT_MAIL_RCPT as required, and calling
* curl_easy_perform() again. It may not be a good idea to keep the
* connection open for a very long time though (more than a few minutes
* may result in the server timing out the connection), and you do want to
* clean up in the end.
*/
curl_easy_cleanup(curl);
}
return (int)res;
}
I haven't filled in CC_MAIL, but is this truly necessary? The actual name of the personal is generally automatically filled out by Google when you send an email.

You can set it below
curl_easy_setopt(curl, CURLOPT_USERNAME, USERNAME);
curl_easy_setopt(curl, CURLOPT_PASSWORD, PASSWORD);
Please refer to the example on curl (tag: curl-7_34_0)
https://github.com/curl/curl/blob/curl-7_34_0/docs/examples/smtp-multi.c
Recommended reference smtp-tls.c, using TLS
https://github.com/curl/curl/blob/master/docs/examples/smtp-tls.c

I am also confused whether we have to use that "<" sign or not while defining that
#define CC_ADDR "<info#example.org>"
section for eg.
Do I have to use #define CC_ADDR "anything" or I have to use #define CC_ADDR "<anything>"
I have one information regarding writing the server mail, we can use smtp.gmail.com:587 and it will work. Note that : used here is used to specify the specific port address to the mail server.

Related

Why do I get the error "cannot find -lcurl" when trying to compile example code?

I'm trying to follow this curl example and get it to compile:
https://github.com/curl/curl/blob/master/docs/examples/smtp-mail.c
https://github.com/curl/curl/blob/master/docs/examples/Makefile.example
And what I have so far is borderline copy/pasted, but I keep getting an error "cannot find -lcurl"
This is what I have for the code:
#include <stdio.h>
#include <string.h>
#include "curl-7.64.0/include/curl/curl.h"
/*
* For an SMTP example using the multi interface please see smtp-multi.c.
*/
/* The libcurl options want plain addresses, the viewable headers in the mail
* can very well get a full name as well.
*/
#define FROM_ADDR "<sender#example.org>"
#define TO_ADDR "<addressee#example.net>"
#define CC_ADDR "<info#example.org>"
#define FROM_MAIL "Sender Person " FROM_ADDR
#define TO_MAIL "A Receiver " TO_ADDR
#define CC_MAIL "John CC Smith " CC_ADDR
static const char *payload_text[] = {
"Date: Mon, 29 Nov 2010 21:54:29 +1100\r\n",
"To: " TO_MAIL "\r\n",
"From: " FROM_MAIL "\r\n",
"Cc: " CC_MAIL "\r\n",
"Message-ID: <dcd7cb36-11db-487a-9f3a-e652a9458efd#"
"rfcpedant.example.org>\r\n",
"Subject: SMTP example message\r\n",
"\r\n", /* empty line to divide headers from body, see RFC5322 */
"The body of the message starts here.\r\n",
"\r\n",
"It could be a lot of lines, could be MIME encoded, whatever.\r\n",
"Check RFC5322.\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) {
/* This is the URL for your mailserver */
curl_easy_setopt(curl, CURLOPT_URL, "smtp://mail.example.com");
/* Note that this option isn't strictly required, omitting it will result
* in libcurl sending the MAIL FROM command with empty sender data. All
* autoresponses should have an empty reverse-path, and should be directed
* to the address in the reverse-path which triggered them. Otherwise,
* they could cause an endless loop. See RFC 5321 Section 4.5.5 for more
* details.
*/
curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM_ADDR);
/* Add two recipients, in this particular case they correspond to the
* To: and Cc: addressees in the header, but they could be any kind of
* recipient. */
recipients = curl_slist_append(recipients, TO_ADDR);
recipients = curl_slist_append(recipients, CC_ADDR);
curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
/* We're using a callback function to specify the payload (the headers and
* body of the message). You could just use the CURLOPT_READDATA option to
* specify a FILE pointer to read from. */
curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source);
curl_easy_setopt(curl, CURLOPT_READDATA, &upload_ctx);
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
/* Send the message */
res = curl_easy_perform(curl);
/* Check for errors */
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
/* Free the list of recipients */
curl_slist_free_all(recipients);
/* curl won't send the QUIT command until you call cleanup, so you should
* be able to re-use this connection for additional messages (setting
* CURLOPT_MAIL_FROM and CURLOPT_MAIL_RCPT as required, and calling
* curl_easy_perform() again. It may not be a good idea to keep the
* connection open for a very long time though (more than a few minutes
* may result in the server timing out the connection), and you do want to
* clean up in the end.
*/
curl_easy_cleanup(curl);
}
return (int)res;
}
And this is what I'm using for the makefile:
TARGET = email
OBJS= smtp-mail.o
CC = gcc
CFLAGS = -c -g
LDFLAGS = -L/curl-7.64.0/lib
LIBS = -lcurl -lsocket -lnsl -lssl -lcrypto
$(TARGET) : $(OBJS)
$(CC) -o $(TARGET) $(OBJS) $(LDFLAGS) $(LIBS)
smtp-mail.o : smtp-mail.c
$(CC) $(CFLAGS) $<
Does anyone know why this would be happening?
EDIT: I updated the paths in smtp-mail.c and the makefile:
#include "/user/jastei/Email/curl-7.58.0/include/curl/curl.h"
LDFLAGS = -L/user/jastei/Email/curl-7.58.0/lib/ -L/user/jastei/Email/curl-7.58.0/lib/vtls
I ran the commands:
./configure --prefix=/user/jastei/Email/curl-7.58.0 --disable-shared
make
make install
At first, it looked like nothing has changed, however, instead of "cannot find -lcurl" I got this: cannot find -lsocket
EDIT 2: Regarding cmake...when I called cmake:
/user/jastei/Email/cmake/bin/cmake CMakeLists.txt
I got this error:
File /user/jastei/Email/cmake/bin/headers/conf.h.in does not exist.
You are going to need to build libcurl yourself to get the static library that you want to compile with. You can grab the latest release at https://github.com/curl/curl/releases/tag/curl-7_64_0. Download the source code zip archive. You can view https://curl.haxx.se/docs/install.html for full building instructions but basically you need to extract the source code, open your terminal, cd to the directory that has the configure script and the Makefile, and then type the following commands:
# change the below prefix path to where you want curl to install
# e.g. ~/curl-7.64.0
./configure --prefix=/path/to/install/to --disable-shared
make
make install
Let it work its magic. That should give you the files that you need.

libcurl SMTP read function returned funny value Segmentation fault c++

I'm trying to play with libcurl SMTP and everything works fine with this example:
http://curl.haxx.se/libcurl/c/smtp-mail.html
#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
/* This is a simple example showing how to send mail using libcurl's SMTP
* capabilities. For an exmaple of using the multi interface please see
* smtp-multi.c.
*
* Note that this example requires libcurl 7.20.0 or above.
*/
#define FROM "<sender#example.org>"
#define TO "<addressee#example.net>"
#define CC "<info#example.org>"
static const char *payload_text[] = {
"Date: Mon, 29 Nov 2010 21:54:29 +1100\r\n",
"To: " TO "\r\n",
"From: " FROM "(Example User)\r\n",
"Cc: " CC "(Another example User)\r\n",
"Message-ID: <dcd7cb36-11db-487a-9f3a-e652a9458efd#rfcpedant.example.org>\r\n",
"Subject: SMTP example message\r\n",
"\r\n", /* empty line to divide headers from body, see RFC5322 */
"The body of the message starts here.\r\n",
"\r\n",
"It could be a lot of lines, could be MIME encoded, whatever.\r\n",
"Check RFC5322.\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) {
/* This is the URL for your mailserver */
curl_easy_setopt(curl, CURLOPT_URL, "smtp://mail.example.com");
/* Note that this option isn't strictly required, omitting it will result in
* libcurl sending the MAIL FROM command with empty sender data. All
* autoresponses should have an empty reverse-path, and should be directed
* to the address in the reverse-path which triggered them. Otherwise, they
* could cause an endless loop. See RFC 5321 Section 4.5.5 for more details.
*/
curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM);
/* Add two recipients, in this particular case they correspond to the
* To: and Cc: addressees in the header, but they could be any kind of
* recipient. */
recipients = curl_slist_append(recipients, TO);
recipients = curl_slist_append(recipients, CC);
curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
/* We're using a callback function to specify the payload (the headers and
* body of the message). You could just use the CURLOPT_READDATA option to
* specify a FILE pointer to read from. */
curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source);
curl_easy_setopt(curl, CURLOPT_READDATA, &upload_ctx);
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
/* Send the message */
res = curl_easy_perform(curl);
/* Check for errors */
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
/* Free the list of recipients */
curl_slist_free_all(recipients);
/* curl won't send the QUIT command until you call cleanup, so you should be
* able to re-use this connection for additional messages (setting
* CURLOPT_MAIL_FROM and CURLOPT_MAIL_RCPT as required, and calling
* curl_easy_perform() again. It may not be a good idea to keep the
* connection open for a very long time though (more than a few minutes may
* result in the server timing out the connection), and you do want to clean
* up in the end.
*/
curl_easy_cleanup(curl);
}
return (int)res;
}
but if I greatly increases a payload function, I get an error:
read function returned funny value
Segmentation fault
How could I solve this problem?
The following code is to send a plain text message
rather than a email message. but the basic ideas are the same.
did you set the curl write function option to point to a callback function?
curl_easy_setopt(curlHandle, CURLOPT_WRITEFUNCTION, &CurlWriteFunction);
//////////////////
where the CurlWriteFunction() would look similar to the following:
//////////////////
size_t CurlWriteFunction(void *ptr, size_t size, size_t nmemb, void *stream)
{
memset(CurlMsgStr, 0, MAX_MSG_STR);
phpCurlError = FALSE;
if(((char *)ptr)[0] == '1' || ((char *)ptr)[1] == '1')
{
phpCurlError = FALSE;
sprintf(CurlMsgStr,"Record sent to URL OK...[%c%c]\n",
((char *)ptr)[0],((char *)ptr)[1]);
}
else if(((char *)ptr)[0] == '0' || ((char *)ptr)[1] == '0')
{
phpCurlError = TRUE;
sprintf(CurlMsgStr,"Record sent to URL FAILED...[%c%c]\n",
((char *)ptr)[0],((char *)ptr)[1]);
}
else
{
phpCurlError = TRUE;
sprintf(CurlMsgStr,"UNKNOWN URL RETURN VALUE...[%c%c]\n",
((char *)ptr)[0],((char *)ptr)[1]);
}
return (nmemb);
} // CurlWriteFunction()
////////////////////
Then send the curl message with something like this:
////////////////////
void sendViaCurl(char *str)
{
#if 0 // eliminate heap thrashing of 8k malloc/free
char* postData = NULL;
#else
static char* postData = NULL;
#endif
CURLcode curlErr;
long curlRespCode = 0;
char recNameStr[MAX_STRING_LENGTH];
if(curlHandle)
{
// Specify the POST data
if(postData == NULL) // then first time through
{
postData = malloc(MAX_RESPONSE_LENGTH * 2);
}
memset(postData,0,MAX_RESPONSE_LENGTH * 2);
sprintf(postData, "%s", str);
curl_easy_setopt(curlHandle, CURLOPT_POSTFIELDS, postData);
// Execute the POST, response goes to STDOUT
curlErr = curl_easy_perform(curlHandle);
// Report any CURL errors
if(curlErr)
{
log_error("CURL ERROR -- %s\n", curl_easy_strerror(curlErr));
}
// Get info on the POST data transfer to URL
curl_easy_getinfo(curlHandle, CURLINFO_RESPONSE_CODE, &curlRespCode);
// log_error( "CURL RESPONSE CODE -- %ld\n", curlRespCode);
if(phpCurlError)
{
log_error( " %s rec rejected by DB -- %s\n", recNameStr, str);
curlRecRejected = TRUE;
}
else
{
log_error( "%s [%s] rec accepted by DB...\n",recNameStr, str);
curlRecRejected = FALSE;
}
}
else
{
log_error( "NOT ABLE TO GET CURL HANDLE...RECORD NOT SENT\n");
curlRecRejected = TRUE;
}
#if 0 // eliminate thrashing of heap with 8k malloc/free
if(postData)
{
free(postData);
postData = NULL;
}
#endif
return;
} // sendViaCurl()

trouble loading external library

I am having trouble using the curl library inside a c++ program. I copied the curl folder directly to the Microsoft Visual Studio 12.0\VC\crt\src folder. I am using a test program directly from Curl's website so there should not be any problem there. However it does give me some unresolved external symbols which looks like the library is not loading correctly. I am using visual studio 12.0 express.
`/***************************************************************************
* _ _ ____ _
* Project ___| | | | _ \| |
* / __| | | | |_) | |
* | (__| |_| | _ <| |___
* \___|\___/|_| \_\_____|
*
* Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel#haxx.se>, et al.
*
* This software is licensed as described in the file COPYING, which
* you should have received as part of this distribution. The terms
* are also available at http://curl.haxx.se/docs/copyright.html.
*
* You may opt to use, copy, modify, merge, publish, distribute and/or sell
* copies of the Software, and permit persons to whom the Software is
* furnished to do so, under the terms of the COPYING file.
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
* KIND, either express or implied.
*
***************************************************************************/
#include <stdio.h>
#include <string.h>
#include "curl\curl.h"
/* This is a simple example showing how to send mail using libcurl's SMTP
* capabilities. It builds on the smtp-mail.c example to add authentication
* and, more importantly, transport security to protect the authentication
* details from being snooped.
*
* Note that this example requires libcurl 7.20.0 or above.
*/
#define FROM "<sender#example.org>"
#define TO "<addressee#example.net>"
#define CC "<info#example.org>"
static const char *payload_text[] = {
"Date: Mon, 29 Nov 2010 21:54:29 +1100\r\n",
"To: " TO "\r\n",
"From: " FROM "(Example User)\r\n",
"Cc: " CC "(Another example User)\r\n",
"Message-ID: <dcd7cb36-11db-487a-9f3a-e652a9458efd#rfcpedant.example.org>\r\n",
"Subject: SMTP TLS example message\r\n",
"\r\n", /* empty line to divide headers from body, see RFC5322 */
"The body of the message starts here.\r\n",
"\r\n",
"It could be a lot of lines, could be MIME encoded, whatever.\r\n",
"Check RFC5322.\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) {
/* Set username and password */
curl_easy_setopt(curl, CURLOPT_USERNAME, "user");
curl_easy_setopt(curl, CURLOPT_PASSWORD, "secret");
/* This is the URL for your mailserver. Note the use of port 587 here,
* instead of the normal SMTP port (25). Port 587 is commonly used for
* secure mail submission (see RFC4403), but you should use whatever
* matches your server configuration. */
curl_easy_setopt(curl, CURLOPT_URL, "smtp://mainserver.example.net:587");
/* In this example, we'll start with a plain text connection, and upgrade
* to Transport Layer Security (TLS) using the STARTTLS command. Be careful
* of using CURLUSESSL_TRY here, because if TLS upgrade fails, the transfer
* will continue anyway - see the security discussion in the libcurl
* tutorial for more details. */
curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL);
/* If your server doesn't have a valid certificate, then you can disable
* part of the Transport Layer Security protection by setting the
* CURLOPT_SSL_VERIFYPEER and CURLOPT_SSL_VERIFYHOST options to 0 (false).
* curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
* curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
* That is, in general, a bad idea. It is still better than sending your
* authentication details in plain text though.
* Instead, you should get the issuer certificate (or the host certificate
* if the certificate is self-signed) and add it to the set of certificates
* that are known to libcurl using CURLOPT_CAINFO and/or CURLOPT_CAPATH. See
* docs/SSLCERTS for more information. */
curl_easy_setopt(curl, CURLOPT_CAINFO, "/path/to/certificate.pem");
/* Note that this option isn't strictly required, omitting it will result in
* libcurl sending the MAIL FROM command with empty sender data. All
* autoresponses should have an empty reverse-path, and should be directed
* to the address in the reverse-path which triggered them. Otherwise, they
* could cause an endless loop. See RFC 5321 Section 4.5.5 for more details.
*/
curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM);
/* Add two recipients, in this particular case they correspond to the
* To: and Cc: addressees in the header, but they could be any kind of
* recipient. */
recipients = curl_slist_append(recipients, TO);
recipients = curl_slist_append(recipients, CC);
curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
/* We're using a callback function to specify the payload (the headers and
* body of the message). You could just use the CURLOPT_READDATA option to
* specify a FILE pointer to read from. */
curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source);
curl_easy_setopt(curl, CURLOPT_READDATA, &upload_ctx);
curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
/* Since the traffic will be encrypted, it is very useful to turn on debug
* information within libcurl to see what is happening during the transfer.
*/
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
/* Send the message */
res = curl_easy_perform(curl);
/* Check for errors */
if (res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
/* Free the list of recipients */
curl_slist_free_all(recipients);
/* Always cleanup */
curl_easy_cleanup(curl);
}
return (int)res;
}`
I suppose you are getting linking error unresolved external symbols for functions like curl_global_init and other curl functions.
To get rid of these errors, you have to compile curl library and link .lib with the above test application

Problems using libcurl to send email (C++ and Win32)

I'm currently experiencing some problems and was hoping I could gain some insight as to what is going on by posting it here. I want to write a simple C++ application (or C) to send an email to a gmail account. I am in a win32 (xp sp2) environment and I am using dev C++ as my compiler. I've included the curl libraries and the application seems to compile fine, however it does not send the email nor does it display errors. Here is the code that I found that I am using to do this:
#include <stdio.h>
#include <string.h>
#include <curl/curl.h>
#include <conio.h>
#include <iostream>
/* This is a simple example showing how to send mail using libcurl's SMTP
* capabilities. It builds on the simplesmtp.c example, adding some
* authentication and transport security.
*/
#define FROM "<email#email.com>"
#define TO "<email#gmail.com>"
#define CC "<email#gmail.com>"
using namespace std;
static const char *payload_text[]={
"Date: Mon, 29 Nov 2010 21:54:29 +1100\n",
"To: " TO "\n",
"From: " FROM "(Example User)\n",
"Cc: " CC "(Another example User)\n",
"Message-ID: <dcd7cb36-11db-487a-9f3a-e652a9458efd#rfcpedant.example.org>\n",
"Subject: SMTP TLS example message\n",
"\n", /* empty line to divide headers from body, see RFC5322 */
"The body of the message starts here.\n",
"\n",
"It could be a lot of lines, could be MIME encoded, whatever.\n",
"Check RFC5322.\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)
{
//cout << "starting";
//_getch();
CURL *curl;
CURLcode res;
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_VERBOSE, 1);
/* This is the URL for your mailserver. Note the use of port 587 here,
* instead of the normal SMTP port (25). Port 587 is commonly used for
* secure mail submission (see RFC4403), but you should use whatever
* matches your server configuration. */
curl_easy_setopt(curl, CURLOPT_URL, "smtp://smtp.gmail.com:587");
/* In this example, we'll start with a plain text connection, and upgrade
* to Transport Layer Security (TLS) using the STARTTLS command. Be careful
* of using CURLUSESSL_TRY here, because if TLS upgrade fails, the transfer
* will continue anyway - see the security discussion in the libcurl
* tutorial for more details. */
curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL);
/* If your server doesn't have a valid certificate, then you can disable
* part of the Transport Layer Security protection by setting the
* CURLOPT_SSL_VERIFYPEER and CURLOPT_SSL_VERIFYHOST options to 0 (false).
* curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
* curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
* That is, in general, a bad idea. It is still better than sending your
* authentication details in plain text though.
* Instead, you should get the issuer certificate (or the host certificate
* if the certificate is self-signed) and add it to the set of certificates
* that are known to libcurl using CURLOPT_CAINFO and/or CURLOPT_CAPATH. See
* docs/SSLCERTS for more information.
*/
//curl_easy_setopt(curl, CURLOPT_CAINFO, "/path/to/certificate.pem");
/* A common reason for requiring transport security is to protect
* authentication details (user names and passwords) from being "snooped"
* on the network. Here is how the user name and password are provided: */
curl_easy_setopt(curl, CURLOPT_USERNAME, "username");
curl_easy_setopt(curl, CURLOPT_PASSWORD, "password");
/* value for envelope reverse-path */
curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM);
/* Add two recipients, in this particular case they correspond to the
* To: and Cc: addressees in the header, but they could be any kind of
* recipient. */
recipients = curl_slist_append(recipients, TO);
recipients = curl_slist_append(recipients, CC);
curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
/* In this case, we're using a callback function to specify the data. You
* could just use the CURLOPT_READDATA option to specify a FILE pointer to
* read from.
*/
curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source);
curl_easy_setopt(curl, CURLOPT_READDATA, &upload_ctx);
/* Since the traffic will be encrypted, it is very useful to turn on debug
* information within libcurl to see what is happening during the transfer.
*/
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
/* send the message (including headers) */
res = curl_easy_perform(curl);
/* Check for errors */
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
/* free the list of recipients and clean up */
curl_slist_free_all(recipients);
curl_easy_cleanup(curl);
_getch();
}
return 0;
}
When I compile and run this, I see a black screen for a milisecond or so, then nothing, no email sent, no errors, etc. I thought by adding the 'curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);' (as reccomended per libcurl's website) would display output, but nothing. So I added the '_getch()' line at the end before the return, and still the window is dissappearing.
I also tried using 'system("pause")' before the final return to no avail either. Currently is appears I need to get the readable output to further debug the problem so I can continue on and get this code to send emails.
I have also tried changing the port to 465 to no avail either.
Anyone have any idea what's going on here? Thank you for your time.

How to null the output of smtp

I am using the following code for smtp:
When it invokes sendEmail, the output will display in the terminal. How can I send it to dev/null or not output it? Running in background doesn't help.
Partial Output:
* About to connect() to smtp.gmail.com port 587 (#0)
* Trying 173.194.79.109... * connected
< 220 mx.google.com ESMTP nv6sm10641402pbc.42
> EHLO ubuntu
< 250-mx.google.com at your service, [222.164.82.97]
< 250-SIZE 35882577
< 250-8BITMIME
< 250-STARTTLS
< 250 ENHANCEDSTATUSCODES
> STARTTLS
< 220 2.0.0 Ready to start TLS
* successfully set certificate verify locations:
* CAfile: none
Code:
#include <stdio.h>
#include <string>
#include <cstring>
#include <curl/curl.h>
using namespace std;
/* This is a simple example showing how to send mail using libcurl's SMTP
* capabilities. It builds on the simplesmtp.c example, adding some
* authentication and transport security.
*/
#define FROM "<asktheprogramer2#gmail.com>"
#define CC "<asktheprogramer2#gmail.com>"
string ToAddress,strSubject, strMessage;
struct upload_status {
int lines_read;
};
static size_t payload_source(void *ptr, size_t size, size_t nmemb, void *userp)
{
const char *payload_text[]={ToAddress.c_str(),"From: " FROM "\n","Cc: " CC "\n",strSubject.c_str(),"\n", /* empty line to divide headers from body, see RFC5322 */
strMessage.c_str(),NULL};
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;
}
void sendMail(string strRecipent, string strAubject, string strBessage){
ToAddress="To: ";
ToAddress+=strRecipent;
ToAddress+="\n";
strSubject="Subject: ";
strSubject+=strAubject;
strSubject+="\n";
strMessage=strBessage;
CURL *curl;
CURLcode res;
struct curl_slist *recipients = NULL;
struct upload_status upload_ctx;
upload_ctx.lines_read = 0;
curl = curl_easy_init();
if (curl) {
/* This is the URL for your mailserver. Note the use of port 587 here,
* instead of the normal SMTP port (25). Port 587 is commonly used for
* secure mail submission (see RFC4403), but you should use whatever
* matches your server configuration. */
curl_easy_setopt(curl, CURLOPT_URL, "smtp://smtp.gmail.com:500");
/* In this example, we'll start with a plain text connection, and upgrade
* to Transport Layer Security (TLS) using the STARTTLS command. Be careful
* of using CURLUSESSL_TRY here, because if TLS upgrade fails, the transfer
* will continue anyway - see the security discussion in the libcurl
* tutorial for more details. */
curl_easy_setopt(curl, CURLOPT_USE_SSL, (long)CURLUSESSL_ALL);
/* If your server doesn't have a valid certificate, then you can disable
* part of the Transport Layer Security protection by setting the
* CURLOPT_SSL_VERIFYPEER and CURLOPT_SSL_VERIFYHOST options to 0 (false).
* curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
* curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
* That is, in general, a bad idea. It is still better than sending your
* authentication details in plain text though.
* Instead, you should get the issuer certificate (or the host certificate
* if the certificate is self-signed) and add it to the set of certificates
* that are known to libcurl using CURLOPT_CAINFO and/or CURLOPT_CAPATH. See
* docs/SSLCERTS for more information.
*/
//curl_easy_setopt(curl, CURLOPT_CAINFO, "/path/to/certificate.pem");
/* A common reason for requiring transport security is to protect
* authentication details (user names and passwords) from being "snooped"
* on the network. Here is how the user name and password are provided: */
curl_easy_setopt(curl, CURLOPT_USERNAME, "sim.dssprojects#gmail.com");
curl_easy_setopt(curl, CURLOPT_PASSWORD, "SIMpassword");
/* value for envelope reverse-path */
curl_easy_setopt(curl, CURLOPT_MAIL_FROM, FROM);
/* Add two recipients, in this particular case they correspond to the
* To: and Cc: addressees in the header, but they could be any kind of
* recipient. */
recipients = curl_slist_append(recipients, strRecipent.c_str());
recipients = curl_slist_append(recipients, CC);
curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
/* In this case, we're using a callback function to specify the data. You
* could just use the CURLOPT_READDATA option to specify a FILE pointer to
* read from.
*/
curl_easy_setopt(curl, CURLOPT_READFUNCTION, payload_source);
curl_easy_setopt(curl, CURLOPT_READDATA, &upload_ctx);
/* Since the traffic will be encrypted, it is very useful to turn on debug
* information within libcurl to see what is happening during the transfer.
*/
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
/* send the message (including headers) */
res = curl_easy_perform(curl);
/* Check for errors */
if(res != CURLE_OK)
fprintf(stderr, "curl_easy_perform() failed: %s\n",
curl_easy_strerror(res));
/* free the list of recipients and clean up */
curl_slist_free_all(recipients);
curl_easy_cleanup(curl);
}
}
int main(void)
{
int pid = fork();
if (pid == 0)
{
for(int i=0;i<2;i++)
{
sleep(10);
sendMail("<asktheprogramer#gmail.com>","ABE Reminder","You have an appt in 15 mins");
}
return 0;
}
else
{
sleep(30);
}
return 0;
}
A possibility would be to redirect the standard output and standard error. I am unsure if there is an equivalent mechanism for achieving this via C++ streams but you could use freopen():
freopen("stdout.txt", "w", stdout);
freopen("stderr.txt", "w", stderr);
You can redirect the output of your program when running it. Like this (assuming *nix environment):
./<yourprogram> > /dev/null
for the standard output.
./<yourprogram> &> /dev/null
for standard and error outputs.
Delete or comment out this line from the code:
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);