27
2017
09

ios基于libcurl发送带附件邮件

最近开发,为了查看日志文件,引入日志及邮件发送功能
日志使用的是boost库,邮件功能是使用libcurl库,分享下

后续把压缩上传功能加上

邮件发送功能,示例代码使用了一个第三方的类和个api的两个例子,可以参考 [github](https://github.com/billnie/Exam)

/* * This is the list of basic details you need to tweak to get things right. */
#define USERNAME "xj.nie@exam.com.cn"
#define PASSWORD "***"
#define SMTPSERVER "smtp.exam.com.cn"
#define SMTPPORT ":25" /* it is a colon+port string, but you can set it
to "" to use the default port */
#define RECIPIENT "<706919534@qq.com>"
#define MAILFROM "<xj.nie@exam.com.cn>"

#define MULTI_PERFORM_HANG_TIMEOUT 60 * 1000

/* Note that you should include the actual meta data headers here as well if you want the mail to have a Subject, another From:, show a To: or whatever you think your mail should feature! */

static struct timeval tvnow(void)
{
    /* ** time() returns the value of time in seconds since the Epoch. */
    struct timeval now;
    now.tv_sec = (long)time(NULL);
    now.tv_usec = 0;
    return now;
}

static long tvdiff(struct timeval newer, struct timeval older)
{
    return (newer.tv_sec-older.tv_sec)*1000+
    (newer.tv_usec-older.tv_usec)/1000;
}

#define FROM "<xj.nie@exam.com.cn>"
#define TO "<706919534@qq.com>"
#define CC "<xj.nie@exam.com.cn>"
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: App-log\r\n",
    "\r\n", /* empty line to divide headers from body, see RFC5322 */
    "This is the App ios app logs.\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 vmain(void)
{
    CURL *curl;
    CURLM *mcurl;
    int still_running = 1;
    struct timeval mp_start;
    struct curl_slist *recipients = NULL;
    struct upload_status upload_ctx;

    upload_ctx.lines_read = 0;

    curl_global_init(CURL_GLOBAL_DEFAULT);

    curl = curl_easy_init();
    if(!curl)
        return 1;

    mcurl = curl_multi_init();
    if(!mcurl)
        return 2;

    /* This is the URL for your mailserver */
    curl_easy_setopt(curl, CURLOPT_URL, "smtp://smtp.protruly.com.cn: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);
// 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);
    curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
    curl_easy_setopt(curl, CURLOPT_USERNAME, USERNAME);
    curl_easy_setopt(curl, CURLOPT_PASSWORD, PASSWORD);
    /* Tell the multi stack about our easy handle */
    curl_multi_add_handle(mcurl, curl);

    /* Record the start time which we can use later */
    mp_start = tvnow();

    /* We start some action by calling perform right away */
    curl_multi_perform(mcurl, &still_running);

    while(still_running) {
        struct timeval timeout;
        fd_set fdread;
        fd_set fdwrite;
        fd_set fdexcep;
        int maxfd = -1;
        int rc;
        CURLMcode mc; /* curl_multi_fdset() return code */

        long curl_timeo = -1;

        /* Initialise the file descriptors */
        FD_ZERO(&fdread);
        FD_ZERO(&fdwrite);
        FD_ZERO(&fdexcep);

        /* Set a suitable timeout to play around with */
        timeout.tv_sec = 1;
        timeout.tv_usec = 0;

        curl_multi_timeout(mcurl, &curl_timeo);
        if(curl_timeo >= 0) {
            timeout.tv_sec = curl_timeo / 1000;
            if(timeout.tv_sec > 1)
                timeout.tv_sec = 1;
            else
                timeout.tv_usec = (curl_timeo % 1000) * 1000;
        }

        /* get file descriptors from the transfers */
        mc = curl_multi_fdset(mcurl, &fdread, &fdwrite, &fdexcep, &maxfd);

        if(mc != CURLM_OK) {
            fprintf(stderr, "curl_multi_fdset() failed, code %d.\n", mc);
            break;
        }

        /* On success the value of maxfd is guaranteed to be >= -1. We call select(maxfd + 1, ...); specially in case of (maxfd == -1) there are no fds ready yet so we call select(0, ...) --or Sleep() on Windows-- to sleep 100ms, which is the minimum suggested value in the curl_multi_fdset() doc. */

        if(maxfd == -1) {
#ifdef _WIN32
            Sleep(100);
            rc = 0;
#else
            /* Portable sleep for platforms other than Windows. */
            struct timeval wait = { 0, 100 * 1000 }; /* 100ms */
            rc = select(0, NULL, NULL, NULL, &wait);
#endif
        }
        else {
            /* Note that on some platforms 'timeout' may be modified by select(). If you need access to the original value save a copy beforehand. */
            rc = select(maxfd+1, &fdread, &fdwrite, &fdexcep, &timeout);
        }

        if(tvdiff(tvnow(), mp_start) > MULTI_PERFORM_HANG_TIMEOUT) {
            fprintf(stderr,
                    "ABORTING: Since it seems that we would have run forever.\n");
            break;
        }  

        switch(rc) {  
            case -1:  /* select error */  
                break;  
            case 0:   /* timeout */  
            default:  /* action */  
                curl_multi_perform(mcurl, &still_running);  
                break;  
        }  
    }  

    /* Free the list of recipients */  
    curl_slist_free_all(recipients);  

    /* Always cleanup */  
    curl_multi_remove_handle(mcurl, curl);  
    curl_multi_cleanup(mcurl);  
    curl_easy_cleanup(curl);  
    curl_global_cleanup();  

    return 0;  
}
int main()
{
// vmain();
// xmain();
    std::vector<std::string> secret =
    {
    };

    std::vector<std::string> to =
    {
        "706919534@qq.com"
    };

    std::vector<std::string> cc =
    {

    };

    std::vector<std::string> attach =
    {
        "/Users/zzx/up.txt"
    };

    CurlSmtp* mail = new CurlSmtp("xj.nie@exam.com.cn"
        , "****"
        , to
        , secret
        , cc
        , attach
        , "DialChat-app log"
        , "This is App ios app log file"
        , "smtp.exam.com.cn"
        , "25");    //qq587

    mail->send_mail();
    sleep(5);

    // send another mail
// mail->set_from("bingley_li@maxmob.cn");
// mail->set_password("adfsf");
// mail->set_subject("test2");
// mail->set_message("another boy hehe hahah");
// mail->set_server(SMTP_SERVER);
// mail->set_port(SMTP_PORT);
//
// cc.clear();
// cc.push_back("godsb@qq.com");
// mail->set_cc(cc);
//
// to.clear();
// to.push_back("honeyligo@sina.com");
// mail->set_to(to);
// 
// attach.clear();
// attach.push_back("./1.png");
// mail->set_attach(attach);
// 
// mail->send_mail();

    sleep(5);
    delete mail;

    return 0;
}

ios使用

int sendmail(const char *url)
{

    std::vector<std::string> secret =
    {
    };

    std::vector<std::string> to =
    {
        "706919534@qq.com"
    };

    std::vector<std::string> cc =
    {

    };

    std::vector<std::string> attach =
    {
    };
    if(url ){
        attach.push_back(url);
    }
    CurlSmtp* mail = new CurlSmtp("xj.nie@exam.com.cn"
                                  , "bql-1234"
                                  , to
                                  , secret
                                  , cc
                                  , attach
                                  , "App-app log"
                                  , "This is App ios app log file"
                                  , "smtp.exam.com.cn"
                                  , "25");    //qq587

    mail->send_mail();

    delete mail;

    return 0;
}


//调用
-(RACSignal* ) requsetMailLog:(NSString *)file{
    RACSignal *signal;
    signal = [RACSignal createSignal: ^RACDisposable *(id<RACSubscriber> subscriber) {
        dispatch_async(dispatch_get_global_queue(0, 0),^(void){
            int ret;
            ret = sendmail([file cStringUsingEncoding:NSUTF8StringEncoding]);
            [subscriber sendNext:[NSNumber numberWithInt:ret]];
            [subscriber sendCompleted];
        });
        return nil;
    }];
    return signal;
}
上一篇:点击图片放大 下一篇:Intent的简介以及属性的详解