C++:用 libcurl 发送一封带有附件的邮件
编写mingw C++ 程序,用 libcurl 发送一封带有附件的邮件
下面是一个使用 MinGW 编译的 C++ 程序,使用 libcurl 发送带附件的邮件。这个程序完全通过代码实现 SMTP 邮件发送,不依赖外部邮件客户端:
// send_email.cpp
#include <iostream>
#include <fstream>
#include <curl/curl.h>
#include <cstring>
#include <vector>
using namespace std;// 用于读取文件内容的回调函数
static size_t read_callback(char *ptr, size_t size, size_t nmemb, void *userdata) {ifstream *file = static_cast<ifstream*>(userdata);if (!file || !file->is_open()) {return CURL_READFUNC_ABORT;}file->read(ptr, size * nmemb);size_t bytes_read = file->gcount();return bytes_read;
}// 用于生成随机边界字符串
string generate_boundary() {static const char alphanum[] ="0123456789""ABCDEFGHIJKLMNOPQRSTUVWXYZ""abcdefghijklmnopqrstuvwxyz";const int len = 24;string result;result.reserve(len);for (int i = 0; i < len; ++i) {result += alphanum[rand() % (sizeof(alphanum) - 1)];}return "----=" + result;
}int main() {CURL *curl;CURLcode res = CURLE_OK;// 邮件配置 - 替换为你的实际信息const char *smtp_server = "smtp.gmail.com";const char *username = "your_email@gmail.com";const char *password = "your_app_password";const char *from = "your_email@gmail.com";const char *to = "recipient@example.com";const char *subject = "测试邮件 - 带附件";const char *body_text = "这是一封使用 MinGW 和 libcurl 发送的测试邮件,包含附件。";const char *attachment_path = "test.txt"; // 附件路径// 初始化 libcurlcurl_global_init(CURL_GLOBAL_DEFAULT);curl = curl_easy_init();if (!curl) {cerr << "无法初始化 libcurl" << endl;return 1;}// 生成 MIME 边界string boundary = generate_boundary();// 构建完整的邮件内容string mime_message;// 邮件头部mime_message = "From: " + string(from) + "\r\n";mime_message += "To: " + string(to) + "\r\n";mime_message += "Subject: " + string(subject) + "\r\n";mime_message += "MIME-Version: 1.0\r\n";mime_message += "Content-Type: multipart/mixed; boundary=\"" + boundary + "\"\r\n\r\n";// 正文部分mime_message += "--" + boundary + "\r\n";mime_message += "Content-Type: text/plain; charset=utf-8\r\n";mime_message += "Content-Transfer-Encoding: 8bit\r\n\r\n";mime_message += string(body_text) + "\r\n\r\n";// 附件部分mime_message += "--" + boundary + "\r\n";mime_message += "Content-Type: application/octet-stream; name=\"test.txt\"\r\n";mime_message += "Content-Disposition: attachment; filename=\"test.txt\"\r\n";mime_message += "Content-Transfer-Encoding: base64\r\n\r\n";// 打开附件文件并编码为 Base64ifstream file(attachment_path, ios::binary);if (!file.is_open()) {cerr << "无法打开附件文件: " << attachment_path << endl;return 1;}// 读取文件内容vector<char> buffer((istreambuf_iterator<char>(file)),istreambuf_iterator<char>());file.close();// Base64 编码char *base64_data = curl_easy_escape(curl, buffer.data(), buffer.size());if (!base64_data) {cerr << "Base64 编码失败" << endl;return 1;}mime_message += base64_data;curl_free(base64_data);// 结束 MIME 消息mime_message += "\r\n\r\n";mime_message += "--" + boundary + "--\r\n";// 设置 libcurl 选项curl_easy_setopt(curl, CURLOPT_URL, string("smtps://" + string(smtp_server)).c_str());curl_easy_setopt(curl, CURLOPT_USERNAME, username);curl_easy_setopt(curl, CURLOPT_PASSWORD, password);curl_easy_setopt(curl, CURLOPT_MAIL_FROM, from);struct curl_slist *recipients = NULL;recipients = curl_slist_append(recipients, to);curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL);curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L); // 仅用于测试,生产环境应设为1Lcurl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L); // 仅用于测试,生产环境应设为2L// 设置读取回调istringstream mime_stream(mime_message);curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_callback);curl_easy_setopt(curl, CURLOPT_READDATA, &mime_stream);curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);// 设置邮件大小curl_easy_setopt(curl, CURLOPT_INFILESIZE_LARGE, (curl_off_t)mime_message.size());// 发送邮件res = curl_easy_perform(curl);// 检查结果if (res != CURLE_OK) {cerr << "邮件发送失败: " << curl_easy_strerror(res) << endl;} else {cout << "邮件发送成功!" << endl;}// 清理资源curl_slist_free_all(recipients);curl_easy_cleanup(curl);curl_global_cleanup();return (int)res;
}
编译和运行说明
-
安装依赖:
- 安装 MinGW:https://www.mingw-w64.org/
- 下载 libcurl:https://curl.se/windows/ (选择 MinGW 版本)
- 将 libcurl 的头文件和库文件放入 MinGW 的包含路径和库路径
-
编译命令:
g++ -o send_email.exe send_email.cpp -lcurl -lssl -lcrypto -lz -lws2_32
-
配置邮箱:
- 对于 Gmail:
- 开启 “允许不够安全的应用”:https://myaccount.google.com/lesssecureapps
- 或创建应用专用密码:https://myaccount.google.com/apppasswords
- 其他邮箱服务需参考其 SMTP 设置
- 对于 Gmail:
-
替换以下信息:
your_email@gmail.com
:你的邮箱地址your_app_password
:邮箱密码或应用专用密码recipient@example.com
:收件人邮箱test.txt
:附件文件路径(确保文件存在)
关键功能说明
-
MIME 消息构建:
- 程序构建了符合 MIME 标准的邮件结构
- 包含文本正文和附件部分
- 使用随机生成的边界分隔符
-
Base64 编码:
- 附件内容使用 Base64 编码
- 使用 curl_easy_escape 进行编码
-
SMTP 设置:
- 使用 SMTPS (SSL/TLS)
- 设置发件人、收件人列表
- 提供用户名和密码进行认证
-
错误处理:
- 检查文件是否成功打开
- 检查 Base64 编码是否成功
- 检查 curl 操作返回值
注意事项
-
安全性:
- 示例中禁用了 SSL 证书验证(仅用于测试)
- 生产环境中应启用验证并提供 CA 证书
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 1L); curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 2L); curl_easy_setopt(curl, CURLOPT_CAINFO, "path/to/cacert.pem");
-
大文件支持:
- 当前实现将整个文件读入内存
- 对于大文件,应使用流式处理
-
编码问题:
- 确保文本内容使用 UTF-8 编码
- 文件名如有中文可能需要特殊处理
-
调试:
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); // 启用详细输出
这个程序可以直接在 MinGW 环境下编译运行,实现了完整的 SMTP 邮件发送功能,包括文本正文和文件附件。
编写 VC++ 程序,用 libcurl 发送一封带有附件的邮件
下面是一个使用 libcurl 库在 VC++ 中发送带附件邮件的完整示例。这个程序直接通过 SMTP 协议发送邮件,不依赖邮件客户端:
#include <iostream>
#include <string>
#include <curl/curl.h>// 用于存储邮件内容的回调函数
static size_t read_callback(void *ptr, size_t size, size_t nmemb, void *userp)
{FILE *readhere = (FILE *)userp;return fread(ptr, size, nmemb, readhere);
}int main()
{CURL *curl;CURLcode res = CURLE_OK;struct curl_slist *recipients = NULL;FILE *hd_src = NULL;struct curl_slist *headers = NULL;const char *file_path = "C:\\test.txt"; // 替换为你的附件路径curl_global_init(CURL_GLOBAL_DEFAULT);curl = curl_easy_init();if (curl) {// 设置SMTP服务器和端口 (这里以Gmail为例)curl_easy_setopt(curl, CURLOPT_URL, "smtps://smtp.gmail.com:465");// 设置登录凭据 (替换为你的邮箱和密码/应用密码)curl_easy_setopt(curl, CURLOPT_USERNAME, "your_email@gmail.com");curl_easy_setopt(curl, CURLOPT_PASSWORD, "your_app_password");// 启用SSL/TLScurl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL);// 设置发件人curl_easy_setopt(curl, CURLOPT_MAIL_FROM, "your_email@gmail.com");// 添加收件人recipients = curl_slist_append(recipients, "recipient@example.com");curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);// 创建邮件头headers = curl_slist_append(headers, "Subject: 带附件的测试邮件");headers = curl_slist_append(headers, "To: recipient@example.com");headers = curl_slist_append(headers, "From: your_email@gmail.com");headers = curl_slist_append(headers, "Mime-Version: 1.0");headers = curl_slist_append(headers, "Content-Type: multipart/mixed; boundary=\"boundary-string\"");curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);// 构建邮件正文和附件std::string body = "--boundary-string\r\n""Content-Type: text/plain; charset=utf-8\r\n""Content-Transfer-Encoding: 7bit\r\n\r\n""这是一封使用libcurl发送的测试邮件。\r\n""包含一个文本文件附件。\r\n\r\n""--boundary-string\r\n""Content-Type: text/plain; name=\"test.txt\"\r\n""Content-Disposition: attachment; filename=\"test.txt\"\r\n""Content-Transfer-Encoding: base64\r\n\r\n";// 打开附件文件hd_src = fopen(file_path, "rb");if (!hd_src) {std::cerr << "无法打开附件文件: " << file_path << std::endl;return 1;}// 创建回调数据源curl_mime *mime = curl_mime_init(curl);curl_mimepart *part = curl_mime_addpart(mime);// 设置邮件正文curl_mime_data(part, body.c_str(), body.size());// 添加附件part = curl_mime_addpart(mime);curl_mime_filedata(part, file_path);curl_mime_name(part, "attachment");curl_mime_filename(part, "test.txt");curl_mime_type(part, "text/plain");// 设置多部分结束边界part = curl_mime_addpart(mime);curl_mime_data(part, "\r\n--boundary-string--\r\n", CURL_ZERO_TERMINATED);curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);// 发送邮件res = curl_easy_perform(curl);// 检查错误if (res != CURLE_OK)std::cerr << "发送失败: " << curl_easy_strerror(res) << std::endl;elsestd::cout << "邮件发送成功!" << std::endl;// 清理资源if (hd_src) fclose(hd_src);curl_slist_free_all(recipients);curl_slist_free_all(headers);curl_mime_free(mime);curl_easy_cleanup(curl);}curl_global_cleanup();return (int)res;
}
关键步骤说明:
-
初始化libcurl:
curl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init();
-
配置SMTP服务器:
curl_easy_setopt(curl, CURLOPT_URL, "smtps://smtp.gmail.com:465");
-
设置认证信息:
curl_easy_setopt(curl, CURLOPT_USERNAME, "your_email@gmail.com"); curl_easy_setopt(curl, CURLOPT_PASSWORD, "your_app_password");
-
添加收件人:
recipients = curl_slist_append(recipients, "recipient@example.com"); curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
-
构建邮件头:
headers = curl_slist_append(headers, "Subject: 带附件的测试邮件"); // ...其他头部信息...
-
添加附件:
curl_mime *mime = curl_mime_init(curl); curl_mimepart *part = curl_mime_addpart(mime); curl_mime_filedata(part, file_path);
使用前的准备工作:
-
安装libcurl:
- 下载libcurl:https://curl.se/windows/
- 在VC++项目中配置:
- 包含目录:添加curl头文件路径
- 库目录:添加lib文件路径
- 链接器输入:添加
libcurl.lib
-
邮箱设置:
- 对于Gmail:
- 启用"不太安全的应用":https://myaccount.google.com/lesssecureapps
- 或创建应用专用密码:https://myaccount.google.com/apppasswords
- 其他邮箱服务需参考其SMTP设置
- 对于Gmail:
-
替换以下信息:
your_email@gmail.com
:你的邮箱地址your_app_password
:邮箱密码或应用专用密码recipient@example.com
:收件人邮箱C:\\test.txt
:附件文件路径
常见问题解决:
-
认证失败:
- 确保邮箱启用了SMTP访问
- 检查用户名密码是否正确
- 尝试使用应用专用密码
-
附件无法打开:
- 确认文件路径正确
- 检查文件访问权限
- 使用绝对路径
-
SSL连接问题:
- 确保libcurl编译时支持SSL
- 更新CA证书:https://curl.se/docs/caextract.html
- 添加证书路径:
curl_easy_setopt(curl, CURLOPT_CAINFO, "cacert.pem");
-
调试信息:
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); // 启用详细输出
这个程序可以直接集成到VC++项目中,实现无需用户交互的邮件发送功能。