#!/bin/bash ################################################################################ # Email Account/Domain Diagnostics ################################################################################ # Purpose: Verify email is working for specific address or domain # Shows proof of delivery or identifies why emails aren't working ################################################################################ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" source "$SCRIPT_DIR/lib/common-functions.sh" source "$SCRIPT_DIR/lib/system-detect.sh" source "$SCRIPT_DIR/lib/email-functions.sh" show_banner "Email Diagnostics - Verify Email Delivery" # Get mail log path MAIL_LOG=$(get_mail_log_path) if [ ! -f "$MAIL_LOG" ]; then print_error "Mail log not found: $MAIL_LOG" exit 1 fi print_success "Using mail log: $MAIL_LOG" echo "" # Ask what to check echo -e "${BOLD}What would you like to check?${NC}" echo "" echo " 1) Specific email address (e.g., user@example.com)" echo " 2) Entire domain (e.g., example.com)" echo "" read -p "Enter choice [1]: " check_type check_type=${check_type:-1} # Get email/domain to check echo "" if [ "$check_type" = "2" ]; then read -p "Enter domain to check (e.g., example.com): " target search_pattern="@${target}" check_label="domain $target" else read -p "Enter email address to check: " target search_pattern="$target" check_label="email $target" fi if [ -z "$target" ]; then print_error "No email/domain provided" exit 1 fi # Time period to check echo "" echo "Check logs from:" echo " 1) Last 1 hour" echo " 2) Last 6 hours" echo " 3) Last 24 hours (recommended)" echo " 4) Last 48 hours" echo " 5) Last week" echo "" read -p "Enter choice [3]: " time_choice time_choice=${time_choice:-3} case "$time_choice" in 1) hours=1 ;; 2) hours=6 ;; 3) hours=24 ;; 4) hours=48 ;; 5) hours=168 ;; *) hours=24 ;; esac echo "" print_info "Analyzing $check_label for last $hours hours..." echo "" # Calculate time cutoff if date --version 2>&1 | grep -q "GNU"; then # GNU date cutoff_time=$(date -d "$hours hours ago" +"%Y-%m-%d %H:%M:%S") else # BSD date (macOS) cutoff_time=$(date -v-${hours}H +"%Y-%m-%d %H:%M:%S") fi ################################################################################ # Analysis ################################################################################ TEMP_MATCHES="/tmp/email_diag_$$.txt" TEMP_AUTH="/tmp/email_auth_$$.txt" TEMP_ALL="/tmp/email_all_$$.txt" # Search multiple log files for comprehensive results # Check Exim logs (email delivery) if [ -f "/var/log/exim_mainlog" ]; then grep -i "$search_pattern" /var/log/exim_mainlog >> "$TEMP_ALL" 2>/dev/null || true fi # Check maillog (Dovecot auth + some delivery) if [ -f "/var/log/maillog" ]; then grep -i "$search_pattern" /var/log/maillog >> "$TEMP_ALL" 2>/dev/null || true fi # Check messages log (fallback) if [ -f "/var/log/messages" ]; then grep -i "$search_pattern" /var/log/messages >> "$TEMP_ALL" 2>/dev/null || true fi # If we found nothing, fall back to the detected mail log if [ ! -s "$TEMP_ALL" ]; then grep -i "$search_pattern" "$MAIL_LOG" > "$TEMP_ALL" 2>/dev/null || true fi # Separate authentication events (IMAP/POP3 logins) grep -E "imap-login|pop3-login|dovecot.*Login|Logged in|Disconnected" "$TEMP_ALL" > "$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_ALL" > "$TEMP_MATCHES" 2>/dev/null || true if [ ! -s "$TEMP_MATCHES" ]; then print_error "NO EMAIL ACTIVITY FOUND for $check_label" echo "" echo "This means:" echo " • No emails sent TO this $check_label" echo " • No emails sent FROM this $check_label" echo " • No delivery attempts logged" echo "" print_warning "Possible reasons:" echo " 1. Email address/domain doesn't exist on this server" echo " 2. No email activity in the last $hours hours" echo " 3. Emails are going to a different mail server" echo "" # Check if domain exists if [ "$check_type" = "2" ]; then if grep -q "$target" /etc/localdomains 2>/dev/null || grep -q "$target" /etc/userdomains 2>/dev/null; then print_info "Domain $target IS configured on this server" else print_warning "Domain $target NOT found in local domains" fi fi rm -f "$TEMP_MATCHES" "$TEMP_AUTH" "$TEMP_ALL" exit 0 fi total_lines=$(wc -l < "$TEMP_MATCHES") print_success "Found $total_lines log entries for $check_label" echo "" ################################################################################ # Categorize activity ################################################################################ # Count different types first (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') # Only count actual email bounces, not auth failures or successful deliveries bounced=$(grep -i "$search_pattern" "$TEMP_MATCHES" | grep -v "authenticator failed\|Authentication failed\|saved mail to\|=>" | 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 -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') # 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') 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') ################################################################################ # Quick Summary ################################################################################ print_header "QUICK SUMMARY" echo "" # Determine quick status total_problems=$((bounced + rejected + spam_rejected)) total_email_activity=$((sent + received + delivered)) if [ "$total_email_activity" -gt 0 ] && [ "$total_problems" -eq 0 ]; then print_success "Email appears to be working (${total_email_activity} email events, no problems)" elif [ "$total_email_activity" -gt 0 ] && [ "$total_problems" -gt 0 ]; then print_warning "Partial email issues (${total_email_activity} delivered, ${total_problems} failed)" elif [ "$total_problems" -gt 0 ]; then print_error "Email delivery problems detected (${total_problems} failures)" elif [ "$auth_success" -gt 0 ] && [ "$total_email_activity" -eq 0 ]; then print_info "Account active (${auth_success} logins) but no email traffic in last ${hours}h" elif [ "$auth_failed" -gt 0 ]; then print_warning "Failed login attempts detected (${auth_failed} attempts) - possible attack" else print_info "No activity detected in last ${hours} hours" fi echo "" ################################################################################ # Detailed Activity Breakdown ################################################################################ print_header "EMAIL DELIVERY ACTIVITY (last $hours hours)" echo "" # Always show main metrics for clarity if [ "$received" -gt 0 ]; then print_success "Received: $received emails (incoming TO this $check_label)" else echo "Received: 0 emails (no incoming mail)" fi if [ "$sent" -gt 0 ]; then print_success "Sent: $sent emails (outgoing FROM this $check_label)" else echo "Sent: 0 emails (no outgoing mail)" fi if [ "$delivered" -gt 0 ]; then print_success "Delivered: $delivered successful deliveries" else echo "Delivered: 0 (no completed deliveries logged)" fi echo "" # Only show problems if they exist has_problems=0 if [ "$bounced" -gt 0 ]; then print_error "Bounced: $bounced emails bounced/failed" has_problems=1 fi if [ "$deferred" -gt 0 ]; then print_warning "Deferred: $deferred emails temporarily delayed" has_problems=1 fi if [ "$rejected" -gt 0 ]; then print_error "Rejected: $rejected emails blocked/rejected" has_problems=1 fi if [ "$spam_rejected" -gt 0 ]; then print_error "Spam Rejected: $spam_rejected emails marked as spam" has_problems=1 fi if [ "$spf_fail" -gt 0 ]; then print_warning "SPF Failures: $spf_fail authentication failures" has_problems=1 fi if [ "$dkim_fail" -gt 0 ]; then print_warning "DKIM Failures: $dkim_fail signature failures" has_problems=1 fi if [ "$greylist" -gt 0 ]; then print_info "Greylisted: $greylist emails temporarily delayed (normal anti-spam)" fi if [ $has_problems -eq 0 ]; then print_success "No delivery problems detected" 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 "MAILBOX ACCESS ACTIVITY (IMAP/POP3 Logins)" echo "" print_info "This shows if customer can access their mailbox (not email delivery)" echo "" if [ "$auth_success" -gt 0 ]; then print_success "Successful Logins: $auth_success (password is correct, mailbox accessible)" fi if [ "$auth_failed" -gt 0 ]; then print_error "Failed Logins: $auth_failed (WRONG PASSWORD or brute-force attack)" # 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 maildir="" # 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 account_found=1 fi fi # Check Plesk mail directory if [ $account_found -eq 0 ] && [ -d "/var/qmail/mailnames/$domain_part/$local_part" ]; then account_found=1 maildir="/var/qmail/mailnames/$domain_part/$local_part" fi # Check generic /var/mail if [ $account_found -eq 0 ] && [ -f "/var/mail/$local_part" ]; then account_found=1 maildir="/var/mail/$local_part" fi # If successful logins exist, account must exist (even if we can't find the directory) if [ $account_found -eq 0 ] && [ "$auth_success" -gt 0 ]; then account_found=1 print_success "Email account EXISTS (confirmed by successful logins)" print_warning "Note: Mailbox directory not found in standard locations" elif [ $account_found -eq 1 ]; then print_success "Email account EXISTS on this server" # Show mailbox details if we found the directory if [ -n "$maildir" ] && [ -d "$maildir" ]; then disk_usage=$(du -sh "$maildir" 2>/dev/null | awk '{print $1}') if [ -n "$disk_usage" ]; then print_info "Mailbox size: $disk_usage" fi # Count messages msg_count=$(find "$maildir" -type f -name "*:2,*" 2>/dev/null | wc -l) if [ "$msg_count" -gt 0 ]; then print_info "Messages stored: $msg_count" fi # Check for quota file quota_file=$(find "$maildir" -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 else 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 ################################################################################ print_header "DIAGNOSTIC RESULT" echo "" # Determine overall status if [ "$delivered" -gt 0 ] && [ "$bounced" -eq 0 ] && [ "$rejected" -eq 0 ] && [ "$spam_rejected" -eq 0 ]; then print_success "EMAIL IS WORKING PROPERLY" echo "" echo "Evidence: $delivered successful deliveries in the last $hours hours" echo "No bounces, rejections, or spam filtering detected" echo "" elif [ "$delivered" -gt 0 ] && [ "$bounced" -gt 0 ]; then print_warning "EMAIL PARTIALLY WORKING" echo "" echo "Some emails delivered ($delivered) but some failed ($bounced)" echo "Check bounce reasons below for details" echo "" elif [ "$bounced" -gt 0 ] || [ "$rejected" -gt 0 ] || [ "$spam_rejected" -gt 0 ]; then print_error "EMAIL HAS DELIVERY PROBLEMS" echo "" echo "Emails are being rejected, bouncing, or filtered as spam" echo "See details below for why" echo "" elif [ "$deferred" -gt 0 ]; then print_warning "EMAIL DELAYED" echo "" echo "Emails are being deferred (temporary failures)" echo "This usually resolves itself within minutes" echo "" elif [ "$sent" -gt 0 ] || [ "$received" -gt 0 ]; then print_info "EMAIL ACTIVITY DETECTED" echo "" echo "Email traffic logged but no delivery confirmations in last $hours hours" echo "This may be normal depending on email volume" echo "" elif [ "$auth_success" -gt 0 ] || [ "$auth_failed" -gt 0 ]; then print_info "MAILBOX ACCESS ONLY" echo "" echo "No email delivery activity, only mailbox access (IMAP/POP3) detected" echo "This means the account exists and is being checked, but no emails sent/received" echo "" if [ "$auth_success" -gt 0 ]; then echo "Authentication is working (customer can access mailbox)" fi if [ "$auth_failed" -gt 0 ]; then echo "Failed login attempts detected (see details below)" fi echo "" else print_warning "NO EMAIL ACTIVITY FOUND" echo "" echo "No email sending, receiving, or mailbox access in the last $hours hours" echo "Account may be inactive or not used during this time period" echo "" fi ################################################################################ # Show recent activity samples ################################################################################ if [ "$delivered" -gt 0 ]; then print_header "RECENT SUCCESSFUL DELIVERIES (last 5 from past $hours hours)" echo "" print_info "PROOF - These emails were delivered recently:" echo "" grep -i "=> .*$search_pattern\|delivered.*$search_pattern" "$TEMP_MATCHES" | tail -5 | while read line; do # Extract timestamp if present 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 " ${GREEN}[$timestamp]${NC} $line" else echo " $line" fi done echo "" fi if [ "$bounced" -gt 0 ]; then print_header "DELIVERY FAILURE ANALYSIS" echo "" # Get all bounce lines TEMP_BOUNCES="/tmp/email_bounces_$$.txt" grep -i "$search_pattern" "$TEMP_MATCHES" | grep -v "authenticator failed\|Authentication failed\|saved mail to\|=>" | grep -i "550\|551\|552\|553\|554\|bounced\|Mail delivery failed\|** " > "$TEMP_BOUNCES" 2>/dev/null # Categorize failures (sanitize counts to remove newlines) recipient_unknown=$(grep -ci "user unknown\|No such user\|does not exist\|recipient rejected\|Recipient address rejected\|550.*User" "$TEMP_BOUNCES" 2>/dev/null || echo 0) recipient_unknown=$(echo "$recipient_unknown" | head -1 | tr -d '\n\r') mailbox_full=$(grep -ci "mailbox.*full\|quota.*exceeded\|552\|insufficient.*space\|over.*quota" "$TEMP_BOUNCES" 2>/dev/null || echo 0) mailbox_full=$(echo "$mailbox_full" | head -1 | tr -d '\n\r') relay_denied=$(grep -ci "relay.*denied\|relay.*not.*permitted\|relaying denied\|554.*relay" "$TEMP_BOUNCES" 2>/dev/null || echo 0) relay_denied=$(echo "$relay_denied" | head -1 | tr -d '\n\r') # Only count actual blacklist/RBL rejections, exclude common false positives blocked=$(grep -i "$TEMP_BOUNCES" -e "blacklist" -e "block list" -e "RBL" -e "DNSBL" -e "listed in" -e "blocked using" -e "on our block list" | \ grep -v "mailbox.*full\|quota.*exceeded\|authentication\|auth.*failed\|SPF.*fail\|DKIM.*fail\|user unknown\|does not exist\|relay.*denied\|content.*filter\|rejected due to content\|greylisted\|greylist" | \ wc -l 2>/dev/null || echo 0) blocked=$(echo "$blocked" | head -1 | tr -d '\n\r') dns_failure=$(grep -ci "domain.*not.*found\|Host.*unknown\|Name.*not.*resolve\|MX.*not.*found" "$TEMP_BOUNCES" 2>/dev/null || echo 0) dns_failure=$(echo "$dns_failure" | head -1 | tr -d '\n\r') connection_fail=$(grep -ci "timeout\|connection.*refused\|connection.*failed\|Network.*unreachable" "$TEMP_BOUNCES" 2>/dev/null || echo 0) connection_fail=$(echo "$connection_fail" | head -1 | tr -d '\n\r') print_info "Failure breakdown by reason:" echo "" if [ "$recipient_unknown" -gt 0 ]; then print_error " Recipient doesn't exist: $recipient_unknown emails" echo " Reason: Email address is invalid or doesn't exist on recipient server" grep -i "user unknown\|No such user\|does not exist\|recipient rejected\|550.*User" "$TEMP_BOUNCES" | head -2 | while read line; do echo " Example: $(echo "$line" | grep -oE '[^ ]+@[^ ,]+' | head -1)" done echo "" fi if [ "$mailbox_full" -gt 0 ]; then print_warning " Mailbox full: $mailbox_full emails" echo " Reason: Recipient's mailbox has exceeded storage quota" grep -i "mailbox.*full\|quota.*exceeded\|552" "$TEMP_BOUNCES" | head -2 | while read line; do echo " Example: $(echo "$line" | grep -oE '[^ ]+@[^ ,]+' | head -1)" done echo "" fi if [ "$relay_denied" -gt 0 ]; then print_error " Relay denied: $relay_denied emails" echo " Reason: Server not authorized to send to this domain" echo " Solution: Check if server IP needs to be whitelisted" echo "" fi if [ "$blocked" -gt 0 ]; then print_error " Blocked/Spam filtered: $blocked emails" echo " Reason: Sender IP or domain is blacklisted, or content flagged as spam" echo "" # Extract specific blacklists from rejection messages (strict filter to avoid false positives) TEMP_BLACKLISTS="/tmp/email_blacklists_$$.txt" grep -iE "blacklist|block list|RBL|DNSBL|listed in|blocked using|on our block list|S3150|S3140|AS\(48|CS01|local policy|gmail.*(suspicious|reputation|spam|detected).*reputation|gmail.*detected.*suspicious|spamhaus|barracuda|spamcop|sorbs|abuseat|yahoo.*block|yahoo.*reject|aol.*block|aol.*reject|me\.com.*reject|icloud.*reject|mac\.com.*reject|protonmail.*block|protonmail.*reject|pm\.me.*reject|zoho.*block|zoho.*reject|fastmail.*block|fastmail.*reject|outlook.*block|hotmail.*block|live\.com.*block|msn\.com.*block" "$TEMP_BOUNCES" > "$TEMP_BLACKLISTS" 2>/dev/null || true # Try to extract server IP from rejection messages extracted_ip="" if grep -qiE '\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\]|from [0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' "$TEMP_BLACKLISTS" 2>/dev/null; then extracted_ip=$(grep -oE '\[?[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\]?' "$TEMP_BLACKLISTS" 2>/dev/null | head -1 | tr -d '[]') fi if [ -s "$TEMP_BLACKLISTS" ]; then # Blacklist/Provider detection with real-world message patterns # Format: "name|display_name|removal_url|detection_keywords" blacklist_db=( # Traditional RBLs - Format: "id|name|url|patterns|difficulty|avg_time" "spamhaus|Spamhaus (ZEN/SBL/XBL)|https://check.spamhaus.org/|spamhaus|sbl.spamhaus|zen.spamhaus|xbl.spamhaus|pbl.spamhaus|HARD|1-7 days" "barracuda|Barracuda Central BRBL|https://www.barracudacentral.org/rbl/removal-request|barracuda|MODERATE|1-3 days" "spamcop|SpamCop Blocking List|https://www.spamcop.net/bl.shtml|spamcop|bl.spamcop|EASY|Same day" "sorbs|SORBS DNSBL|http://www.sorbs.net/lookup.shtml|sorbs|dnsbl.sorbs|MODERATE|1-2 days" "cbl|CBL (Composite Block List)|https://cbl.abuseat.org/lookup.cgi|cbl.abuseat|abuseat|MODERATE|1-3 days" "psbl|PSBL (Passive Spam Block List)|https://psbl.org/|psbl.surriel|psbl|MODERATE|1-2 days" "uceprotect|UCEPROTECT Network|http://www.uceprotect.net/en/rblcheck.php|uceprotect|HARD|3-7 days" "invaluement|Invaluement DNSBL|http://www.invaluement.com/removal/|invaluement|MODERATE|1-3 days" "mailspike|Mailspike Blacklist|https://mailspike.net/anubis/lookup.html|mailspike|EASY|Same day" "truncate|GBUdb (Truncate)|http://www.gbudb.com/|truncate.gbudb|gbudb|EASY|Same day" "dnsrbl|DNSRBL.org|http://www.dnsrbl.org/|dnsrbl|MODERATE|1-2 days" "backscatterer|Backscatterer.org|http://www.backscatterer.org/|backscatterer|EASY|Same day" "dnswl|DNSWL (actually whitelist)|https://www.dnswl.org/|dnswl|N/A|N/A" "mxtoolbox|MXToolbox Blacklist|https://mxtoolbox.com/blacklists.aspx|mxtoolbox|EASY|Same day" # Major Email Providers (not traditional RBLs but they block based on reputation) "microsoft|Microsoft/Outlook/Hotmail/Live Block|https://sendersupport.olc.protection.outlook.com/snds/|outlook.*block|hotmail.*block|live\.com.*block|msn\.com.*block|protection\.outlook.*block|on our block list|S3150|S3140|AS\(48|MODERATE|Same day" "gmail|Gmail Reputation Filter|https://support.google.com/mail/contact/bulk_send_new|gmail.*suspicious|gmail.*reputation|gmail.*spam|gmail.*blocked|gmail.*detected|EASY|Same day" "apple|Apple iCloud/me.com/mac.com Block|https://support.apple.com/|local policy|icloud.*reject|me\.com.*reject|mac\.com.*reject|CS01|HARD|3-7 days" "yahoo|Yahoo/AOL Mail Block|https://senders.yahooinc.com/contact|yahoo.*block|yahoo.*reject|aol.*block|aol.*reject|verizonmedia.*block|MODERATE|1-2 days" "zoho|Zoho Mail Block|https://www.zoho.com/mail/help/|zoho.*reject|zoho.*block|zohomail.*reject|EASY|Same day" "protonmail|ProtonMail Block|https://protonmail.com/support/|protonmail.*reject|protonmail.*block|pm\.me.*reject|MODERATE|1-3 days" "fastmail|Fastmail Block|https://www.fastmail.help/|fastmail.*reject|fastmail.*block|MODERATE|1-2 days" "att|AT&T/SBC Block List|https://www.att.com/support/|att\.net.*block|sbcglobal.*block|MODERATE|1-3 days" "comcast|Comcast/Xfinity Block|http://postmaster.comcast.net/|comcast.*block|xfinity.*block|MODERATE|1-3 days" "cox|Cox Communications Block|https://www.cox.com/residential/support.html|cox\.net.*block|MODERATE|1-3 days" "verizon|Verizon/Frontier Block|https://www.verizon.com/support/|verizon.*block|frontier.*block|MODERATE|1-3 days" "spectrum|Spectrum/Charter Block|https://www.spectrum.net/support|spectrum.*block|charter.*block|rr\.com.*block|MODERATE|1-3 days" ) detected_blacklists="" # Check each blacklist pattern against rejection messages for entry in "${blacklist_db[@]}"; do IFS='|' read -r bl_id bl_name bl_url bl_patterns bl_difficulty bl_time <<< "$entry" # Split patterns and check each one matched=0 IFS='|' read -ra PATTERNS <<< "$bl_patterns" for pattern in "${PATTERNS[@]}"; do if grep -qiE "$pattern" "$TEMP_BLACKLISTS" 2>/dev/null; then matched=1 break fi done if [ $matched -eq 1 ]; then detected_blacklists="${detected_blacklists}${bl_name}|${bl_url}|${bl_difficulty}|${bl_time}\n" fi done if [ -n "$detected_blacklists" ]; then print_warning " ⚠ SPECIFIC BLACKLISTS/BLOCKS DETECTED:" echo "" if [ -n "$extracted_ip" ]; then print_info " Server IP detected: $extracted_ip" echo "" fi echo -e "$detected_blacklists" | sort -u | while IFS='|' read -r bl_name bl_url bl_difficulty bl_time; do if [ -n "$bl_name" ]; then # Format difficulty and time if available if [ -n "$bl_difficulty" ] && [ -n "$bl_time" ]; then print_error " • $bl_name [$bl_difficulty - $bl_time]" else print_error " • $bl_name" fi # Generate IP-specific lookup URL if IP was extracted if [ -n "$extracted_ip" ]; then case "$bl_url" in *spamhaus.org*) echo " Lookup: https://check.spamhaus.org/?ip=${extracted_ip}" ;; *barracudacentral.org*) echo " Lookup: https://www.barracudacentral.org/rbl/lookup?ip=${extracted_ip}" ;; *spamcop.net*) echo " Lookup: https://www.spamcop.net/query.html?ip=${extracted_ip}" ;; *sorbs.net*) echo " Lookup: http://www.sorbs.net/lookup.shtml?ip=${extracted_ip}" ;; *) echo " Removal/Info: $bl_url" ;; esac else echo " Removal/Info: $bl_url" fi echo "" fi done else # Generic spam filter (not a specific blacklist) echo " ℹ No specific blacklist detected in rejection message" echo " May be content-based spam filtering or unlisted blacklist" echo "" fi # Show example rejection messages print_info " 📋 EXAMPLE REJECTION MESSAGES:" echo "" head -3 "$TEMP_BLACKLISTS" | while read line; do # Truncate very long lines echo " $(echo "$line" | cut -c1-120)" done echo "" fi echo " 🔧 RECOMMENDED ACTIONS:" echo " 1. Check your server IP against the detected blacklists above" echo " 2. Visit removal/delisting URLs to submit requests" echo " 3. Verify SPF/DKIM/DMARC records are correctly configured" echo " 4. Check if server has been compromised (sending spam)" echo " 5. Review mail queue for suspicious outbound emails" echo "" rm -f "$TEMP_BLACKLISTS" fi if [ "$dns_failure" -gt 0 ]; then print_error " DNS/Domain issues: $dns_failure emails" echo " Reason: Recipient domain doesn't exist or has no MX records" grep -i "domain.*not.*found\|Host.*unknown" "$TEMP_BOUNCES" | head -2 | while read line; do echo " Example: $(echo "$line" | grep -oE '[^ ]+@[^ ,]+' | head -1)" done echo "" fi if [ "$connection_fail" -gt 0 ]; then print_warning " Connection failures: $connection_fail emails" echo " Reason: Could not connect to recipient mail server (temporary)" echo " Solution: These usually resolve themselves, check if persistent" echo "" fi # Calculate uncategorized total_categorized=$((recipient_unknown + mailbox_full + relay_denied + blocked + dns_failure + connection_fail)) if [ "$total_categorized" -lt "$bounced" ]; then other=$((bounced - total_categorized)) print_warning " Other failures: $other emails" echo " See detailed logs below for specific reasons" echo "" fi # Show recent failures for reference print_header "RECENT FAILURE EXAMPLES (last 3)" echo "" grep -i "$search_pattern" "$TEMP_MATCHES" | grep -v "authenticator failed\|Authentication failed\|saved mail to\|=>" | grep -i "550\|551\|552\|553\|554\|bounced\|Mail delivery failed\|** " | tail -3 | 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}" # Extract the key error message error_msg=$(echo "$line" | grep -oE "550 [^<]*|551 [^<]*|552 [^<]*|User unknown|does not exist|Mailbox full|relay denied" | head -1) if [ -n "$error_msg" ]; then echo " Error: $error_msg" fi recipient=$(echo "$line" | grep -oE '[^ ]+@[^ ,<>]+' | grep -v "$search_pattern" | head -1) if [ -n "$recipient" ]; then echo " To: $recipient" fi fi echo "" done rm -f "$TEMP_BOUNCES" fi if [ "$rejected" -gt 0 ]; then print_header "RECENT REJECTIONS (last 5)" echo "" 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 "" fi if [ "$spam_rejected" -gt 0 ]; then print_header "RECENT SPAM REJECTIONS (last 5)" echo "" 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" 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 "" if [ "$spf_fail" -gt 0 ]; then echo "SPF failures detected:" grep -i "SPF.*fail" "$TEMP_MATCHES" | head -3 echo "" fi if [ "$dkim_fail" -gt 0 ]; then echo "DKIM failures detected:" grep -i "DKIM.*fail" "$TEMP_MATCHES" | head -3 echo "" fi fi ################################################################################ # Recommendations ################################################################################ print_header "RECOMMENDATIONS" echo "" if [ "$bounced" -gt 0 ]; then echo "To fix bounces:" echo " 1. Verify the recipient email address is correct" echo " 2. Check if recipient mailbox is full" echo " 3. Ensure domain DNS is configured properly" echo "" fi if [ "$rejected" -gt 0 ]; then echo "To fix rejections:" echo " 1. Check if server IP is blacklisted (use Blacklist Check tool)" echo " 2. Verify SPF/DKIM/DMARC records are correct" echo " 3. Check if recipient is blocking your domain" echo "" fi if [ "$spf_fail" -gt 0 ]; then echo "To fix SPF failures:" echo " 1. Add this server's IP to domain's SPF record" echo " 2. Use SPF/DKIM/DMARC Check tool for details" 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:-1}" != "2" ] && [ "${account_found:-0}" -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 ################################################################################ REPORT_FILE="/tmp/email_diag_${target//[@.]/_}_$(date +%Y%m%d_%H%M%S).txt" cp "$TEMP_MATCHES" "$REPORT_FILE" print_info "Full log saved to: $REPORT_FILE" echo "" # Cleanup rm -f "$TEMP_MATCHES" "$TEMP_AUTH" "$TEMP_ALL" "$TEMP_BOUNCES"