On Sat, Feb 25, 2017 at 10:48:33PM -0800, Nicholas Chambers wrote:
> Hello all! I'm writing a little thing which involves emailing an image after 
> $x
> amount of time. To make sure the code works, I wanted to put it in a separate
> program and test it. Currently the code I have is attached as mail.c, and the
> image I am trying to send is purple.jpeg. The email sends, and I get it in my
> inbox, but the image fails to load. Could someone help me figure out why?
> 
> Cheers,
> Nicholas Chambers
> 
> 
> 

> #include <stdio.h>
> #include <string.h>
> #include <curl/curl.h>
> 
> #define FROM    "<[email protected]>"
> #define TO      "<[email protected]>"
> 
> static const char *payload_text[] = {
>   "To: " TO "\r\n",
>   "From: " FROM "\r\n",
>   "Subject: SMTPS Example\r\n",
>   "Date: Mon, 29 Nov 2010 21:54:29 +1100\r\n",

Naturally, you'll want to set this dynamically, since an old date will get lost
in people's in-boxes and old dates are used by some systems as a spam indicator.

>   "User-Agent: My eMail Client\r\n",
>   "MIME-Version: 1.0\r\n",
>   "Content-Type: multipart/mixed;\r\n",
>    " boundary=\"------------030203080101020302070708\"\r\n",    
>   "\r\nThis is a multi-part message in MIME format.\r\n",
>   "--------------030203080101020302070708\r\n",
>   "Content-Type: text/plain; charset=utf-8; format=flowed\r\n",
>   "Content-Transfer-Encoding: 7bit\r\n",
>   "\r\n", /* empty line to divide headers from body, see RFC5322 */
>   "The body of the message starts here.\r\n",
>   "\r\n",
>   "--------------030203080101020302070708\r\n",
>   "Content-Type: text/jpeg; charset=utf-8; format=flowed\r\n",

You want image/jpeg here. And charset and format are meaningless for that type.

>   "Content-Disposition: attachment;\r\n",

If you use this, then the image won't be shown inline in most e-mail clients.
Maybe that's what you want and maybe not.

>   "  filename=\"purple.jpeg\"\r\n",
>   "\r\n",
>   
> "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAYEBQYFBAYGBQYHBwYIC\r\n",

This header is only needed for the data: URL scheme. It's not a part of
image/jpeg data and needs to be removed.

[...]
>   
> "XPUfCNuI+MfCPjKXqB7Q8Z4Z4p4YF9OgqVKlfSEqVKlRlh8J6R8Z6x8Ohj0h4Q8IeEDAEMoEr9J+\r\n",
>   "jv1cR5jGMIbhxOJ2nP6f//Z\r\n",
>   "--------------030203080101020302070708--\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++;

Sending data line-by-line works, but it's pretty inefficient. You could likely
send the entirety of the message in a single callback. Rather than storing the
message as an array of strings, I'd store it as a single string and send
(size*nmemb) bytes of that string each time until it's all sent.

>  
>     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://localhost:25");
>  
>     /* 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);
>     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;
> }
-------------------------------------------------------------------
Unsubscribe: https://cool.haxx.se/list/listinfo/curl-library
Etiquette:   https://curl.haxx.se/mail/etiquette.html

Reply via email to