编写mingw C++ 程序,用 libcurl 发送一封带有附件的邮件
下面是一个使用 MinGW 编译的 C++ 程序,使用 libcurl 发送带附件的邮件。这个程序完全通过代码实现 SMTP 邮件发送,不依赖外部邮件客户端:
cpp
// 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 = "[email protected]";
const char *password = "your_app_password";
const char *from = "[email protected]";
const char *to = "[email protected]";
const char *subject = "测试邮件 - 带附件";
const char *body_text = "这是一封使用 MinGW 和 libcurl 发送的测试邮件,包含附件。";
const char *attachment_path = "test.txt"; // 附件路径
// 初始化 libcurl
curl_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";
// 打开附件文件并编码为 Base64
ifstream 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); // 仅用于测试,生产环境应设为1L
curl_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 的包含路径和库路径
-
编译命令:
bashg++ -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:
-
替换以下信息:
[email protected]
:你的邮箱地址your_app_password
:邮箱密码或应用专用密码[email protected]
:收件人邮箱test.txt
:附件文件路径(确保文件存在)
关键功能说明
-
MIME 消息构建:
- 程序构建了符合 MIME 标准的邮件结构
- 包含文本正文和附件部分
- 使用随机生成的边界分隔符
-
Base64 编码:
- 附件内容使用 Base64 编码
- 使用 curl_easy_escape 进行编码
-
SMTP 设置:
- 使用 SMTPS (SSL/TLS)
- 设置发件人、收件人列表
- 提供用户名和密码进行认证
-
错误处理:
- 检查文件是否成功打开
- 检查 Base64 编码是否成功
- 检查 curl 操作返回值
注意事项
-
安全性:
-
示例中禁用了 SSL 证书验证(仅用于测试)
-
生产环境中应启用验证并提供 CA 证书
cppcurl_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 编码
- 文件名如有中文可能需要特殊处理
-
调试:
cppcurl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); // 启用详细输出
这个程序可以直接在 MinGW 环境下编译运行,实现了完整的 SMTP 邮件发送功能,包括文本正文和文件附件。
编写 VC++ 程序,用 libcurl 发送一封带有附件的邮件
下面是一个使用 libcurl 库在 VC++ 中发送带附件邮件的完整示例。这个程序直接通过 SMTP 协议发送邮件,不依赖邮件客户端:
cpp
#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, "[email protected]");
curl_easy_setopt(curl, CURLOPT_PASSWORD, "your_app_password");
// 启用SSL/TLS
curl_easy_setopt(curl, CURLOPT_USE_SSL, CURLUSESSL_ALL);
// 设置发件人
curl_easy_setopt(curl, CURLOPT_MAIL_FROM, "[email protected]");
// 添加收件人
recipients = curl_slist_append(recipients, "[email protected]");
curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
// 创建邮件头
headers = curl_slist_append(headers, "Subject: 带附件的测试邮件");
headers = curl_slist_append(headers, "To: [email protected]");
headers = curl_slist_append(headers, "From: [email protected]");
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;
else
std::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:
cppcurl_global_init(CURL_GLOBAL_DEFAULT); curl = curl_easy_init();
-
配置SMTP服务器:
cppcurl_easy_setopt(curl, CURLOPT_URL, "smtps://smtp.gmail.com:465");
-
设置认证信息:
cppcurl_easy_setopt(curl, CURLOPT_USERNAME, "[email protected]"); curl_easy_setopt(curl, CURLOPT_PASSWORD, "your_app_password");
-
添加收件人:
cpprecipients = curl_slist_append(recipients, "[email protected]"); curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
-
构建邮件头:
cppheaders = curl_slist_append(headers, "Subject: 带附件的测试邮件"); // ...其他头部信息...
-
添加附件:
cppcurl_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:
-
替换以下信息:
[email protected]
:你的邮箱地址your_app_password
:邮箱密码或应用专用密码[email protected]
:收件人邮箱C:\\test.txt
:附件文件路径
常见问题解决:
-
认证失败:
- 确保邮箱启用了SMTP访问
- 检查用户名密码是否正确
- 尝试使用应用专用密码
-
附件无法打开:
- 确认文件路径正确
- 检查文件访问权限
- 使用绝对路径
-
SSL连接问题:
- 确保libcurl编译时支持SSL
- 更新CA证书:https://curl.se/docs/caextract.html
- 添加证书路径:
curl_easy_setopt(curl, CURLOPT_CAINFO, "cacert.pem");
-
调试信息:
cppcurl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); // 启用详细输出
这个程序可以直接集成到VC++项目中,实现无需用户交互的邮件发送功能。