黑名單監控:腳本、API 與 Webhook 通知
黑名單監控是指定期針對寄件 IP 與網域查詢多份 DNS 封鎖清單(DNSBL),並且只在結果發生變化時發出通知。在列入發生的當下就察覺,而不是等客戶反映郵件被退信才知道,能讓您在損害擴大之前,有時間找出原因並申請移除。
實務上有兩種做法:自己執行一個小型的 dig 與 cron 腳本,或透過 API 與 Webhook 將檢查交給服務處理。無論採用哪種方式,有兩個細節決定監控結果是否可信:透過公用解析器送出的查詢,會被 Spamhaus 等清單拒絕,並產生誤導性的回應;而錯誤碼絕不能被算成列入。
本文引用的清單營運者規則,依據的是其在 2026 年 11 月時的官方頁面。政策會變動,在依賴某種設定之前,請先確認最新內容。關於 DNSBL 運作方式的背景知識,請參閱什麼是 DNSBL(RBL)。
決定監控對象與要查詢的清單
首先,請寫下您實際需要監控的對象。
- 寄件 IP 位址。也就是您的郵件伺服器或電子郵件服務實際用來寄信的位址。網站與郵件往往是從不同的機器送出,因此請從您寄出郵件的 Received 標頭確認位址。如果您透過 IPv6 寄信,也請監控這些位址。
- 網域。寄件者(From)地址中的網域,以及郵件內連結中出現的所有網域。網域是拿來對照網域封鎖清單檢查,這與 IP 清單是分開的。
查詢格式定義於 RFC 5782。IPv4 是將各位元組反轉後加上清單的區域名稱,因此在某份清單上查詢 192.0.2.99 時,名稱就是 99.2.0.192 後面接上區域名稱。IPv6 則是將位址寫成 32 個十六進位 nibble 並反轉順序。網域則是直接放在區域名稱前面。被列入的項目會回傳 A 記錄,依慣例位於 127.0.0.0/8 範圍內;未列入的項目則回傳 NXDOMAIN。RFC 也指出,清單應發布說明列入原因的 TXT 記錄。
請監控多份清單,而不是只看一份,因為收件端使用的清單並不相同。各回傳碼的意義因營運者而異;常見的代碼請參閱DNSBL 回傳碼說明。
為什麼公用解析器會給出錯誤的回應
自行建置監控時常見的錯誤,是透過 Google Public DNS(8.8.8.8)或 Cloudflare(1.1.1.1)等公用解析器送出查詢。Spamhaus 官方的 DNSBL 使用 FAQ 說明了會發生什麼情況:
- 免費使用 Spamhaus DNSBL 的條件是非商業用途,而且查詢不得來自公用或開放式解析器,也不得來自使用通用反解的 IP。
- 透過 Google Public DNS 等免費開放式解析器查詢時,多數情況下會得到未列入(NXDOMAIN)的回應。換句話說,已被列入的 IP 可能看起來是乾淨的。
- 透過公用解析器的查詢也可能收到 127.255.255.254。這是錯誤碼,而不是列入。同樣地,127.255.255.252 代表 DNSBL 名稱拼寫錯誤,127.255.255.255 則代表查詢次數過多。Spamhaus 表示,不得將這些代碼解讀為所查詢的對象已被列入。
- 會改寫 NXDOMAIN 回應的解析器會改為回傳某個 IP 位址,因此您永遠看不到正確的 NXDOMAIN。
FAQ 的首要建議是自行架設 DNS 解析器。對於必須繼續使用公用解析器的使用者,Spamhaus 建議使用其 Data Query Service(DQS);哪些部分免費,請查閱其條款。FAQ 也建議使用 dig txt whoami.fastly.net 來確認您實際使用的是哪個解析器。
RFC 5782 另外提供了內建的健全性檢查:IPv4 清單必須包含 127.0.0.2 的項目,且不得包含 127.0.0.1;用戶端應定期檢查這些測試項目,以確認清單運作正常。在 Spamhaus 的範例中,2.0.0.127.zen.spamhaus.org 會回傳 127.0.0.10、127.0.0.4 與 127.0.0.2,而 1.0.0.127.zen.spamhaus.org 則回傳 NXDOMAIN。監控程式應先進行這項測試,若測試失敗,就捨棄該次執行結果。
方法 1:dig 與 cron 腳本
以下是一個最簡單的腳本,針對 Spamhaus ZEN 與 SpamCop(bl.spamcop.net,SpamCop 的說明文件指出,被列入的 IP 會回應 127.0.0.2)檢查一個 IPv4 位址。請將位址與區域換成您自己的設定。
#!/bin/sh
# 查詢您自己的遞迴解析器(例如同一台主機上的 unbound),切勿使用公用解析器
RESOLVER=127.0.0.1
IP=192.0.2.10
ZONES="zen.spamhaus.org bl.spamcop.net"
REV=$(echo "$IP" | awk -F. '{print $4"."$3"."$2"."$1}')
q() {
out=$(dig +time=3 +tries=1 @"$RESOLVER" "$1" A) || { echo ERR; return; }
case "$out" in
*"status: NOERROR"*) a=$(printf '%s\n' "$out" | awk '$4=="A"{print $5}'); echo "${a:-NX}" ;;
*"status: NXDOMAIN"*) echo NX ;;
*) echo ERR ;;
esac
}
for Z in $ZONES; do
# 若 127.0.0.2 測試項目沒有解析為列入代碼,就不要信任這次的執行結果
case "$(q "2.0.0.127.$Z")" in
127.255.255.*|NX|ERR) echo "$Z ERROR test-entry"; continue ;;
127.*) ;;
*) echo "$Z ERROR test-entry"; continue ;;
esac
A=$(q "$REV.$Z")
case "$A" in
NX) echo "$Z CLEAN" ;;
ERR) echo "$Z ERROR no-answer" ;;
127.255.255.*) echo "$Z ERROR $A" ;;
127.*) echo "$Z LISTED $A" ;;
*) echo "$Z ERROR unexpected $A" ;;
esac
done這個腳本的處理方式:
- 只有 NXDOMAIN 狀態才算乾淨,127.255.255.x 是錯誤,其他任何 127.x 則是列入。127.0.0.0/8 以外的值一律視為異常,例如解析器改寫了回應。
- 逾時會讓 dig 以非零值結束,而 SERVFAIL 與 REFUSED 則以 0 結束。這些情況都不會被視為乾淨;腳本會記錄為錯誤。
- 回傳碼因清單而異。例如有些清單使用 127.0.0.1 表示查詢遭到拒絕,因此每新增一份清單,請閱讀其說明文件,並視需要擴充 case 陳述式。
接著讓 cron 將每次執行結果與上一次比較,只在有變化時才寄信:
# Example: run hourly, send mail only when the output differs from the last run
0 * * * * /usr/local/bin/dnsbl-watch.sh > /var/tmp/dnsbl.now 2>&1; cmp -s /var/tmp/dnsbl.now /var/tmp/dnsbl.prev || mail -s "DNSBL status changed" you@example.com < /var/tmp/dnsbl.now; mv /var/tmp/dnsbl.now /var/tmp/dnsbl.prev每小時一次的間隔只是範例。Spamhaus 免費提供給少量的非商業用途,超過其查詢量門檻的用戶端需要使用付費方案;隨著監控的 IP 數量增加,請確認各清單的條款。FAQ 也建議將指令多執行幾次,確認結果保持一致。
方法 2:DNSBL Checker 批次 API 與 Webhook
如果您不想自行維護解析器與各清單的解析規則,也可以讓服務代為執行檢查。以下介紹本站的 v1 API,內容僅限於伺服器實作實際提供的功能。參考文件位於 /en/api-docs,金鑰則在會員頁面 /account 發行。註冊只需要電子郵件地址,登入時使用寄到信箱的連結。
驗證與限制
- 金鑰以
dnsbl_開頭,只在發行後立即顯示一次;系統只儲存其雜湊值。重新發行金鑰會使先前的金鑰失效。 - 每次請求都要在
X-API-Key標頭中送出金鑰。僅支援 HTTPS;純 http:// 會被重新導向至 https://,因此請從一開始就呼叫 https://。 - 限制為每天 1,000 次檢查(一個目標計為一次)、每批次 100 個目標,以及 50 個監控登錄。超過每日上限時,會收到
429,並附上daily_limit_exceeded與resets_at時間戳記。
批次檢查
將網域名稱或 IP 位址組成的 targets 陣列送到 POST /api/v1/batch:
curl -X POST https://dnsblchecker.com/api/v1/batch \
-H "X-API-Key: $DNSBL_API_KEY" -H "Content-Type: application/json" \
-d '{"targets":["example.com"]}'如果仍有目標需要檢查,回應會是 202 並附上 batch_id。請每隔幾秒輪詢 GET /api/v1/batch/{batch_id},直到 status 變成 done(以下為節錄範例;數字與清單名稱僅為示意,並非實際結果):
{
"batch_id": 1, "status": "done", "created": "2026-11-03 09:10:41", "count": 1, "pending": 0,
"results": [
{
"target": "example.com", "type": "domain",
"status": "done", "verdict": "listed",
"checked_at": "2026-11-03 09:12",
"lists_checked": 80, "listed_count": 1, "error_count": 4,
"listed_on": [
{ "list": "ZapBL RHSBL", "zone": "rhsbl.zapbl.net", "response": "127.0.0.2" }
]
}
]
}- 只要有至少一份清單回報列入,
verdict就是listed,否則為clean。逾時或以 127.255.255.x 等錯誤碼回應的清單,會計入error_count,絕不會被算成列入。 - 如果有過去 30 天內儲存的結果,批次會直接回傳該結果。用於定期監控時,請務必查看
checked_at。 - 格式錯誤的目標會連同原因放在
rejected中回傳,且不計入次數。如果傳入網址,只會使用其中的主機名稱。192.0.2.0/24 等僅供文件使用的範圍會被拒絕,因此請用實際的寄件 IP 測試。
Webhook 監控
使用 POST /api/v1/monitors 登錄 target 與 callback_url。之後每個已登錄的目標每天會在不使用快取的情況下檢查一次(首次檢查會在登錄後約一天內執行),而且只有在首次檢查(monitor.initial)以及判定結果在 listed 與 clean 之間切換(monitor.status_changed)時,才會以 JSON 格式向您的網址送出 POST。
curl -X POST https://dnsblchecker.com/api/v1/monitors \
-H "X-API-Key: $DNSBL_API_KEY" -H "Content-Type: application/json" \
-d '{"target":"example.com","callback_url":"https://your-app.example/hooks/dnsbl"}'- 回應中的
signing_secret只會顯示一次。每次送出的通知都帶有X-DNSBL-Signature: sha256=...標頭,其值是以該密鑰對原始內文計算的 HMAC-SHA256。請在您這一端進行驗證。 callback_url必須使用 443 連接埠的 https,且必須解析到公用 IP;系統不會追隨重新導向,逾時時間為 10 秒,因此請將耗時的工作排入佇列,並盡快回應。- 如果您的端點回傳
2xx以外的狀態,或連線失敗,會在下一次每日檢查時重新送出。失敗原因會顯示在GET /api/v1/monitors的last_delivery_error中,而DELETE /api/v1/monitors/{monitor_id}可刪除監控。
import hmac, hashlib
expected = "sha256=" + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
ok = hmac.compare_digest(expected, request.headers.get("X-DNSBL-Signature", ""))通知設計:頻率、多份清單與誤報
監控只有在幾個月後大家仍會閱讀其通知時才有用。不斷發出通知的監控,很快就會被忽視。
頻率
- 請將查詢頻率與通知頻率分開考量。依排程查詢,但只在狀態改變時通知。每天一封「一切正常」的訊息,會讓真正重要的那一則通知被淹沒。
- RFC 5782 指出,清單的 TTL 應反映清單變動的速度,而垃圾郵件來源清單可能使用以分鐘為單位的 TTL。選擇檢查間隔時,請考量到有些列入會很快出現、也很快到期。
- 大量查詢可能違反清單的使用條款,或讓您收到 127.255.255.255(查詢次數過多),而不是真正的回應。
多份清單
- 每則通知都要包含清單名稱。各清單被收件端採用的程度不同,因此您可以對收件者最重視的清單立即通知,其餘則彙整成摘要。
- 上述 Webhook 只會在判定結果於 listed 與 clean 之間切換時觸發。如果某個目標已經被列入,之後又出現在第二份清單上,並不會送出事件。若要掌握這種情況,請留意
GET /api/v1/monitors中的last_listed_count,或執行批次檢查並查看listed_on。
誤報與暫時性的回應
- 將錯誤與列入分開記錄。Spamhaus 警告營運者,不要依據其錯誤碼拒收或過濾郵件;同樣的道理也適用於監控。逾時或 127.255.255.x 的回應,絕不應觸發列入通知。
- 為了避免對單一次的異常結果做出反應,請在連續兩次得到相同結果後才發出通知,或在送出任何通知前,於幾分鐘後重新查詢。
- 如果錯誤持續發生,請懷疑是解析器有所變更,或清單端有所變動,並先查看測試項目的結果。
- 家用 IP 被列入 Spamhaus PBL 屬於政策性列入,而不是指控:它代表該位址不應直接寄送郵件。請依清單分別決定哪些情況需要通知(請參閱Spamhaus 的移除方式)。
偵測到列入時該怎麼做
- 確認結果。請到營運者自己的查詢頁面確認,並記下清單名稱、時間與顯示的原因。
- 先排除原因。請檢查是否有遭入侵的帳號、被濫用的網頁表單、受感染的機器、名單管理不良,以及不一致的反解(PTR)或 HELO 名稱。在原因仍存在時申請移除,通常會導致再次被列入。
- 依照該清單的移除程序處理。是否解除由各清單營運者決定,提出申請並不保證列入一定會被解除。如果該 IP 不在您的控管之下(例如共享主機),請聯絡您的主機商或 ISP。
- 讓監控確認結果。收件端也會執行自己的過濾機制,因此在判定結果恢復為 clean 之後,也請持續留意郵件投遞狀況。
若只想單次查詢某個 IP 或網域,請使用黑名單檢查工具。如果追查原因或處理申請超出您能負擔的範圍,也可以尋求我們的協助。郵件遭退信時的完整排查流程,請參閱郵件因黑名單遭封鎖的說明。
常見問題
我透過 8.8.8.8 檢查,結果沒有被列入,這樣就沒問題了嗎?
不一定。Spamhaus 的 FAQ 指出,透過 Google Public DNS 等免費開放式解析器的查詢,多數情況下會得到未列入(NXDOMAIN)的回應,因此已被列入的 IP 可能看起來是乾淨的。請從您自己的解析器查詢,或使用營運者的查詢頁面。
我收到 127.255.255.254,代表我被列入了嗎?
不是。這是透過公用或開放式解析器查詢時回傳的錯誤碼,Spamhaus 表示它並不代表該對象已被列入。請將它記錄為錯誤,不要發出列入通知。
可以每天呼叫批次 API 來當作監控嗎?
批次可能會回傳最多 30 天前儲存的結果,因此不一定是今天的狀態。請查看 checked_at,或改用每天都會重新檢查的 Webhook 監控(POST /api/v1/monitors)。
收到通知後,應該立刻申請移除嗎?
請先排除原因。在問題仍存在時提出的申請,通常最後會導致再次被列入。決定權永遠在清單營運者手上。
參考的官方頁面
本文內容已於發布時對照下列官方頁面確認。各項政策與運作方式可能未經通知即變更,涉及重要決定前,請先查閱官方頁面。
- RFC 5782: DNS Blacklists and Whitelists
- Spamhaus FAQ: DNSBL Usage
- Spamhaus: Using our public mirrors? Check your return codes now
- SpamCop FAQ: How do I configure my mailserver to reject mail based on the blocklist?
相關文章
如何解讀 DNSBL 回傳碼:RFC 5782 中 127.0.0.2 的意義、Spamhaus、SpamCop 與 UCEPROTECT 的代碼、錯誤碼,以及 NXDOMAIN 與 SERVFAIL 的差異。
被 Spamhaus 列入了嗎?了解您被列入的是哪個清單(ZEN、PBL、XBL、CSS、SBL、DBL)、回傳代碼的意義,以及各清單正確的移除方式。
郵件被黑名單擋下了嗎?教您看懂退信代碼、依正確順序排查原因、判斷哪些黑名單需要處理,並以正確方式申請移除。