Search code examples
c++libcurl

Sending an email using curl c++


Im trying to send an email using curl c++, i managed to log in well and when i run the program it works fine, does not throw any error, but the email never comes.

This is my code:

#include <iostream>
#include <curl/curl.h>

static const char *payload_text =
  "Date: Mon, 29 Nov 2010 21:54:29 +1100\r\n"
  "To: " "mailto" "\r\n"
  "From: " "mymail" "\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";

size_t read_function(char *buffer, size_t size, size_t nmemb,char *data)
{
    size_t len;
    if(size == 0 or nmemb == 0)
    {
        return 0;
    }
    if(data)
    {
        len = strlen(data);
        memcpy(buffer, data, len);
        return len;
    }
    return 0;  
}

int main()
{
    CURL *curl;
    CURLcode res = CURLE_OK;
    const char *data = payload_text;
 
    curl = curl_easy_init();
    if(curl) 
    {
        curl_easy_setopt(curl, CURLOPT_USERNAME, "mymail"); 
        curl_easy_setopt(curl, CURLOPT_PASSWORD, "password");
        curl_easy_setopt(curl, CURLOPT_URL, "smtp://smtp.gmail.com:587");
        curl_easy_setopt(curl, CURLOPT_MAIL_FROM, "my mail");
        curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, "mailto");
        curl_easy_setopt(curl, CURLOPT_READDATA,payload_text);
        curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_function);
        curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
        curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
        curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL);
    }
    res = curl_easy_perform(curl);
    
    if(res != CURLE_OK)
    {
        fprintf(stderr, "curl_easy_perform() failed: %s\n",
        curl_easy_strerror(res));
        curl_easy_cleanup(curl);
    }
    return 0;
}

I think the problem is in the curl options READDATA and READUNCTION. In the documentation says that you have to pass as an argument to READDATA a data pointer. const char *data = payload_text; is the data pointer, right?

then READFUNCTION takes as an argument a function which return the size of the data and i think that is what size_t read_function(char *buffer, size_t size, size_t nmemb,char *data) is doing.

I am new in this so any advice would be good for me.


Solution

  • I found this to be a helpful starting point: https://curl.se/libcurl/c/smtp-mail.html

    There are two main problems with your code:

    1. Your read_function didn't keep track of how much of the payload has been read so it would keep giving the same content to libcurl over and over and never signal the end of the message.
    2. You were setting CURLOPT_MAIL_RCPT to a string when in fact it should be a struct curl_slist * because there can be multiple recipients.

    Here is a fixed example that I tested on my computer and it worked. Private data at the top of the file was modified before posting.

    #define USERNAME "david"
    #define PASSWORD "xxxxx"
    #define MAILTO "[email protected]"
    #define MAILFROM "[email protected]"
    #define SMTP "smtp://your.smtp.server.example.com:25"
    
    #include <stdio.h>
    #include <curl/curl.h>
    
    const char * payload_text =
      "Date: Mon, 29 Nov 2010 21:54:29 +1100\r\n"
      "To: " MAILTO "\r\n"
      "From: " MAILFROM "\r\n"
      "Subject: SMTP example message with libcurl 6\r\n"
      "\r\n"
      "Hello world!\r\n";
    
    struct ReadData
    {
      explicit ReadData(const char * str)
      {
        source = str;
        size = strlen(str);
      }
    
      const char * source;
      size_t size;
    };
    
    size_t read_function(char * buffer, size_t size, size_t nitems, ReadData * data)
    {
      size_t len = size * nitems;
      if (len > data->size) { len = data->size; }
      memcpy(buffer, data->source, len);
      data->source += len;
      data->size -= len;
      return len;
    }
    
    int main()
    {
      CURL * curl = curl_easy_init();
      if (!curl)
      {
        fprintf(stderr, "curl_easy_init failed\n");
        return 1;
      }
    
      curl_easy_setopt(curl, CURLOPT_USERNAME, USERNAME);
      curl_easy_setopt(curl, CURLOPT_PASSWORD, PASSWORD);
      curl_easy_setopt(curl, CURLOPT_URL, SMTP);
      curl_easy_setopt(curl, CURLOPT_MAIL_FROM, MAILFROM);
    
      struct curl_slist * rcpt = NULL;
      rcpt = curl_slist_append(rcpt, MAILTO);
      curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, rcpt);
    
      ReadData data(payload_text);
      curl_easy_setopt(curl, CURLOPT_READDATA, &data);
      curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_function);
    
      curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
      curl_easy_setopt(curl, CURLOPT_UPLOAD, 1);
      curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL);
    
      // If your server doesn't have a proper SSL certificate:
      curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
    
      CURLcode res = curl_easy_perform(curl);
      if (res != CURLE_OK)
      {
        fprintf(stderr, "curl_easy_perform() failed: %s\n",
          curl_easy_strerror(res));
        curl_easy_cleanup(curl);
      }
      return 0;
    }