You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 03:57:56