Enhance email diagnostics with comprehensive tracking
Bug fixes: - Fix integer expression errors by sanitizing grep output - Separate IMAP/POP3 authentication from email delivery events - Prevent login failures from being counted as email bounces New tracking features: - Spam rejections (SpamAssassin) - Greylisting events - Emails received count - Authentication activity (successful/failed logins) - Failed login IPs extraction - Top 5 senders and recipients - Email account existence check - Mailbox size and message count - Quota information - Email forwarder detection Enhanced recommendations: - Spam rejection troubleshooting - Greylisting explanation - Account not found guidance - Failed login attempt handling
This commit is contained in:
@@ -89,8 +89,18 @@ fi
|
|||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
TEMP_MATCHES="/tmp/email_diag_$$.txt"
|
TEMP_MATCHES="/tmp/email_diag_$$.txt"
|
||||||
|
TEMP_AUTH="/tmp/email_auth_$$.txt"
|
||||||
|
|
||||||
|
# Get ALL matches for this email/domain
|
||||||
grep -i "$search_pattern" "$MAIL_LOG" > "$TEMP_MATCHES" 2>/dev/null
|
grep -i "$search_pattern" "$MAIL_LOG" > "$TEMP_MATCHES" 2>/dev/null
|
||||||
|
|
||||||
|
# Separate authentication events (IMAP/POP3 logins)
|
||||||
|
grep -E "imap-login|pop3-login|dovecot.*Login|Logged in|Disconnected" "$TEMP_MATCHES" > "$TEMP_AUTH" 2>/dev/null || true
|
||||||
|
|
||||||
|
# Get only email delivery events (exclude auth logs)
|
||||||
|
grep -v "imap-login\|pop3-login\|dovecot.*Login\|Logged in\|Disconnected" "$TEMP_MATCHES" > "$TEMP_MATCHES.delivery" 2>/dev/null || true
|
||||||
|
mv "$TEMP_MATCHES.delivery" "$TEMP_MATCHES"
|
||||||
|
|
||||||
if [ ! -s "$TEMP_MATCHES" ]; then
|
if [ ! -s "$TEMP_MATCHES" ]; then
|
||||||
print_error "❌ NO EMAIL ACTIVITY FOUND for $check_label"
|
print_error "❌ NO EMAIL ACTIVITY FOUND for $check_label"
|
||||||
echo ""
|
echo ""
|
||||||
@@ -129,14 +139,33 @@ echo ""
|
|||||||
print_header "📊 Activity Summary"
|
print_header "📊 Activity Summary"
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# Count different types
|
# Count different types (sanitize to remove newlines)
|
||||||
delivered=$(grep -ci "=> .*$search_pattern\|delivered.*$search_pattern" "$TEMP_MATCHES" || echo 0)
|
delivered=$(grep -ci "=> .*$search_pattern\|delivered.*$search_pattern" "$TEMP_MATCHES" 2>/dev/null || echo 0)
|
||||||
sent=$(grep -ci "<=.*$search_pattern" "$TEMP_MATCHES" || echo 0)
|
delivered=$(echo "$delivered" | head -1 | tr -d '\n\r')
|
||||||
bounced=$(grep -ci "bounce.*$search_pattern\|failed.*$search_pattern\|550.*$search_pattern" "$TEMP_MATCHES" || echo 0)
|
sent=$(grep -ci "<=.*$search_pattern" "$TEMP_MATCHES" 2>/dev/null || echo 0)
|
||||||
deferred=$(grep -ci "deferred.*$search_pattern\|retry.*$search_pattern\|temporarily rejected" "$TEMP_MATCHES" || echo 0)
|
sent=$(echo "$sent" | head -1 | tr -d '\n\r')
|
||||||
rejected=$(grep -ci "rejected.*$search_pattern\|denied.*$search_pattern\|blocked.*$search_pattern" "$TEMP_MATCHES" || echo 0)
|
bounced=$(grep -ci "bounce.*$search_pattern\|failed.*$search_pattern\|550.*$search_pattern" "$TEMP_MATCHES" 2>/dev/null || echo 0)
|
||||||
spf_fail=$(grep -ci "SPF.*fail.*$search_pattern" "$TEMP_MATCHES" || echo 0)
|
bounced=$(echo "$bounced" | head -1 | tr -d '\n\r')
|
||||||
dkim_fail=$(grep -ci "DKIM.*fail.*$search_pattern" "$TEMP_MATCHES" || echo 0)
|
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=$(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)
|
||||||
|
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')
|
||||||
|
received=$(grep -ci "=> .*$search_pattern" "$TEMP_MATCHES" 2>/dev/null || echo 0)
|
||||||
|
received=$(echo "$received" | head -1 | tr -d '\n\r')
|
||||||
|
|
||||||
|
# Count authentication events
|
||||||
|
auth_failed=$(grep -ci "auth failed\|Login aborted\|authentication failed" "$TEMP_AUTH" 2>/dev/null || echo 0)
|
||||||
|
auth_failed=$(echo "$auth_failed" | head -1 | tr -d '\n\r')
|
||||||
|
auth_success=$(grep -ci "Logged in\|Login:.*user=.*$search_pattern" "$TEMP_AUTH" 2>/dev/null || echo 0)
|
||||||
|
auth_success=$(echo "$auth_success" | head -1 | tr -d '\n\r')
|
||||||
|
|
||||||
if [ "$delivered" -gt 0 ]; then
|
if [ "$delivered" -gt 0 ]; then
|
||||||
print_success "✅ Delivered: $delivered emails successfully delivered"
|
print_success "✅ Delivered: $delivered emails successfully delivered"
|
||||||
@@ -166,7 +195,149 @@ if [ "$dkim_fail" -gt 0 ]; then
|
|||||||
print_warning "⚠ DKIM Failures: $dkim_fail signature failures"
|
print_warning "⚠ DKIM Failures: $dkim_fail signature failures"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ "$spam_rejected" -gt 0 ]; then
|
||||||
|
print_error "🚫 Spam Rejected: $spam_rejected emails marked as spam"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$greylist" -gt 0 ]; then
|
||||||
|
print_info "⏱ Greylisted: $greylist emails temporarily delayed (anti-spam measure)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$received" -gt 0 ]; then
|
||||||
|
print_info "📥 Received: $received emails received TO this $check_label"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Show email traffic patterns
|
||||||
|
if [ "$sent" -gt 0 ] || [ "$received" -gt 0 ]; then
|
||||||
echo ""
|
echo ""
|
||||||
|
print_header "📊 Email Traffic Patterns"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Top recipients (who this email is sending to)
|
||||||
|
if [ "$sent" -gt 0 ]; then
|
||||||
|
print_info "Top 5 recipients (emails sent TO):"
|
||||||
|
grep -i "<= .*$search_pattern" "$TEMP_MATCHES" | grep -oE "=> [^@]+@[^ ]+" | sed 's/=> //' | sort | uniq -c | sort -rn | head -5 | while read count recipient; do
|
||||||
|
echo " $recipient - $count emails"
|
||||||
|
done
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Top senders (who is sending to this email)
|
||||||
|
if [ "$received" -gt 0 ]; then
|
||||||
|
print_info "Top 5 senders (emails received FROM):"
|
||||||
|
grep -i "=> .*$search_pattern" "$TEMP_MATCHES" | grep -oE "<= [^@]+@[^ ]+" | sed 's/<= //' | sort | uniq -c | sort -rn | head -5 | while read count sender; do
|
||||||
|
echo " $sender - $count emails"
|
||||||
|
done
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Show authentication summary
|
||||||
|
if [ -s "$TEMP_AUTH" ]; then
|
||||||
|
echo ""
|
||||||
|
print_header "🔐 Authentication Activity (IMAP/POP3 Login Attempts)"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
if [ "$auth_success" -gt 0 ]; then
|
||||||
|
print_success "✅ Successful Logins: $auth_success (password is correct)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$auth_failed" -gt 0 ]; then
|
||||||
|
print_error "❌ Failed Logins: $auth_failed (WRONG PASSWORD or unauthorized access)"
|
||||||
|
|
||||||
|
# Extract IPs attempting failed logins
|
||||||
|
failed_ips=$(grep -i "auth failed\|Login aborted" "$TEMP_AUTH" | grep -oE "rip=[0-9.]+|from [0-9.]+" | sed 's/rip=//; s/from //' | sort | uniq -c | sort -rn)
|
||||||
|
if [ -n "$failed_ips" ]; then
|
||||||
|
echo ""
|
||||||
|
print_warning "IPs with failed login attempts:"
|
||||||
|
echo "$failed_ips" | while read count ip; do
|
||||||
|
echo " $ip - $count attempts"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
################################################################################
|
||||||
|
# Account Status Check (for specific email addresses)
|
||||||
|
################################################################################
|
||||||
|
|
||||||
|
if [ "$check_type" != "2" ]; then
|
||||||
|
print_header "📧 Email Account Status"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Extract username and domain from email
|
||||||
|
local_part=$(echo "$target" | cut -d'@' -f1)
|
||||||
|
domain_part=$(echo "$target" | cut -d'@' -f2)
|
||||||
|
|
||||||
|
# Check if email account exists in various locations
|
||||||
|
account_found=0
|
||||||
|
|
||||||
|
# Check cPanel mail directory
|
||||||
|
if [ -d "/home/*/mail/$domain_part/$local_part" ]; then
|
||||||
|
maildir=$(find /home/*/mail/$domain_part/$local_part -maxdepth 0 -type d 2>/dev/null | head -1)
|
||||||
|
if [ -n "$maildir" ]; then
|
||||||
|
print_success "✅ Email account EXISTS on this server"
|
||||||
|
account_found=1
|
||||||
|
|
||||||
|
# Get disk usage
|
||||||
|
if [ -d "$maildir" ]; then
|
||||||
|
disk_usage=$(du -sh "$maildir" 2>/dev/null | awk '{print $1}')
|
||||||
|
print_info "📊 Mailbox size: $disk_usage"
|
||||||
|
|
||||||
|
# Count messages
|
||||||
|
msg_count=$(find "$maildir" -type f -name "*:2,*" 2>/dev/null | wc -l)
|
||||||
|
print_info "📬 Messages stored: $msg_count"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for quota file
|
||||||
|
quota_file=$(find /home/*/mail/$domain_part/$local_part -name "maildirsize" 2>/dev/null | head -1)
|
||||||
|
if [ -f "$quota_file" ]; then
|
||||||
|
quota_info=$(head -1 "$quota_file" 2>/dev/null)
|
||||||
|
print_info "💾 Quota: $quota_info"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check Plesk mail directory
|
||||||
|
if [ $account_found -eq 0 ] && [ -d "/var/qmail/mailnames/$domain_part/$local_part" ]; then
|
||||||
|
print_success "✅ Email account EXISTS on this server (Plesk)"
|
||||||
|
account_found=1
|
||||||
|
maildir="/var/qmail/mailnames/$domain_part/$local_part"
|
||||||
|
disk_usage=$(du -sh "$maildir" 2>/dev/null | awk '{print $1}')
|
||||||
|
print_info "📊 Mailbox size: $disk_usage"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check generic /var/mail
|
||||||
|
if [ $account_found -eq 0 ] && [ -f "/var/mail/$local_part" ]; then
|
||||||
|
print_success "✅ Email account EXISTS in /var/mail"
|
||||||
|
account_found=1
|
||||||
|
disk_usage=$(du -sh "/var/mail/$local_part" 2>/dev/null | awk '{print $1}')
|
||||||
|
print_info "📊 Mailbox size: $disk_usage"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ $account_found -eq 0 ]; then
|
||||||
|
print_warning "⚠ Email account NOT FOUND on this server"
|
||||||
|
echo ""
|
||||||
|
echo "This could mean:"
|
||||||
|
echo " • Account doesn't exist (typo in email address?)"
|
||||||
|
echo " • Account is on a different mail server"
|
||||||
|
echo " • Mail is handled by external service (Google, Office365, etc.)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for forwarders
|
||||||
|
if [ -f "/etc/valiases/$domain_part" ]; then
|
||||||
|
forwarder=$(grep "^$local_part:" "/etc/valiases/$domain_part" 2>/dev/null)
|
||||||
|
if [ -n "$forwarder" ]; then
|
||||||
|
echo ""
|
||||||
|
print_info "📧 Forwarder configured:"
|
||||||
|
echo " $forwarder"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# Show verdict
|
# Show verdict
|
||||||
@@ -260,6 +431,31 @@ if [ "$rejected" -gt 0 ]; then
|
|||||||
echo ""
|
echo ""
|
||||||
fi
|
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
|
||||||
|
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"
|
||||||
|
else
|
||||||
|
echo " $line"
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$greylist" -gt 0 ]; then
|
||||||
|
print_header "⏱ Recent Greylisting Events (last 5)"
|
||||||
|
echo ""
|
||||||
|
print_info "Note: Greylisting is temporary - emails usually deliver after retry"
|
||||||
|
echo ""
|
||||||
|
grep -i "greylist" "$TEMP_MATCHES" | tail -5 | while read line; do
|
||||||
|
echo " $line"
|
||||||
|
done
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "$spf_fail" -gt 0 ] || [ "$dkim_fail" -gt 0 ]; then
|
if [ "$spf_fail" -gt 0 ] || [ "$dkim_fail" -gt 0 ]; then
|
||||||
print_header "⚠ Authentication Issues"
|
print_header "⚠ Authentication Issues"
|
||||||
echo ""
|
echo ""
|
||||||
@@ -305,6 +501,41 @@ if [ "$spf_fail" -gt 0 ]; then
|
|||||||
echo ""
|
echo ""
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if [ "$spam_rejected" -gt 0 ]; then
|
||||||
|
echo "To fix spam rejections:"
|
||||||
|
echo " 1. Check SpamAssassin score and adjust settings"
|
||||||
|
echo " 2. Verify email content isn't triggering spam filters"
|
||||||
|
echo " 3. Ensure proper SPF/DKIM authentication"
|
||||||
|
echo " 4. Check if sending domain has good reputation"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$greylist" -gt 0 ] && [ "$delivered" -eq 0 ]; then
|
||||||
|
echo "Greylisting delays:"
|
||||||
|
echo " • This is normal anti-spam behavior"
|
||||||
|
echo " • Emails should deliver after sender retries (5-15 minutes)"
|
||||||
|
echo " • No action needed unless emails never arrive"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$check_type" != "2" ] && [ $account_found -eq 0 ]; then
|
||||||
|
echo "Email account not found:"
|
||||||
|
echo " 1. Verify the email address is spelled correctly"
|
||||||
|
echo " 2. Check if domain DNS points to this server"
|
||||||
|
echo " 3. Create the email account if it should exist here"
|
||||||
|
echo " 4. Check if mail is handled by external service"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$auth_failed" -gt 0 ]; then
|
||||||
|
echo "Failed login attempts detected:"
|
||||||
|
echo " 1. Customer may be using wrong password"
|
||||||
|
echo " 2. Could be brute-force attack attempt"
|
||||||
|
echo " 3. Check IPs - block suspicious ones with firewall"
|
||||||
|
echo " 4. Advise customer to change password if compromised"
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
# Save full report
|
# Save full report
|
||||||
################################################################################
|
################################################################################
|
||||||
@@ -316,4 +547,4 @@ print_info "Full log saved to: $REPORT_FILE"
|
|||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
# Cleanup
|
# Cleanup
|
||||||
rm -f "$TEMP_MATCHES"
|
rm -f "$TEMP_MATCHES" "$TEMP_AUTH"
|
||||||
|
|||||||
Reference in New Issue
Block a user