← 返回文章列表

自架郵件伺服器郵件寄出卡住?Postfix 佇列管理完整指南

自架郵件伺服器使用 Postfix 時,郵件可能因為收件方伺服器暫時不可用、網路問題、DNS 解析失敗、被判定為垃圾郵件等原因而滯留在佇列(Queue)中。這些卡住的信件會持續重試發送,不僅浪費系統資源,還可能影響正常郵件的投遞效率。本文逐步說明如何查看、診斷與清理 Postfix 佇列。

目錄

一、查看佇列狀態:postqueue

Postfix 提供 postqueue 指令來查看目前佇列中的信件狀態。

查看佇列摘要:

postqueue -p

輸出範例:

-Queue ID-  --Size-- ----Arrival Time---- -Sender/Recipient-------
3xJ4X2Z1    5000     Tue Aug 25 10:30:01  [email protected]
                                          [email protected]

8kL9mP3q 3200 Tue Aug 25 09:15:33 [email protected] [email protected]

– 2 Kbytes in 2 Requests.

欄位說明:

欄位 說明
Queue ID信件唯一識別碼,用於後續操作(postcat、postsuper)
Size信件大小(位元組)
Arrival Time信件進入佇列的時間
Sender/Recipient寄件者與收件者地址

只查看佇列數量:

postqueue -p | tail -1

輸出如 -- 2 Kbytes in 5 Requests.,表示佇列中有 5 封信件。

強制嘗試重新投遞:

如果問題已排除(例如 DNS 恢復、收件方伺服器恢復),可以強制 Postfix 立即嘗試投遞佇列中的信件:

postqueue -f

二、查看信件內容:postcat

當信件卡在佇列中,需要了解信件內容和投遞失敗的原因時,可以使用 postcat 查看完整信件。

查看單一信件:

postcat -q 3xJ4X2Z1

輸出包含:

  • 信件標頭(Headers):寄件者、收件者、主旨、日期等
  • 信件內容(Body):實際郵件內容
  • Postfix 內部資訊:進入佇列時間、嘗試投遞次數、上次嘗試時間、失敗原因等

查看信件的失敗原因:

postcat 輸出的最後一段通常會包含 reasondiagnostic-code 欄位,說明投遞失敗的原因,例如:

diagnostic-code: host remote.com[203.0.113.50] said: 450 4.1.2
  <[email protected]>: Recipient address rejected: User unknown

常見失敗原因:

錯誤碼 說明 處理方式
450暫時性失敗(收件方暫時不可用)可等待重試,通常會自動恢復
550永久性失敗(收件者不存在)應刪除該信件,無法投遞
451本地錯誤(資源不足)檢查磁碟空間、記憶體
452容量不足檢查信件大小限制設定
Connection timed out連線逾時檢查網路、防火牆、DNS
421 4.7.0Gmail 判定信件內容或連結可疑,已封鎖該信件檢查信件內容是否含可疑連結,參考 Google 說明,調整內容後重新發送

三、刪除佇列信件:postsuper

確認信件無法投遞或為垃圾信件後,可以使用 postsuper 刪除。

刪除單一信件:

postsuper -d 3xJ4X2Z1

刪除所有信件(謹慎使用):

postsuper -d ALL

⚠️ 此指令會刪除佇列中所有信件,包括正在重試的正常信件,請確認後再執行。

只刪除已超過保留期限的信件:

Postfix 預設保留信件 5 天(maximal_queue_lifetime = 5d),超過後會自動退信。如果想手動清除:

# 刪除超過保留期限的信件
postsuper -d ALL delayed

四、大量刪除多組 Queue ID

實務上常遇到需要刪除多封特定信件,但 postsuper -d 一次只能刪除一個 Queue ID。以下提供幾種大量刪除的方式:

方法一:逐一刪除(適用少量)

postsuper -d 3xJ4X2Z1
postsuper -d 8kL9mP3q
postsuper -d 2mN7kR5x

方法二:用 for 迴圈批次刪除

for id in 3xJ4X2Z1 8kL9mP3q 2mN7kR5x; do
    postsuper -d $id
done

方法三:從檔案讀取 Queue ID 大量刪除

將要刪除的 Queue ID 寫入檔案,每行一個:

# 建立 ID 清單檔案
cat > /tmp/queue_ids.txt << 'EOF'
3xJ4X2Z1
8kL9mP3q
2mN7kR5x
5pQ9wL4t
EOF

逐行讀取並刪除

while read id; do postsuper -d “$id” done < /tmp/queue_ids.txt

方法四:依條件篩選後大量刪除

例如刪除所有寄給特定網域的卡住信件:

#!/bin/bash
# delete_queue_by_domain.sh
# 用法: ./delete_queue_by_domain.sh example.com

TARGET_DOMAIN=“$1”

if [ -z “$TARGET_DOMAIN” ]; then echo “用法: $0 <收件網域>” echo “範例: $0 spam-domain.com” exit 1 fi

echo “正在搜尋寄往 $TARGET_DOMAIN 的信件…”

取得符合條件的 Queue ID

IDS=$(postqueue -p | grep “$TARGET_DOMAIN” | awk ‘{print $1}’ | sed ‘s/*//g’)

if [ -z “$IDS” ]; then echo “沒有找到寄往 $TARGET_DOMAIN 的信件” exit 0 fi

COUNT=$(echo “$IDS” | wc -l) echo “找到 $COUNT 封信件,開始刪除…”

for id in $IDS; do postsuper -d “$id” 2>/dev/null echo “已刪除: $id” done

echo “完成!共刪除 $COUNT 封信件。”

方法五:互動式大量刪除腳本

以下腳本提供互動式操作,可先預覽要刪除的信件再確認執行:

#!/bin/bash
# bulk_queue_manager.sh
# Postfix 佇列大量管理工具

echo “===== Postfix 佇列管理工具 =====” echo “” echo “1. 查看佇列摘要” echo “2. 依網域篩選並刪除” echo “3. 依寄件者篩選並刪除” echo “4. 刪除所有佇列信件” echo “5. 匯出 Queue ID 清單” echo “”

read -p "請選擇操作 (1-5): " choice

case $choice in 1) echo “” postqueue -p ;; 2) read -p "輸入收件網域 (如 spam.com): " domain IDS=$(postqueue -p | grep “$domain” | awk ‘{print $1}’ | sed ‘s/*//g’) if [ -z “$IDS” ]; then echo “沒有找到寄往 $domain 的信件” exit 0 fi echo “” echo “找到以下信件:” postqueue -p | grep “$domain” echo “” read -p "確認刪除?(y/N): " confirm if [ “$confirm” = “y” ] || [ “$confirm” = “Y” ]; then for id in $IDS; do postsuper -d “$id” 2>/dev/null done echo “刪除完成!” else echo “已取消” fi ;; 3) read -p "輸入寄件者 Email: " sender IDS=$(postqueue -p | grep “$sender” | awk ‘{print $1}’ | sed ‘s/*//g’) if [ -z “$IDS” ]; then echo “沒有找到來自 $sender 的信件” exit 0 fi echo “” echo “找到以下信件:” postqueue -p | grep “$sender” echo “” read -p “確認刪除?(y/N): " confirm if [ “$confirm” = “y” ] || [ “$confirm” = “Y” ]; then for id in $IDS; do postsuper -d “$id” 2>/dev/null done echo “刪除完成!” else echo “已取消” fi ;; 4) echo “⚠️ 此操作將刪除所有佇列信件!” postqueue -p echo “” read -p “確認刪除所有信件?(yes/N): " confirm if [ “$confirm” = “yes” ]; then postsuper -d ALL echo “所有信件已刪除!” else echo “已取消” fi ;; 5) OUTPUT=”/tmp/postfix_queue_ids_$(date +%Y%m%d_%H%M%S).txt” postqueue -p | grep -v “^-” | grep -v “^$” | awk ‘{print $1}’ | sed ‘s/*//g’ > “$OUTPUT” echo “已匯出至: $OUTPUT” echo “共 $(wc -l < “$OUTPUT”) 封信件” ;; *) echo “無效選項” ;; esac

使用方式:

chmod +x bulk_queue_manager.sh
sudo ./bulk_queue_manager.sh

五、預防信件卡住的設定建議

清理佇列只是治標,調整 Postfix 設定才能治本:

縮短重試次數與保留時間:

/etc/postfix/main.cf 中設定:

# 卡住信件最多保留 2 天(預設 5 天)
maximal_queue_lifetime = 2d
bounce_queue_lifetime = 1d

重試間隔(逐漸拉長)

minimal_backoff_time = 300s maximal_backoff_time = 4000s

限制信件大小:

# 限制單封信件最大 20MB
message_size_limit = 20480000

設定退信通知:

# 超過保留期限後自動退信給寄件者
bounce_notice_recipient = postmaster
delay_notice_recipient = postmaster

修改設定後重新載入:

postfix reload

六、日常維運建議

  • 定期檢查佇列:每天或每週執行 postqueue -p 檢查是否有異常滯留信件
  • 設定監控告警:當佇列超過一定數量(如 100 封)時發送告警通知
  • 記錄清理日誌:每次清理佇列時記錄刪除了哪些信件,方便日後追蹤
  • 分析卡住原因:透過 postcat 查看失敗原因,如果是 DNS 或網路問題需優先修復基礎設施

結語

Postfix 佇列管理是自架郵件伺服器的日常維運工作之一。掌握 postqueuepostcatpostsuper 三個核心指令,搭配本文提供的腳本工具,就能有效率地處理卡住的信件。更重要的是分析卡住的根因,調整 Postfix 設定或修復基礎設施,避免同樣的問題反覆發生。