J.Doe
J.Doe

Reputation: 1

Building SMTP client using libCurl

I recently started to use libcurl libraries to build a simple SMTP client that can send mail to gmail smtp server.Base code is the same as smtp-tls.c from http://curl.haxx.se/libcurl/c/smtp-tls.html but it isn't working for me.When I compile following code

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

static const char *payload_text[] = {
"Date: Mon, 29 Nov 2010 21:54:29 +1100\r\n",
"To: " "<[email protected]>" "\r\n",
"From: " "<[email protected]>" "(Example User)\r\n",
"Message-ID: <dcd7cb36-11db-487a-9f3a-        [email protected]>\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) {

   curl_easy_setopt(curl, CURLOPT_USERNAME, "[email protected]");
   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_MAIL_FROM,"[email protected]");
   recipients = curl_slist_append(recipients, "[email protected]");
   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);
 }
return (int)res;
}

the output is

./smtp: /usr/local/lib/libcurl.so.4: no version information available    (required by ./smtp)
* Rebuilt URL to: smtp://smtp.gmail.com:587/
*   Trying 74.125.195.109...
* Connected to smtp.gmail.com (74.125.195.109) port 587 (#0)
< 220 mx.google.com ESMTP h5sm17332853wjn.20 - gsmtp
> EHLO alan-EasyNote-TS11HR
< 250-mx.google.com at your service, [109.175.102.154]
< 250-SIZE 35882577
< 250-8BITMIME
< 250-STARTTLS
< 250-ENHANCEDSTATUSCODES
< 250-PIPELINING
< 250-CHUNKING
< 250 SMTPUTF8
> MAIL FROM:<[email protected]>
< 530 5.7.0 Must issue a STARTTLS command first. h5sm17332853wjn.20 -    gsmtp
* MAIL failed: 530
> QUIT
< 221 2.0.0 closing connection h5sm17332853wjn.20 - gsmtp
* Closing connection 0
curl_easy_perform() failed: Failed sending data to the peer

,but when I comment curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); line i get different output

./smtp: /usr/local/lib/libcurl.so.4: no version information available   (required by ./smtp)
* Rebuilt URL to: smtp://smtp.gmail.com:587/
*   Trying 74.125.136.108...
* Connected to smtp.gmail.com (74.125.136.108) port 587 (#0)
< 220 mx.google.com ESMTP g8sm17345920wjn.18 - gsmtp
> EHLO alan-EasyNote-TS11HR
< 250-mx.google.com at your service, [109.175.102.154]
< 250-SIZE 35882577
< 250-8BITMIME
< 250-STARTTLS
< 250-ENHANCEDSTATUSCODES
< 250-PIPELINING
< 250-CHUNKING
< 250 SMTPUTF8
> VRFY [email protected]
< 252 2.1.5 Send some mail, I'll try my best g8sm17345920wjn.18 -   gsmtp
252 2.1.5 Send some mail, I'll try my best g8sm17345920wjn.18 - gsmtp
* Connection #0 to host smtp.gmail.com left intact

so can anyone tell me what is wrong with this code and what should I do to change (add or remove) to successful send mail.I must say that I'm new to libcurl and not very familiar with it.Thanks.

Upvotes: 0

Views: 3059

Answers (1)

JeremyP
JeremyP

Reputation: 86661

In the first example, curl attempts to send the mail. The MAIL FROM: command is the first command in SMTP when a new message is to be sent. It tells the receiving server who the envelope sender is. The attempt to send mail is refused because the GMAil server refuses to accept unencrypted email (STARTTLS is a command that effectively turns a plain text SMTP session into an SSL encrypted one).

In the second case, instead of attempting to send an email, curl is simply trying to verify that [email protected] is a real email address. Gmail responds by not actually telling curl the answer one way or another. Most SMTP servers no longer respond helpfully to VRFY because of spamming. My guess is that that turning off the upload option is the equivalent to asking curl to not send anything, just verify the address.

What you need to do is configure curl to use TLS for SMTP, that probably involves some configuration and handling of certificates, but doing that with curl is beyond my level of knowledge.

Edit

A bit of Googling turns up an example of using TLS on the curl web site.

Edit 2

And a link from somebody who got it working with gmail.

Upvotes: 1

Related Questions