我猜你會看到這篇文章,多半正在處理「表單按了送出卻寄不出」的現場問題,或準備替客戶做一次寄信健檢。
這篇文章適合:網站工程師、維運人員、技術 PM。焦點鎖定發信端(網站/主機/程式),用可直接複製的步驟把問題切半、定位並修復。

你會拿到:5 分鐘快篩流程、Windows CMD/OpenSSL/swaks 檢測指令、PHPMailer 測寄腳本、常見錯誤碼對照、實務 Checklist。
不涵蓋範圍:已成功寄出但收不到(垃圾信匣、Outlook 規則、企業防火牆、群組轉寄遺失)。
此類將在下一篇〈表單收不到信〉專文處理,以免混淆。
先快篩:5 分鐘判斷「寄不出」還是「收不到」
目標:用最少步驟把問題切半,避免在錯誤方向耗時。
步驟
📤 表單寄信失敗?先按這些步驟排查:
1
用兩個外部信箱交叉測:
各送一次到 Gmail 與 Outlook(不同網域、不同反垃圾機制)。
各送一次到 Gmail 與 Outlook(不同網域、不同反垃圾機制)。
2
開啟 DevTools → Network:
提交表單時檢查 API 回應碼與 Response 內容:
2xx 但沒收到信 → 可能是收件端(下一篇)
4xx/5xx 或 Response 內有錯誤訊息 → 多半是寄不出(本篇範圍)。
提交表單時檢查 API 回應碼與 Response 內容:
2xx 但沒收到信 → 可能是收件端(下一篇)
4xx/5xx 或 Response 內有錯誤訊息 → 多半是寄不出(本篇範圍)。
3
伺服器側做「系統級測寄」:
用 swaks 或 SMTP 指令測試(共享主機可改用 PHPMailer 測寄腳本)。
用 swaks 或 SMTP 指令測試(共享主機可改用 PHPMailer 測寄腳本)。
4
比對測試結果:
系統級測試也失敗 → 問題可能在主機 / SMTP / DNS 層面
系統級成功、唯獨網站表單失敗 → 程式/外掛/Token 權限等問題
系統級測試也失敗 → 問題可能在主機 / SMTP / DNS 層面
系統級成功、唯獨網站表單失敗 → 程式/外掛/Token 權限等問題
5
查看郵件佇列與 Error Log:
查看 Postfix / Exim 佇列、web error log 中是否有錯誤碼(如 535/550/554/421)、TLS 握手失敗等記錄。
查看 Postfix / Exim 佇列、web error log 中是否有錯誤碼(如 535/550/554/421)、TLS 握手失敗等記錄。
輸出
- 一張簡記:測試時間、收件信箱、API 回應、伺服器日誌截圖 → 方便與客戶或同事同步、避免重複排查。
使用者環境:最容易被忽略的第一層
很多「看起來送了但其實沒送」都卡在這層。
常見狀況
- 瀏覽器快取 / Cookie 過期:CSRF/Nonce 過期,回傳 419/403;或舊 JS 綁在快取裡,導致提交前就被攔。
- 擋第三方腳本或隱私外掛:reCAPTCHA、Turnstile、或前端驗證腳本被擋,按下送出其實沒觸發。
- 公司網路限制:企業 Proxy/防火牆阻擋 POST、或把表單域名列入黑名單,造成提交逾時。
- 時區/時間不同步:Token 驗證依賴時間戳,使用者端時間錯位會被判無效。
- 前端 JS 錯誤:Console 報錯導致 submit 被中斷(尤其 SPA/重前端網站)。
如何檢查
- 無痕視窗+停用瀏覽器外掛再測一次;不同瀏覽器再測一次。
- DevTools → Console/Network:
- Network 觀察 POST 是否發出、回應狀態碼、Response 文字。
- Console 是否有 JS error(跨網域、CORS、CAPTCHA 未通過)。
- 若網站有 CAPTCHA:切到網路環境(行動網路)重測,排除公司網路限制。
- 伺服器端對應時區(PHP
date.timezone
)與頁面 Token 有沒有過期判定過嚴。
快速修正
- 清快取、刷新 Nonce;必要時調整 Token TTL。
- 對前端驗證加上「失敗提示」與退回訊息,避免使用者無感卡住。
- 提供後備提交(純 HTML 表單或簡單 POST)作為故障保險。
後台郵件設定錯誤:不存在的信箱會「拖累整批」
這是最常見且最容易被忽略的實務地雷。
典型地雷
- 寄件人 From 使用不存在的信箱(如
noreply@yourdomain.com
但實際沒建立):- 很多 SMTP/ESP 會拒收或降權,甚至 DMARC 政策會直接擋。
- 混用外部網域:用
From:
xxx@gmail.com
從你自家網域主機送,SPF/DKIM 對不上,容易被退。 - 同封信群發多收件人:To/Cc/Bcc 只要有一個不存在/格式錯,整批可能報錯或中止。
- Reply-To/Return-Path 配置不當:回信與退信無法正確回到可監控的信箱,導致誤判為「沒寄出」。
- 群組/轉寄規則繞來繞去:在寄件端看似正常,但實際被轉寄機制丟失或退回(尤其混用 Google Group/Exchange)。
標準作法(工程師版 SOP)
- From 必須是同網域、且存在、且可驗證(真的建立信箱或使用 SMTP 提供商核可的 Sender)。
- Reply-To 才放客服信箱(可與 From 不同,但要可收信)。
- 逐收件人投遞:程式層「一封一收件人」發送,紀錄每一筆 send result,任何一筆失敗都能精準定位。
- 建立「退信信箱」(Return-Path/Envelope-From)並監控,退信樣板會告訴你是不存在、滿信箱、或策略性拒收。
- 檢核格式:所有收件人 email 先通過 regex/簡單 MX check;避免單一錯誤拖累整批。
程式與主機層:函式、埠號、TLS 與版本相容性
典型地雷
- 寄送方法搞不清:後台以為走 SMTP,其實程式還在用
mail()
。共享主機常預設關閉mail()
或改用sendmail
路徑,造成靜默失敗。 - 埠號與加密錯誤:
- 465=Implicit TLS、587=STARTTLS、25 常被 ISP 擋。
- 465 卻選 STARTTLS、或 587 卻選 SSL/TLS,會握手失敗。
- OpenSSL / cURL / PHP 過舊:伺服器僅支援 TLS1.0/1.1,收信端要求 TLS1.2+ 時,會出現
sslv3 alert handshake failure
、no shared cipher
。 - 主機權限與封鎖:
sendmail_path
不存在、FPM 權限不足、SELinux/AppArmor 擋路、或主機商限制外寄速率(Rate limit / Throttle)。 - 附件與編碼:過大(常見 10–25MB 上限)、中文檔名編碼錯誤、或 Content-Type 不正確導致拒收。
- 外掛相衝:兩個 SMTP/郵件外掛同時啟用,Hook 被覆蓋;或 CMS/外掛版本不相容。
怎麼測
- 直接測 TLS/埠號
# 測 587(STARTTLS)
openssl s_client -starttls smtp -connect smtp.example.com:587 -crlf
# 測 465(Implicit TLS)
openssl s_client -connect smtp.example.com:465 -crlf
- 成功=主機/SMTP 正常;若前端仍失敗=鎖定程式/外掛層。
- 看日誌
- Web/PHP:
error_log
、FPM log;搜尋SMTP
,PHPMailer
,fopen
,stream_socket_enable_crypto
. - MTA(Postfix/Exim):
- Postfix:
/var/log/maillog
或/var/log/mail.log
- Exim:
/var/log/exim_mainlog
- Postfix:
- 雲郵件服務(SendGrid、Amazon SES 等):查事件活動紀錄(Accepted/Deferred/Bounced/Blocked)。
- Web/PHP:
常見錯誤碼對照(寄件端常見)
535 5.7.8
認證失敗(帳密/機制不符、或需應用密碼/Token)。550 5.1.1
收件位址不存在。554 5.7.1
政策性拒收(黑名單、SPF/DKIM/DMARC 不符、或內容被判垃圾)。421 4.7.0
服務暫時不可用/超限,稍後重試。5.7.26
常見於 Google:DMARC 對齊失敗,被策略拒收。
DNS 與郵件驗證:SPF、DKIM、DMARC、PTR 是關鍵
你要的最小合格組合
- From 網域可驗證且存在(真的有信箱或核可的寄件身分)。
- SPF:授權「實際寄信的伺服器或服務」。避免
+all
,建議~all
或-all
。 - DKIM:為 From 的網域 簽章;選好 selector,TXT 正確發布。
- DMARC:
v=DMARC1; p=none/quarantine/reject; rua=...
;確保 對齊(Alignment)成立(adkim
/aspf
通常設s
或r
)。 - PTR(反解):寄件 IP 需有正確 rDNS,HELO/EHLO 主機名與 PTR/主機名一致性越高越不易被打分。
快速檢查指令
REM 查 SPF / DKIM / DMARC(TXT 紀錄)
nslookup -type=TXT yourdomain.com
nslookup -type=TXT default._domainkey.yourdomain.com
nslookup -type=TXT _dmarc.yourdomain.com
REM 查 MX(有些收信端會檢查 From 網域基本健全性)
nslookup -type=MX yourdomain.com
REM 查寄件 IP 的 PTR(反解)
nslookup -type=PTR 203.0.113.10
常見錯誤與修正
- SPF 重複或過長:多家 ESP 疊加
include:
,超過 10 次查詢上限會失效。→ 合併紀錄、用子網域分流。 - DKIM selector 放錯網域:簽
mail.yourdomain.com
,卻把 TXT 發在根網域或反之。→ 對齊 selector 與 d= 參數。 - DMARC p=reject 但未對齊:直接進拒收。→ 先用
p=none
收集報告,調整對齊再升級策略。 - PTR 為通用名稱:如
123-45-6-7.isp-pool.example
。→ 申請自訂反解或使用合規寄信服務。 - 新 DNS 尚未全球傳播:TTL 太長或剛改完就測。→ 降 TTL,給 15–30 分鐘至數小時緩衝。
工程師實務檢測清單
目標:把問題「切半」→「再切半」,10–30 分鐘內定位八九成根因。
A. 前端與環境
- 無痕視窗、停用瀏覽器外掛重測,觀察 DevTools Network/Console。
- 換網路(4G/5G)排除公司 Proxy/防火牆阻擋。
- CAPTCHA 是否顯示並通過回傳。
- 確認 CSRF/Nonce 是否過期;必要時放寬 TTL。
B. 後台設定與收件配置
- From 必須為同網域且存在的信箱;Reply-To 才放客服/對外信箱。
- 逐收件人獨立投遞並記錄每筆結果,避免一人錯拖累全批。
- 建立並監控退信信箱(Return-Path),保存退信樣本。
- 檢核所有收件位址格式與 MX 存在性(可做輕量驗證,不主動對方 SMTP 驗箱)。
C. 程式與主機
- 確認「實際」使用的寄送方法:
mail()
、sendmail
、SMTP、或 ESP API。 - 檢查 PHP/外掛版本;避免雙 SMTP 外掛相衝。
- 測埠與 TLS:
openssl s_client
驗證 465/587;設定與服務端能力一致。 - 系統級測寄:
swaks
或最小 PHPMailer 腳本測試。 - 檢查主機限制:Rate limit、
sendmail_path
、FPM 權限、SELinux。 - 檢查附件大小與檔名編碼。
D. DNS 與驗證
- SPF 僅授權實際寄件來源;避免超過 10 次 DNS lookup。
- DKIM 簽章與 selector、d= 網域一致;DNS TXT 正確。
- DMARC 先
p=none
蒐集報告,再逐步升級至quarantine/reject
。 - 寄件 IP 具備正確 PTR;HELO 名稱與 rDNS/hostname 合理一致。
E. 日誌與證據
- 蒐集時間戳、請求 ID、API Response、伺服器/郵件日誌片段。
- 彙整錯誤碼(535/550/554/421/5.7.26)與對應修正。
- 交叉驗證 Gmail 與 Outlook 測寄結果,保存原始信件標頭(Received/SPF/DKIM/DMARC)。
F. 驗收標準
- 連續三次跨網域(Gmail、Outlook)皆成功收件且通過 SPF/DKIM/DMARC。
- 表單、系統級測寄結果一致。
- 退信率與暫拒(4xx)比例顯著下降,無握手與認證類錯誤。
範例與模板:最小可行測寄腳本與日誌判讀
A) 最小 PHPMailer 測寄腳本(test_smtp_send.php
)
用來「繞過前端與外掛」,直接確認主機與 SMTP 是否健康。請先
composer require phpmailer/phpmailer
。
<?php
// test_smtp_send.php
// 目的:系統級測寄,定位主機/SMTP/TLS 是否可用
// 使用前:composer require phpmailer/phpmailer
use PHPMailer\PHPMailer\PHPMailer;
use PHPMailer\PHPMailer\Exception;
require __DIR__ . '/vendor/autoload.php';
$mail = new PHPMailer(true);
try {
// 基本參數
$mail->isSMTP();
$mail->Host = 'smtp.example.com'; // ← 你的 SMTP
$mail->SMTPAuth = true;
$mail->Username = 'sender@example.com'; // ← 你的帳號
$mail->Password = 'your_app_password'; // 建議用應用程式密碼或 API Key
$mail->Port = 587; // 587=STARTTLS, 465=Implicit TLS
$mail->SMTPSecure = PHPMailer::ENCRYPTION_STARTTLS; // 若用 465 改為 ENCRYPTION_SMTPS
// Debug(只在測試時開)
$mail->SMTPDebug = 2; // 0=關閉, 2=詳細握手
$mail->Debugoutput = 'error_log'; // 輸出到 PHP error_log
// 寄件人與收件人
$mail->setFrom('sender@example.com', 'SMTP Health Check'); // 必須為存在且同網域的信箱
$mail->addAddress('you@gmail.com', 'Test Receiver'); // 測向 Gmail 或 Outlook
// $mail->addAddress('you@outlook.com');
// 建議明確設定回覆與退信地址
$mail->addReplyTo('support@example.com', 'Support');
$mail->Sender = 'bounce@example.com'; // Return-Path(需存在,方便收退信)
// 內容
$mail->isHTML(true);
$mail->Subject = 'SMTP pipeline ok';
$mail->Body = 'This is a minimal SMTP test via PHPMailer.';
$mail->AltBody = 'Minimal SMTP test.';
$mail->send();
echo "OK: message accepted by SMTP.\n";
} catch (Exception $e) {
echo "FAIL: {$mail->ErrorInfo}\n";
}
如何判讀
- 結果顯示
OK: message accepted by SMTP.
→ 主機與 SMTP 正常;若表單仍失敗=程式/外掛/權限層。 - 若握手或認證錯誤,
SMTPDebug
會顯示關鍵線索(TLS 失敗、535 Auth、超時等)。
B) 系統級 SMTP 測試(swaks
)
swaks --to you@receiver.com --server smtp.example.com \
--port 587 --auth LOGIN --auth-user "sender@example.com" \
--auth-password '********' --tls \
--header "Subject: hello from swaks" \
--body "SMTP pipeline ok"
- 成功 → SMTP 端無誤;失敗訊息可比對錯誤碼(535/550/554/421)。
C) 郵件標頭判讀要點(收件端觀察)
收到測試信後,開啟「原始郵件」檢視標頭,重點看:
Authentication-Results: ... spf=pass ... dkim=pass ... dmarc=pass
Received: from smtp.example.com ...
spf=pass dkim=pass dmarc=pass
→ 驗證齊備,之後收件穩定度高。- 缺一常致投遞品質下滑;若
dmarc=fail
且對方政策嚴格,可能直接拒收。
D) 日誌關鍵字與範例
Web/PHP
stream_socket_enable_crypto(): SSL operation failed
→ TLS 參數或版本不相容。Connection could not be established with host
→ DNS/Port/防火牆或主機封鎖。SMTP Error: Could not authenticate
→ 535 認證錯;常見是應用密碼未啟用或機制不符。
Postfix(/var/log/mail.log)
status=sent (250 2.0.0 Ok: queued as ...)
→ 投遞成功status=deferred (421 4.7.0 ...)
→ 暫拒,稍後重試status=bounced (550 5.1.1 User unknown)
→ 收件人不存在
Exim(/var/log/exim_mainlog)
<=
收信、=>
投遞、**
退信H=mx.receiver.com [x.x.x.x] rejected RCPT <user@...>: Recipient address rejected: User unknown
→ 550
E) 寄件策略小模板(工程實務)
- 單筆投遞:一封對一收件人,成功與否逐筆記錄,避免一人錯拖累全批。
- 退信管道:固定以
bounce@yourdomain.com
為 Return-Path,解析退信原因,自動重試可恢復的 4xx。 - 事件追蹤:紀錄 request-id、message-id、SMTP response;與 GA4 或後台 log 連動,形成可追溯閉環。
表單「寄不出」大多不是單點錯,而是環境 → 後台 → 程式 → DNS/郵件驗證 → 收件端多層交互的結果。照著本文的快篩與檢測清單,把問題一層一層切半,多數情況能在 10~30 分鐘內定位八九成根因;接著用 SOP 模板把修正做紮實,之後的寄送會穩定許多。