如何在libcurl邮件发送代码中使用变量构造邮件内容?
动态构造libcurl邮件内容的实现方案
我看了你这段基于libcurl的邮件发送代码,要实现动态插入日期、用户名这类变量来构造邮件内容,其实有几个很顺手的方案,我给你一步步拆解:
方案一:提前构造完整的邮件内容缓冲区(最直观)
这个思路是在调用curl_easy_perform之前,先把包含变量的完整邮件内容拼接好,再让读取函数逐行返回。好处是逻辑简单,容易调试,适合内容不长的场景。
步骤1:修改状态结构体
首先扩展UploadStatus,让它能存储我们预先生成的内容行:
typedef struct { int lines_read; const char **payload; // 存储预先生成的动态内容行 } UploadStatus;
步骤2:在主函数中构造动态内容
利用asprintf(自动管理内存的字符串拼接工具)生成带变量的内容行:
// 生成动态变量 time_t clock; struct tm *tm; time(&clock); tm = localtime(&clock); const char *user_name = "Lucas"; // 动态拼接正文行 char *body_line = NULL; asprintf(&body_line, "Day %d Welcome %s\r\n", tm->tm_mday, user_name); // 构造完整的邮件内容数组 const char *payload[] = { "Message Test\r\n", "\r\n", // 必须的空行:分隔邮件头和正文(遵循RFC5322) body_line, NULL }; // 把内容传给状态结构体 UploadStatus upload_ctx = {0}; upload_ctx.payload = payload;
步骤3:修改读取函数
让读取函数直接从预先生成的数组里取内容:
size_t payload_source(void *ptr, size_t size, size_t nmemb, void *userp) { if((size == 0) || (nmemb == 0) || ((size * nmemb) < 1)) return 0; UploadStatus *upload = (UploadStatus*) userp; const char *data = upload->payload[upload->lines_read]; if(data) { size_t len = strlen(data); memcpy(ptr, data, len); upload->lines_read++; return len; } return 0; }
步骤4:清理内存
发送完成后别忘了释放asprintf分配的内存:
free(body_line);
方案二:在读取函数中动态生成内容(适合大内容/实时数据)
如果邮件内容需要实时生成,或者不想提前占用内存,可以把变量传到状态结构体里,在读取函数中按需生成每一行内容。
步骤1:修改状态结构体,加入动态变量
typedef struct { int lines_read; struct tm *tm; // 日期信息 const char *user_name; // 用户名 } UploadStatus;
步骤2:主函数中初始化状态结构体
time_t clock; struct tm *tm; time(&clock); tm = localtime(&clock); const char *user_name = "Lucas"; UploadStatus upload_ctx = {0}; upload_ctx.tm = tm; upload_ctx.user_name = user_name;
步骤3:修改读取函数,动态生成每行内容
size_t payload_source(void *ptr, size_t size, size_t nmemb, void *userp) { if((size == 0) || (nmemb == 0) || ((size * nmemb) < 1)) return 0; UploadStatus *upload = (UploadStatus*) userp; char buffer[256]; // 临时缓冲区存储动态内容 const char *data = NULL; // 根据读取行数生成对应内容 switch(upload->lines_read) { case 0: data = "Message Test\r\n"; break; case 1: data = "\r\n"; break; case 2: snprintf(buffer, sizeof(buffer), "Day %d Welcome %s\r\n", upload->tm->tm_mday, upload->user_name); data = buffer; break; default: data = NULL; break; } if(data) { size_t len = strlen(data); memcpy(ptr, data, len); upload->lines_read++; return len; } return 0; }
完整可运行代码(方案一)
这里给你整合好的完整代码,替换账号密码后就能直接测试:
#include <curl/curl.h> #include <time.h> #include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { int lines_read; const char **payload; } UploadStatus; size_t payload_source(void *ptr, size_t size, size_t nmemb, void *userp) { if((size == 0) || (nmemb == 0) || ((size * nmemb) < 1)) return 0; UploadStatus *upload = (UploadStatus*) userp; const char *data = upload->payload[upload->lines_read]; if(data) { size_t len = strlen(data); memcpy(ptr, data, len); upload->lines_read++; return len; } return 0; } int main(void) { CURLcode res = CURLE_OK; struct curl_slist *recipients = NULL; UploadStatus upload_ctx = {0}; const char *from = "test@gmail.com"; const char *to = "UrTxtEmail"; // 替换为实际收件人地址 // 生成动态变量 time_t clock; struct tm *tm; time(&clock); tm = localtime(&clock); const char *user_name = "Lucas"; // 动态构造邮件内容 char *body_line = NULL; asprintf(&body_line, "Day %d Welcome %s\r\n", tm->tm_mday, user_name); const char *payload[] = { "Message Test\r\n", "\r\n", // 分隔头和正文的空行 body_line, NULL }; upload_ctx.payload = payload; CURL *curl = curl_easy_init(); if(curl) { // 设置SMTP账号信息 curl_easy_setopt(curl, CURLOPT_USERNAME, from); curl_easy_setopt(curl, CURLOPT_PASSWORD, "your-app-password"); // Gmail建议用应用专用密码 curl_easy_setopt(curl, CURLOPT_URL, "smtp://smtp.gmail.com:587/"); // 启用STARTTLS加密 curl_easy_setopt(curl, CURLOPT_USE_SSL, (long) CURLUSESSL_ALL); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); curl_easy_setopt(curl, CURLOPT_MAIL_FROM, from); recipients = curl_slist_append(recipients, to); 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); // 调试用:开启后会输出SMTP交互详情 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); } // 释放动态分配的内存 free(body_line); return (int) res; }
注意事项
- 如果使用Gmail,开启两步验证后必须用应用专用密码,不能用普通账号密码。
asprintf是GNU扩展,Windows环境可以用_snprintf_s替代,或者手动分配内存拼接字符串。- 邮件格式必须严格遵循RFC5322:邮件头和正文之间必须有一个单独的
\r\n空行。
内容的提问来源于stack exchange,提问作者Lucas L
相关产品推荐
相关产品推荐

