From 0d372eab79d5178c8ef1351cdfe2620e3be11755 Mon Sep 17 00:00:00 2001 From: cschantz Date: Wed, 31 Dec 2025 19:13:01 -0500 Subject: [PATCH] Fix bounce and spam detection to exclude auth failures Improved accuracy: - Bounces now only count actual SMTP delivery failures (550-554 codes) - Excludes SMTP/IMAP/FTP authentication failures from bounce count - Spam rejected now only counts actually rejected emails - Excludes emails delivered to spam folder (those are successful deliveries) - Updated display sections to match new filtering logic This fixes the misleading "334 bounced" count that was actually showing authentication failures, not email delivery problems. --- modules/email/email-diagnostics.sh | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/modules/email/email-diagnostics.sh b/modules/email/email-diagnostics.sh index 423ef2b..e8a1e47 100755 --- a/modules/email/email-diagnostics.sh +++ b/modules/email/email-diagnostics.sh @@ -159,17 +159,19 @@ delivered=$(grep -ci "=> .*$search_pattern\|delivered.*$search_pattern" "$TEMP_M delivered=$(echo "$delivered" | head -1 | tr -d '\n\r') sent=$(grep -ci "<=.*$search_pattern" "$TEMP_MATCHES" 2>/dev/null || echo 0) sent=$(echo "$sent" | head -1 | tr -d '\n\r') -bounced=$(grep -ci "bounce.*$search_pattern\|failed.*$search_pattern\|550.*$search_pattern" "$TEMP_MATCHES" 2>/dev/null || echo 0) +# Only count actual email bounces, not auth failures +bounced=$(grep -i "$search_pattern" "$TEMP_MATCHES" | grep -v "authenticator failed\|Authentication failed" | grep -ci "550\|551\|552\|553\|554\|bounced\|Mail delivery failed" 2>/dev/null || echo 0) bounced=$(echo "$bounced" | head -1 | tr -d '\n\r') deferred=$(grep -ci "deferred.*$search_pattern\|retry.*$search_pattern\|temporarily rejected" "$TEMP_MATCHES" 2>/dev/null || echo 0) deferred=$(echo "$deferred" | head -1 | tr -d '\n\r') -rejected=$(grep -ci "rejected.*$search_pattern\|denied.*$search_pattern\|blocked.*$search_pattern" "$TEMP_MATCHES" 2>/dev/null || echo 0) +rejected=$(grep -i "$search_pattern" "$TEMP_MATCHES" | grep -v "authenticator failed\|Authentication failed" | grep -ci "rejected RCPT\|rejected.*relay.*denied\|rejected.*spam" 2>/dev/null || echo 0) rejected=$(echo "$rejected" | head -1 | tr -d '\n\r') spf_fail=$(grep -ci "SPF.*fail.*$search_pattern" "$TEMP_MATCHES" 2>/dev/null || echo 0) spf_fail=$(echo "$spf_fail" | head -1 | tr -d '\n\r') dkim_fail=$(grep -ci "DKIM.*fail.*$search_pattern" "$TEMP_MATCHES" 2>/dev/null || echo 0) dkim_fail=$(echo "$dkim_fail" | head -1 | tr -d '\n\r') -spam_rejected=$(grep -ci "spam.*$search_pattern\|SpamAssassin.*rejected.*$search_pattern" "$TEMP_MATCHES" 2>/dev/null || echo 0) +# Only count actually rejected spam, not spam delivered to spam folder +spam_rejected=$(grep -i "$search_pattern" "$TEMP_MATCHES" | grep -i "spam" | grep -ci "rejected\|blocked\|denied" 2>/dev/null || echo 0) spam_rejected=$(echo "$spam_rejected" | head -1 | tr -d '\n\r') greylist=$(grep -ci "greylist.*$search_pattern\|greylisted.*$search_pattern" "$TEMP_MATCHES" 2>/dev/null || echo 0) greylist=$(echo "$greylist" | head -1 | tr -d '\n\r') @@ -507,9 +509,9 @@ fi if [ "$bounced" -gt 0 ]; then print_header "RECENT BOUNCES/FAILURES (last 5 from past $hours hours)" echo "" - print_warning "PROOF - These emails failed recently:" + print_warning "PROOF - These emails failed delivery:" echo "" - grep -i "bounce.*$search_pattern\|failed.*$search_pattern\|550.*$search_pattern" "$TEMP_MATCHES" | tail -5 | while read line; do + grep -i "$search_pattern" "$TEMP_MATCHES" | grep -v "authenticator failed\|Authentication failed" | grep -i "550\|551\|552\|553\|554\|bounced\|Mail delivery failed" | tail -5 | while read line; do timestamp=$(echo "$line" | grep -oE '[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}|[A-Z][a-z]{2} [0-9]+ [0-9]{2}:[0-9]{2}:[0-9]{2}' | head -1) if [ -n "$timestamp" ]; then echo -e " ${RED}[$timestamp]${NC} $line" @@ -522,14 +524,14 @@ if [ "$bounced" -gt 0 ]; then # Extract bounce reasons print_header "COMMON BOUNCE REASONS" echo "" - grep -i "bounce\|550\|fail" "$TEMP_MATCHES" | grep -oE "550 .*|User unknown|Mailbox.*full|Relay.*denied|blocked" | sort | uniq -c | sort -rn | head -5 + grep -i "$search_pattern" "$TEMP_MATCHES" | grep -v "authenticator failed\|Authentication failed" | grep -i "550\|551\|bounced" | grep -oE "550 [^:]*|551 [^:]*|User unknown|Mailbox.*full|Relay.*denied|No such user" | sort | uniq -c | sort -rn | head -5 echo "" fi if [ "$rejected" -gt 0 ]; then print_header "RECENT REJECTIONS (last 5)" echo "" - grep -i "rejected.*$search_pattern\|denied.*$search_pattern\|blocked.*$search_pattern" "$TEMP_MATCHES" | tail -5 | while read line; do + grep -i "$search_pattern" "$TEMP_MATCHES" | grep -v "authenticator failed\|Authentication failed" | grep -i "rejected RCPT\|rejected.*relay.*denied\|rejected.*spam" | tail -5 | while read line; do echo " $line" done echo "" @@ -538,7 +540,9 @@ fi if [ "$spam_rejected" -gt 0 ]; then print_header "RECENT SPAM REJECTIONS (last 5)" echo "" - grep -i "spam.*$search_pattern\|SpamAssassin.*rejected" "$TEMP_MATCHES" | tail -5 | while read line; do + print_info "Emails rejected as spam (not delivered):" + echo "" + grep -i "$search_pattern" "$TEMP_MATCHES" | grep -i "spam" | grep -i "rejected\|blocked\|denied" | tail -5 | while read line; do timestamp=$(echo "$line" | grep -oE '[0-9]{4}-[0-9]{2}-[0-9]{2} [0-9]{2}:[0-9]{2}:[0-9]{2}|[A-Z][a-z]{2} [0-9]+ [0-9]{2}:[0-9]{2}:[0-9]{2}' | head -1) if [ -n "$timestamp" ]; then echo -e " ${RED}[$timestamp]${NC} $line"