diff --git a/modules/email/email-diagnostics.sh b/modules/email/email-diagnostics.sh index 9d33091..d87e591 100755 --- a/modules/email/email-diagnostics.sh +++ b/modules/email/email-diagnostics.sh @@ -89,8 +89,18 @@ fi ################################################################################ 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 +# 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 print_error "❌ NO EMAIL ACTIVITY FOUND for $check_label" echo "" @@ -129,14 +139,33 @@ echo "" print_header "📊 Activity Summary" echo "" -# Count different types -delivered=$(grep -ci "=> .*$search_pattern\|delivered.*$search_pattern" "$TEMP_MATCHES" || echo 0) -sent=$(grep -ci "<=.*$search_pattern" "$TEMP_MATCHES" || echo 0) -bounced=$(grep -ci "bounce.*$search_pattern\|failed.*$search_pattern\|550.*$search_pattern" "$TEMP_MATCHES" || echo 0) -deferred=$(grep -ci "deferred.*$search_pattern\|retry.*$search_pattern\|temporarily rejected" "$TEMP_MATCHES" || echo 0) -rejected=$(grep -ci "rejected.*$search_pattern\|denied.*$search_pattern\|blocked.*$search_pattern" "$TEMP_MATCHES" || echo 0) -spf_fail=$(grep -ci "SPF.*fail.*$search_pattern" "$TEMP_MATCHES" || echo 0) -dkim_fail=$(grep -ci "DKIM.*fail.*$search_pattern" "$TEMP_MATCHES" || echo 0) +# Count different types (sanitize to remove newlines) +delivered=$(grep -ci "=> .*$search_pattern\|delivered.*$search_pattern" "$TEMP_MATCHES" 2>/dev/null || echo 0) +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) +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=$(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 print_success "✅ Delivered: $delivered emails successfully delivered" @@ -166,8 +195,150 @@ if [ "$dkim_fail" -gt 0 ]; then print_warning "⚠ DKIM Failures: $dkim_fail signature failures" 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 "" + 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 ################################################################################ @@ -260,6 +431,31 @@ if [ "$rejected" -gt 0 ]; then echo "" 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 print_header "⚠ Authentication Issues" echo "" @@ -305,6 +501,41 @@ if [ "$spf_fail" -gt 0 ]; then echo "" 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 ################################################################################ @@ -316,4 +547,4 @@ print_info "Full log saved to: $REPORT_FILE" echo "" # Cleanup -rm -f "$TEMP_MATCHES" +rm -f "$TEMP_MATCHES" "$TEMP_AUTH"