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;
}

编译和运行说明

  1. 安装依赖

    • 安装 MinGW:https://www.mingw-w64.org/
    • 下载 libcurl:https://curl.se/windows/ (选择 MinGW 版本)
    • 将 libcurl 的头文件和库文件放入 MinGW 的包含路径和库路径
  2. 编译命令

    g++ -o send_email.exe send_email.cpp -lcurl -lssl -lcrypto -lz -lws2_32
    
  3. 配置邮箱

    • 对于 Gmail:
      • 开启 “允许不够安全的应用”:https://myaccount.google.com/lesssecureapps
      • 或创建应用专用密码:https://myaccount.google.com/apppasswords
    • 其他邮箱服务需参考其 SMTP 设置
  4. 替换以下信息

    • your_email@gmail.com:你的邮箱地址
    • your_app_password:邮箱密码或应用专用密码
    • recipient@example.com:收件人邮箱
    • test.txt:附件文件路径(确保文件存在)

关键功能说明

  1. MIME 消息构建

    • 程序构建了符合 MIME 标准的邮件结构
    • 包含文本正文和附件部分
    • 使用随机生成的边界分隔符
  2. Base64 编码

    • 附件内容使用 Base64 编码
    • 使用 curl_easy_escape 进行编码
  3. SMTP 设置

    • 使用 SMTPS (SSL/TLS)
    • 设置发件人、收件人列表
    • 提供用户名和密码进行认证
  4. 错误处理

    • 检查文件是否成功打开
    • 检查 Base64 编码是否成功
    • 检查 curl 操作返回值

注意事项

  1. 安全性

    • 示例中禁用了 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");
      
  2. 大文件支持

    • 当前实现将整个文件读入内存
    • 对于大文件,应使用流式处理
  3. 编码问题

    • 确保文本内容使用 UTF-8 编码
    • 文件名如有中文可能需要特殊处理
  4. 调试

    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;
}

关键步骤说明:

  1. 初始化libcurl

    curl_global_init(CURL_GLOBAL_DEFAULT);
    curl = curl_easy_init();
    
  2. 配置SMTP服务器

    curl_easy_setopt(curl, CURLOPT_URL, "smtps://smtp.gmail.com:465");
    
  3. 设置认证信息

    curl_easy_setopt(curl, CURLOPT_USERNAME, "your_email@gmail.com");
    curl_easy_setopt(curl, CURLOPT_PASSWORD, "your_app_password");
    
  4. 添加收件人

    recipients = curl_slist_append(recipients, "recipient@example.com");
    curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients);
    
  5. 构建邮件头

    headers = curl_slist_append(headers, "Subject: 带附件的测试邮件");
    // ...其他头部信息...
    
  6. 添加附件

    curl_mime *mime = curl_mime_init(curl);
    curl_mimepart *part = curl_mime_addpart(mime);
    curl_mime_filedata(part, file_path);
    

使用前的准备工作:

  1. 安装libcurl

    • 下载libcurl:https://curl.se/windows/
    • 在VC++项目中配置:
      • 包含目录:添加curl头文件路径
      • 库目录:添加lib文件路径
      • 链接器输入:添加libcurl.lib
  2. 邮箱设置

    • 对于Gmail:
      • 启用"不太安全的应用":https://myaccount.google.com/lesssecureapps
      • 或创建应用专用密码:https://myaccount.google.com/apppasswords
    • 其他邮箱服务需参考其SMTP设置
  3. 替换以下信息

    • your_email@gmail.com:你的邮箱地址
    • your_app_password:邮箱密码或应用专用密码
    • recipient@example.com:收件人邮箱
    • C:\\test.txt:附件文件路径

常见问题解决:

  1. 认证失败

    • 确保邮箱启用了SMTP访问
    • 检查用户名密码是否正确
    • 尝试使用应用专用密码
  2. 附件无法打开

    • 确认文件路径正确
    • 检查文件访问权限
    • 使用绝对路径
  3. SSL连接问题

    • 确保libcurl编译时支持SSL
    • 更新CA证书:https://curl.se/docs/caextract.html
    • 添加证书路径:curl_easy_setopt(curl, CURLOPT_CAINFO, "cacert.pem");
  4. 调试信息

    curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L); // 启用详细输出
    

这个程序可以直接集成到VC++项目中,实现无需用户交互的邮件发送功能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/web/82885.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

tensorflow image_dataset_from_directory 训练数据集构建

以数据集 https://www.kaggle.com/datasets/vipoooool/new-plant-diseases-dataset 为例 目录结构 训练图像数据集要求&#xff1a; 主目录下包含多个子目录&#xff0c;每个子目录代表一个类别。每个子目录中存储属于该类别的图像文件。 例如 main_directory/ ...cat/ ...…

遨游Spring AI:第一盘菜Hello World

Spring AI的正式版已经发布了&#xff0c;很显然&#xff0c;接下来我们要做的事情就是写一个Hello World。 总体思路就是在本地搭建一个简单的大模型&#xff0c;然后编写Spring AI代码与模型进行交互。 分五步&#xff1a; 1. 安装Ollama&#xff1b; 2. 安装DeepSeek&…

华为云Flexus+DeepSeek征文|基于华为云Flexus X和DeepSeek-R1打造个人知识库问答系统

目录 前言 1 快速部署&#xff1a;一键搭建Dify平台 1.1 部署流程详解 1.2 初始配置与登录 2 构建专属知识库 2.1 进入知识库模块并创建新库 2.2 选择数据源导入内容 2.3 上传并识别多种文档格式 2.4 文本处理与索引构建 2.5 保存并完成知识库创建 3接入ModelArts S…

Java优化:双重for循环

在工作中&#xff0c;经常性的会出现在两张表中查找相同ID的数据&#xff0c;许多开发者会使用两层for循环嵌套&#xff0c;虽然实现功能没有问题&#xff0c;但是效率极低&#xff0c;一下是一个简单的优化过程&#xff0c;代码耗时凑从26856ms优化到了748ms。 功能场景 有两…

Prompt Tuning:生成的模型文件有什么构成

一、为什么Prompt Tuning会生成模型文件? 1. Prompt Tuning的本质:优化可训练的「提示参数」 核心逻辑:Prompt Tuning(提示调优)是一种轻量级的微调技术,仅优化模型输入层的提示向量(Prompt Embedding)或少量额外参数,而非更新整个预训练模型的权重。生成模型文件的原…

ARM SMMUv3简介(一)

1.概述 SMMU&#xff08;System Memory Management Unit&#xff0c;系统内存管理单元&#xff09;是ARM架构中用于管理设备访问系统内存的硬件模块。SMMU和MMU的功能类似&#xff0c;都是将虚拟地址转换成物理地址&#xff0c;不同的是MMU转换的虚拟地址来自CPU&#xff0c;S…

在 Windows 系统上运行 Docker 容器中的 Ubuntu 镜像并显示 GUI

在 Windows 上安装一个 X Server&#xff08;如 VcXsrv 或 X410&#xff09;&#xff0c;Ubuntu 容器通过网络将图形界面转发到 Windows。 步骤&#xff1a; 安装 X Server&#xff1a; 推荐使用VcXsrv&#xff0c;免费开源。 安装后运行 XLaunch&#xff0c;选择&#xff1…

Vue3学习(4)- computed的使用

1. 简述与使用 作用&#xff1a;computed 用于基于响应式数据派生出新值&#xff0c;其值会自动缓存并在依赖变化时更新。 ​缓存机制​&#xff1a;依赖未变化时直接返回缓存值&#xff0c;避免重复计算&#xff08;通过 _dirty 标志位实现&#xff09;。​响应式更新​&…

【HarmonyOS 5】出行导航开发实践介绍以及详细案例

以下是 ‌HarmonyOS 5‌ 出行导航的核心能力详解&#xff08;无代码版&#xff09;&#xff0c;聚焦智能交互、多端协同与场景化创新&#xff1a; 一、交互革新&#xff1a;从被动响应到主动服务 ‌意图驱动导航‌ ‌自然语义理解‌&#xff1a;用户通过语音指令&#xff08;如…

csrf攻击学习

原理 csrf又称跨站伪造请求攻击&#xff0c;现代网站利用Cookie、Session 或 Token 等机制识别用户身份&#xff0c;一旦用户访问某个网站&#xff0c;浏览器在之后请求会自动带上这些信息来识别用户身份。用户在网站进行请求或者操作时服务器会给出对应的内容&#xff0c;比如…

深入剖析MySQL锁机制,多事务并发场景锁竞争

一、隐藏字段对 InnoDB 的行锁&#xff08;Record Lock&#xff09;与间隙锁&#xff08;Gap Lock&#xff09;的影响 1. 隐藏字段与锁的三大核心影响 类型影响维度描述DB_TRX_IDMVCC 可见性控制决定是否读取当前版本&#xff0c;或在加锁时避开不可见版本&#xff08;影响加锁…

以SMMUv2为例,使用Trace32可视化操作SMMU的常用命令详解

Trace32支持一系列的SMMU命令&#xff0c;可以帮助用户更好地配置、查看和分析SMMU。换句话说&#xff0c;就是让SMMU的配置变得可视化。 在添加SMMU实例之前&#xff0c;需要选择一个CPU来激活该SMMU实例的相关命令。Trace32让SMMU的配置可视化的本质是&#xff0c;操纵CPU读取…

将数据库表导出为C#实体对象

数据库方式 use 数据库;declare TableName sysname 表名 declare Result varchar(max) /// <summary> /// TableName /// </summary> public class TableName {select Result Result /// <summary>/// CONVERT(NVARCHAR(500), ISNULL(ColN…

CSS 预处理器与工具

目录 CSS 预处理器与工具1. Less主要特性 2. Sass/SCSS主要特性 3. Tailwind CSS主要特性 4. 其他工具PostCSSCSS Modules 5. 选择建议 CSS 预处理器与工具 1. Less Less 是一个 CSS 预处理器&#xff0c;它扩展了 CSS 语言&#xff0c;添加了变量、嵌套规则、混合&#xff0…

this.$set() 的用法详解(Vue响应式系统相关)

1. 什么是 this.$set()&#xff1f; this.$set(target, key, value) 是 Vue 2 中提供的一个方法&#xff0c;用于向响应式对象中动态添加属性&#xff0c;确保新加的属性同样是响应式的。 2. 为什么需要它&#xff1f; Vue 2 的响应式系统基于 Object.defineProperty&#…

【HarmonyOS Next之旅】DevEco Studio使用指南(三十)

目录 1 -> 部署云侧工程 2 -> 通过CloudDev面板获取云开发资源支持 3 -> 通用云开发模板 3.1 -> 适用范围 3.2 -> 效果图 4 -> 总结 1 -> 部署云侧工程 可以选择在云函数和云数据库全部开发完成后&#xff0c;将整个云工程资源统一部署到AGC云端。…

如何配置nginx解决前端跨域请求问题

我们以一个简单的例子模拟不同情况下产生的跨域问题以及解决方案。假设在http://127.0.0.1:8000的页面调用接口 fetch(http://127.0.0.1:8003/api/data)常看到的错误“Access to fetch at ‘http://127.0.0.1:8003/api/data’ from origin ‘http://localhost:8000’ has been…

React Hooks 指南:何时使用 useEffect ?

在 React 的函数组件中&#xff0c;useEffect Hook 是一个强大且不可或缺的工具。它允许我们处理副作用 (side effects)——那些在组件渲染之外发生的操作。但是&#xff0c;什么时候才是使用 useEffect 的正确时机呢&#xff1f;让我们深入探讨一下&#xff01; 什么是副作用…

bat批量去掉本文件夹中的文件扩展名

本文本夹内 批量去掉本文件夹中的文件扩展名 假如你有一些文件&#xff0c;你想去掉他们的扩展名 有没有方便的办法呢 今天我们就分享一种办法。 下面&#xff0c;就来看看吧。 首先我们新建一个记事本&#xff0c;把名字改为&#xff0c;批量去掉本文件夹中的文件扩展名.txt 然…

STM32标准库-输入捕获

一、输入捕获 1.简介 IC&#xff08;Input Capture&#xff09;输入捕获输入 捕获模式下&#xff0c;当通道输入引脚出现指定电平跳变时&#xff0c;当前CNT的值将被锁存到CCR中&#xff0c;可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数 每个高级定时器和…