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
繁體地址,請注明出處:http://hk.pswp.cn/web/82885.shtml
英文地址,請注明出處:http://en.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波形的頻率、占空比、脈沖間隔、電平持續時間等參數 每個高級定時器和…