編寫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++項目中,實現無需用戶交互的郵件發送功能。