郵件與網域
檢查 SPF
涵蓋範圍: 適用於任何國家的網域。我們會像收件伺服器一樣讀取記錄(RFC 7208):它的機制、結尾方式、最多 30 次查詢範圍內的每一個 include 和 redirect,以及 DNS 查詢次數與 10 次上限的比較。
開啟工具本頁內容
用途
檢查網域的 SPF 記錄:哪些伺服器可以用它的名義寄信、其他伺服器會被如何處理(「-all」、「~all」、「+all」)、它需要多少次 DNS 查詢(上限 10 次),以及每一個 include。
使用要求
任何 NoCall 帳號都可以閱讀這些指南。部分工具需要 Pro,各指南會註明。
SPF 是一種 DNS 記錄,網域會在其中列出獲准替它寄信的伺服器。如果沒有 SPF,或 SPF 有錯誤、過於寬鬆,別人就更容易以該網域的名義寄出假郵件。輸入網域、電子郵件地址或連結,我們會讀取它的 SPF 並為你說明。
使用步驟
輸入你要檢查的網域,或貼上電子郵件地址或連結:我們只會使用其中的網域。
按下「檢查 SPF」。我們會讀取 SPF 記錄,並像收件伺服器一樣追蹤每一個 include。
看看記錄的結尾和查詢次數:理想的結果是「-all」或「~all」,且查詢次數不超過 10 次。
虛構範例
此範例為虛構內容,並非真實查詢。請勿撥打電話或開啟其中的連結。
v=spf1 include:_spf.example.com ~all理解結果
這個網域沒有 SPF: 它沒有說明哪些伺服器可以替它寄信,因此更容易被冒充。如果這是你的網域,請發布 SPF 記錄。
SPF 記錄有錯誤: 收件伺服器無法套用它,所以對它們來說,這個網域等於沒有 SPF。下方的訊號會說明問題所在。
任何人都能以這個網域的名義寄信: 記錄以「+all」結尾,等於授權全世界所有伺服器。這樣設定的 SPF 毫無保護作用。
SPF 沒有完全保護這個網域: 記錄沒有說明該如何處理不在清單上的伺服器,因此以這個網域名義寄出的假郵件不會被標記。
SPF 設定正確: 這個網域列出了可以替它寄信的伺服器,並要求收件端標記或拒收其餘的郵件。單靠 SPF 無法阻止冒充:告訴收件端該怎麼做的是 DMARC。
+all:任何伺服器都能寄信(危險)
?all:記錄沒有說明如何處理它們
~all:標記為可疑
-all:拒收
沒有「all」:記錄沒有說明如何處理它們
限制
我們讀取的是該網域的公開 DNS 記錄。如果你輸入電子郵件地址或連結,只有其中的網域會離開你的瀏覽器。你查詢的網域不會被儲存。
疑難排解
這看起來不像公開的網域。請試試類似 example.com 的網域。
DNS 沒有及時回應。請過幾秒再試。
你連續做了很多次檢查。請等一分鐘後再試。
透過 API 使用
需要 API 金鑰和點數。每次完成的呼叫扣 1 點,即使沒有資料也一樣。有效的 Pro 帳戶每個 UTC 曆月包含 20 點,由所有 API 路由共用並優先扣用;當月未使用的點數不會累積到下個月。在帳戶頁面購買的點數不需 Pro 即可使用,且永不過期。
錯誤一律不扣點:401 invalid_api_key(缺少金鑰或金鑰無效)、403 pro_required(沒有 Pro 點數,也沒有購買的點數)、422 輸入無效、429 quota_exceeded(點數用完)、rate_limit_exceeded 或 ai_busy(sms-check 的 AI 已達負載上限)、503 tool_warming(資料仍在準備中)或 tool 或供應商無法使用。收到 429 或 503 後,請等 Retry-After 標頭中的秒數過後再重試。
以收件端的方式讀取網域的 SPF 記錄(RFC 7208):其中的項目、結尾、整個 include 樹狀結構的 DNS 查詢次數與 10 次上限的比較、每個 include 及其是否發布 SPF,並以訊號列出記錄的問題。不儲存任何內容。
將 JSON 主體傳送到該 tool 專屬的路由,或加上 tool 欄位後傳送到 POST /v2/tools。兩種路由回傳的結果相同。
POST https://api.nocall.io/v2/spf-check
POST https://api.nocall.io/v2/tools {"tool":"spf-check","domain":"example.com"}參數
| 名稱 | 類型 | 必填 | 說明 |
|---|---|---|---|
| domain | string (1–320) | 是 | 網域,或會從中取出網域的電子郵件地址或連結,最多 320 個字元。僅限公開名稱:IP 位址、單一標籤名稱和特殊用途名稱(.local、.internal、.test…)會傳回 422。 |
REQUEST_ID="$(uuidgen)" && [ -n "$REQUEST_ID" ] &&
curl --request POST 'https://api.nocall.io/v2/spf-check' \
--header "Authorization: Bearer $NOCALL_API_KEY" \
--header 'Content-Type: application/json' \
--header "Idempotency-Key: $REQUEST_ID" \
--data '{"domain":"example.com"}'import json
import os
import urllib.request
import uuid
api_key = os.environ.get('NOCALL_API_KEY')
if not api_key:
raise SystemExit('Set NOCALL_API_KEY')
request = urllib.request.Request(
'https://api.nocall.io/v2/spf-check',
method='POST',
data=json.dumps({'domain': 'example.com'}).encode(),
headers={
'Authorization': 'Bearer ' + api_key,
'Content-Type': 'application/json',
'Idempotency-Key': str(uuid.uuid4()),
},
)
with urllib.request.urlopen(request, timeout=30) as response:
result = json.load(response)
print(result['data']['result'], result['meta']['unitsCharged'])import { randomUUID } from 'node:crypto';
const requestId = randomUUID();
const apiKey = process.env.NOCALL_API_KEY;
if (!apiKey) throw new Error('Set NOCALL_API_KEY');
const response = await fetch('https://api.nocall.io/v2/spf-check', {
method: 'POST',
headers: {
Authorization: 'Bearer ' + apiKey,
'Content-Type': 'application/json',
'Idempotency-Key': requestId,
},
body: JSON.stringify({ domain: 'example.com' }),
});
const result = await response.json();
if (!response.ok) throw new Error(result.error?.code ?? 'request_failed');
console.log(result.data.result, result.meta.unitsCharged);回應範例(200)
這是 API 參考文件中的範例。查詢使用虛構號碼,彙總資料和 AI 回答只呈現結果的結構,並非即時資料。
{
"data": {
"tool": "spf-check",
"result": {
"domain": "example.com",
"domainAscii": "example.com",
"found": true,
"record": "v=spf1 include:_spf.google.com ~all",
"recordCount": 1,
"terms": [
{
"qualifier": "pass",
"mechanism": "include",
"value": "_spf.google.com"
},
{
"qualifier": "softfail",
"mechanism": "all",
"value": null
}
],
"allResult": "softfail",
"lookups": 1,
"includes": [
{
"domain": "_spf.google.com",
"found": true
}
],
"signals": [
"softfail_all"
],
"valid": true,
"attention": false
}
},
"meta": {
"requestId": "req_example",
"unitsCharged": 1,
"usage": {
"periodStart": "2026-10-01",
"unitLimit": 20,
"unitsUsed": 3,
"unitsRemaining": 17
}
}
}結果欄位(data.result)
| 欄位 | 類型 | 說明 |
|---|---|---|
| domain | string | Unicode 形式的網域。 |
| domainAscii | string | 同一個網域的 ASCII 形式(punycode),即 DNS 所見的形式。 |
| found | boolean | 網域是否發布 SPF 記錄。 |
| record | string | null | 已發布的 SPF 記錄原文;沒有或不只一筆時為 null。 |
| recordCount | integer | 網域發布的 SPF 記錄筆數;超過一筆即為錯誤。 |
| terms | array<object> | 依序列出記錄的機制與修飾詞,各附其限定詞(pass、fail、softfail 或 neutral;redirect 和 exp 為 null)與值。 |
| allResult | "pass" | "fail" | "softfail" | "neutral" | null | 記錄的結尾(它的 all,或其 redirect 目標的 all):pass、fail、softfail 或 neutral;沒有時為 null。 |
| lookups | integer | 整個 include 樹狀結構中會查詢 DNS 的機制與修飾詞數量。超過 10 個時,收件端會停止處理(permerror)。 |
| includes | array<object> | 依讀取順序列出的每個 include 和 redirect 目標,以及它是否發布 SPF。 |
| signals | array<string (enum, 12)> | no_spf、multiple_records、syntax_error、too_many_lookups、include_not_found、include_loop、plus_all、neutral_all、softfail_all、no_all、ptr_mechanism 或 macros。 |
| valid | boolean | 收件端是否能評估這筆記錄:只有一筆記錄、沒有語法錯誤、最多 10 次查詢、每個 include 都找得到,且沒有迴圈。 |
| attention | boolean | 結果是否值得進一步查看:沒有 SPF、記錄無效,或記錄以 +all、?all 結尾或沒有 all。 |
常見問題
什麼是 SPF?
Sender Policy Framework:一種 DNS 記錄,網域會在其中列出獲准替它寄信的伺服器。收到郵件的伺服器會檢查投遞這封郵件的伺服器是否在這份清單上。
「-all」和「~all」哪個比較好?
「-all」要求收件端拒收來自清單外伺服器的郵件;「~all」則要求將這些郵件標記為可疑。兩者都有保護作用,許多網域會使用「~all」,再交由 DMARC 決定如何處理。「+all」和「?all」則沒有保護作用。
為什麼 10 次查詢的上限很重要?
每一個 include、a、mx、ptr、exists 和 redirect,都會讓收件伺服器查詢一次 DNS。如果整筆記錄需要超過 10 次,就會被視為錯誤,SPF 也會失效。請移除不再使用的服務,或請你的供應商提供更精簡的 include。
SPF 能單獨阻止假郵件嗎?
不能。SPF 檢查的是隱藏的信封寄件者,而不是你在「寄件者」中看到的地址。將兩者連結起來、並要求收件端隔離或拒收未通過驗證之郵件的,是 DMARC。也請一併檢查該網域的 DMARC。
