Foxmail「特快專遞」功能可直接將郵件送達收件方郵件伺服器,省去 SMTP 轉發延遲、即時掌握投遞狀態、避免免費信箱發送限制。本文完整實作:本機 DNS 列舉 → MX 記錄查詢 → 多 MX 伺服器嘗試 → SMTP 協定對話 → MIME 編碼支援附件。
標準路徑: MUA → SMTP Client → SMTP Relay (發信方) → MX (收信方) → MDA → 收件箱 特快專遞: MUA → SMTP Client → MX (收信方) → MDA → 收件箱
關鍵差異:直接連線收件方 MX 伺服器,需自行解析 MX 記錄。
使用 IPHLPAPI:GetAdaptersInfo 取得所有網卡 → GetPerAdapterInfo 取得每張網卡的 DNS 伺服器陣列。
std::vector GetLocalDnsServers() {
std::vector dnsList;
ULONG bufSize = 0; GetAdaptersInfo(nullptr, &bufSize);
std::vector buf(bufSize); PIP_ADAPTER_INFO pInfo = (PIP_ADAPTER_INFO)buf.data();
GetAdaptersInfo(pInfo, &bufSize);
for (auto p = pInfo; p; p = p->Next) {
ULONG perSize = 0; GetPerAdapterInfo(p->Index, nullptr, &perSize);
std::vector perBuf(perSize); PIP_PER_ADAPTER_INFO pPer = (PIP_PER_ADAPTER_INFO)perBuf.data();
if (GetPerAdapterInfo(p->Index, pPer, &perSize) == ERROR_SUCCESS) {
for (auto* ip = &pPer->DnsServerList; ip; ip = ip->Next)
dnsList.push_back(ip->IpAddress.String);
}
}
return dnsList;
}
DNS 訊息結構:Header (12 bytes) + Question (QNAME + QTYPE=15 MX + QCLASS=1 IN) + Answer/Authority/Additional (解析回應用)。
// 簡化版同步查詢 (生產環境建議用非阻塞 + 重試 + 隨機 Transaction ID)
std::vector> QueryMx(const std::string& domain, const std::string& dnsServer) {
// 1. 建立查詢封包
// 2. sendto UDP :53
// 3. recvfrom 解析回應
// 4. 從 Answer 區解析 MX 記錄:Preference (優先序) + Exchange (主機名)
// 5. 依 Preference 排序回傳
// 完整程式碼見附件 (含壓縮指標解析、CNAME 追蹤、Additional 區 A 記錄直接取 IP)
}
查詢 gmail.com 典型回應:
gmail-smtp-in.l.google.com 5 alt1.gmail-smtp-in.l.google.com 10 alt2.gmail-smtp-in.l.google.com 10 alt3.gmail-smtp-in.l.google.com 20 alt4.gmail-smtp-in.l.google.com 20
class SmtpDirect {
SOCKET sock_;
bool SendRecv(const std::string& cmd, const std::string& expectedPrefix = "") {
send(sock_, cmd.c_str(), cmd.size(), 0);
char buf[1024]; int n = recv(sock_, buf, sizeof(buf)-1, 0);
if (n <= 0) return false;
buf[n] = 0;
if (!expectedPrefix.empty() && strncmp(buf, expectedPrefix.c_str(), expectedPrefix.size()) != 0)
return false; // 錯誤碼
return true;
}
public:
bool Connect(const char* host, int port = 25) {
// getaddrinfo → socket → connect → 接收 220 歡迎
}
bool MailFrom(const char* from) { return SendRecv("MAIL FROM:<" + std::string(from) + ">\r\n", "250"); }
bool RcptTo(const char* to) { return SendRecv("RCPT TO:<" + std::string(to) + ">\r\n", "250"); }
bool Data(const std::string& mimeMessage) {
if (!SendRecv("DATA\r\n", "354")) return false;
send(sock_, mimeMessage.c_str(), mimeMessage.size(), 0);
send(sock_, "\r\n.\r\n", 5, 0); // 結束標記
return SendRecv("", "250");
}
void Quit() { SendRecv("QUIT\r\n", "221"); closesocket(sock_); }
};
From: "Sender"To: "Recipient" Subject: =?utf-8?B?5b6u5L+h6Lev?= Date: Mon, 01 Jan 2024 12:00:00 +0800 MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="----BOUNDARY123" ------BOUNDARY123 Content-Type: multipart/alternative; boundary="----ALT456" ------ALT456 Content-Type: text/plain; charset=utf-8 純文字備選內容 ------ALT456 Content-Type: text/html; charset=utf-8 HTML 內容
------ALT456-- ------BOUNDARY123 Content-Type: image/png; name="logo.png" Content-Transfer-Encoding: base64 Content-ID:
Content-Disposition: inline; filename="logo.png" iVBORw0KGgoAAAANSUhEUg... (Base64 編碼) ------BOUNDARY123--
| 阻礙 | 現象 | 對策 |
|---|---|---|
| 住宅 IP 信譽差 | Gmail/Outlook 直接拒收 (550 5.7.1) | 使用具良好信譽的雲端 IP / SMTP Relay / 郵件 API (SendGrid, Mailgun) |
| 無 PTR 記錄 | 多數企業郵箱拒收 | 要求 ISP 設定 rDNS 或改用有 PTR 的伺服器 |
| SPF/DKIM/DMARC 未通過 | 進垃圾信或拒收 | 簽署 DKIM、發布 SPF/DMARC、對齊 From 網域 |
| 加密傳輸 | 部分 MX 強制 STARTTLS | 整合 OpenSSL,支援 STARTTLS 升級 |
| 灰名單 | 暫時拒收 450,需重試 | 實作指數退避重試 (10min, 30min, 1h...) |
bool SendDirect(const Email& mail) {
auto dnsList = GetLocalDnsServers();
auto mxList = QueryMx(ExtractDomain(mail.to), dnsList[0]); // 取第一組可用 DNS
for (auto& [host, pref] : mxList) {
SmtpDirect smtp;
if (!smtp.Connect(host.c_str())) continue;
if (!smtp.MailFrom(mail.from)) continue;
if (!smtp.RcptTo(mail.to)) continue;
if (!smtp.Data(BuildMime(mail))) continue;
smtp.Quit();
return true; // 成功投遞至少一台 MX
}
return false; // 全部失敗
}
「直連 MX」技術雖能繞過 SMTP Relay,但現代反垃圾機制 (IP 信譽、SPF/DKIM/DMARC、灰名單、STARTTLS) 使得住宅/伺服器直發成功率極低。實務上建議:自建郵件伺服器請完整部署 SPF/DKIM/DMARC/rDNS/信譽預熱;應用層整合請改用專業郵件 API (SendGrid, Amazon SES, Mailgun, Postmark)。本文完整原始碼 (含 DNS 解析器、SMTP 狀態機、MIME Builder、Base64、OpenSSL STARTTLS、重試邏輯、GUI 測試工具) 請參考文章附件。