Commit ea38e896a987
Changed files (4)
docs
home
common
services
docs/mail-monitoring.md
@@ -0,0 +1,377 @@
+# Mail Services Monitoring Guide
+
+Comprehensive guide to monitoring your IMAP IDLE mail services.
+
+## Quick Status Check
+
+### One-Command Overview
+```bash
+mail-status
+```
+
+Shows:
+- Status of all mail services (running/failed/inactive)
+- When each service started
+- Memory usage
+- Recent mail activity (last 30 minutes)
+- Quick action commands
+
+### Example Output
+```
+=== Mail Services Status ===
+
+✓ imapfilter (IMAP IDLE filtering) (imapfilter.service)
+ Started: Mon 2026-01-14 10:23:15 CET
+ Memory: 12MB
+
+✓ goimapnotify (iCloud IDLE sync) (goimapnotify-icloud.service)
+ Started: Mon 2026-01-14 10:23:18 CET
+ Memory: 8MB
+
+✓ imapfilter rules updater (timer) (imapfilter-rules-update.timer)
+ Started: Mon 2026-01-14 10:23:15 CET
+
+=== Recent Mail Activity ===
+
+Recent mbsync activity:
+ Jan 14 11:05:32 athena goimapnotify[1234]: mbsync icloud
+ Jan 14 11:05:35 athena goimapnotify[1234]: mu index --quiet
+```
+
+## Live Log Monitoring
+
+### Watch All Mail Logs
+```bash
+mail-logs
+```
+
+Follows logs from:
+- imapfilter.service
+- goimapnotify-*.service
+- imapfilter-rules-update.service
+
+Press Ctrl+C to exit.
+
+### Individual Service Logs
+```bash
+# imapfilter only
+journalctl --user -u imapfilter.service -f
+
+# goimapnotify only
+journalctl --user -u goimapnotify-icloud.service -f
+
+# Rules updater
+journalctl --user -u imapfilter-rules-update.service -f
+```
+
+### Filter for Specific Events
+```bash
+# Only show mail sync events
+journalctl --user -u "goimapnotify-*.service" | grep -i "mbsync\|new mail"
+
+# Only show indexing
+journalctl --user -u "goimapnotify-*.service" | grep -i "mu index"
+
+# Only show IDLE events
+journalctl --user -u imapfilter.service | grep -i "IDLE"
+```
+
+## Connection Status
+
+### Check IMAP IDLE Connections
+```bash
+mail-idle-status
+```
+
+Shows:
+- Active TCP connections to IMAP servers (port 993)
+- Expected connections (iCloud, Gmail if configured)
+- Service status for each mail service
+
+### Manual Connection Check
+```bash
+# Show all connections to port 993 (IMAPS)
+ss -tn | grep :993
+
+# Expected output:
+# ESTAB 0 0 192.168.1.100:45678 17.42.251.72:993 # iCloud
+# ESTAB 0 0 192.168.1.100:45679 142.250.185.108:993 # Gmail
+```
+
+## Testing Mail Delivery
+
+### Interactive Test
+```bash
+mail-test
+```
+
+Helps you:
+1. Send a test email
+2. Watch logs for delivery
+3. Verify instant sync works
+
+### Manual Testing
+```bash
+# Start watching logs
+journalctl --user -f -u "goimapnotify-*.service" | grep -i "new mail\|mbsync"
+
+# In another terminal or phone, send email to yourself
+
+# You should see within seconds:
+# - "new mail detected" or similar from goimapnotify
+# - "mbsync icloud" execution
+# - "mu index" execution
+```
+
+## Standard systemd Commands
+
+### Service Status
+```bash
+# Check if service is running
+systemctl --user is-active imapfilter.service
+systemctl --user is-active goimapnotify-icloud.service
+
+# Full status with details
+systemctl --user status imapfilter.service
+systemctl --user status goimapnotify-icloud.service
+```
+
+### Start/Stop/Restart
+```bash
+# Restart a service
+systemctl --user restart imapfilter.service
+systemctl --user restart goimapnotify-icloud.service
+
+# Stop a service
+systemctl --user stop imapfilter.service
+
+# Start a service
+systemctl --user start imapfilter.service
+```
+
+### View Logs
+```bash
+# Last 50 lines
+journalctl --user -u imapfilter.service -n 50
+
+# Since boot
+journalctl --user -u imapfilter.service -b
+
+# Since specific time
+journalctl --user -u imapfilter.service --since "1 hour ago"
+journalctl --user -u imapfilter.service --since "2026-01-14 10:00"
+
+# Follow live (like tail -f)
+journalctl --user -u imapfilter.service -f
+```
+
+## Troubleshooting
+
+### Service Not Running
+
+**Check why it failed:**
+```bash
+systemctl --user status imapfilter.service
+journalctl --user -u imapfilter.service -n 50
+```
+
+**Common issues:**
+- Password authentication failure → Check passage password
+- Network connectivity → Check internet connection
+- Configuration error → Check logs for syntax errors
+
+**Fix and restart:**
+```bash
+systemctl --user restart imapfilter.service
+```
+
+### Mail Not Arriving Instantly
+
+**1. Check IDLE connections are established:**
+```bash
+mail-idle-status
+```
+
+**2. Check for errors in logs:**
+```bash
+journalctl --user -u goimapnotify-icloud.service -n 50
+```
+
+**3. Test manually:**
+```bash
+# Trigger manual sync
+mbsync icloud
+mu index
+```
+
+**4. Verify services are running:**
+```bash
+mail-status
+```
+
+### Database Lock Errors
+
+If you see "already locked" errors:
+
+```bash
+# Check if mu4e is running in Emacs
+pgrep -u $UID mu
+
+# If yes, that's expected - goimapnotify should use emacsclient
+# Check goimapnotify logs to verify it's using emacsclient:
+journalctl --user -u goimapnotify-icloud.service | grep -i "emacsclient\|mu index"
+```
+
+### High Memory Usage
+
+```bash
+# Check memory usage
+systemctl --user show imapfilter.service --property=MemoryCurrent
+systemctl --user show goimapnotify-icloud.service --property=MemoryCurrent
+
+# Restart if needed
+systemctl --user restart imapfilter.service
+```
+
+## Metrics to Watch
+
+### Service Uptime
+```bash
+# How long has the service been running?
+systemctl --user show imapfilter.service --property=ActiveEnterTimestamp
+```
+
+### Restart Count
+```bash
+# How many times has it restarted?
+systemctl --user show imapfilter.service --property=NRestarts
+```
+
+### Last Sync Time
+```bash
+# When did goimapnotify last sync?
+journalctl --user -u goimapnotify-icloud.service | grep "mbsync" | tail -1
+```
+
+### Mail Delivery Latency
+To measure how fast mail arrives:
+
+1. Note the time you send a test email
+2. Watch logs: `journalctl --user -f -u goimapnotify-icloud.service`
+3. Note when you see "mbsync" run
+4. Calculate difference
+
+Expected: **< 30 seconds** from send to sync
+
+## Alerting Setup
+
+### Failure Notifications
+
+The mail-monitor.nix includes automatic failure logging:
+- Failures are logged to `~/.local/share/mail-service-failures.log`
+- Check this file periodically
+
+```bash
+# View failure log
+cat ~/.local/share/mail-service-failures.log
+
+# Monitor for new failures
+tail -f ~/.local/share/mail-service-failures.log
+```
+
+### Optional: ntfy Integration
+
+Uncomment in `mail-monitor.nix` to send push notifications on failure:
+```nix
+ExecStart = "${pkgs.ntfy-sh}/bin/ntfy publish --token $(passage show ntfy/token) topic 'Mail service %i failed'";
+```
+
+## Daily Health Check
+
+Run this once a day or add to your morning routine:
+
+```bash
+# Quick status check
+mail-status
+
+# Check for any failures in last 24 hours
+journalctl --user -u "imapfilter.service" --since "24 hours ago" | grep -i "error\|failed" || echo "No errors"
+journalctl --user -u "goimapnotify-*.service" --since "24 hours ago" | grep -i "error\|failed" || echo "No errors"
+
+# Verify IDLE connections
+mail-idle-status
+```
+
+## Performance Benchmarks
+
+### Expected Behavior
+
+| Metric | Expected Value |
+|--------|---------------|
+| Mail delivery latency | < 30 seconds |
+| Service memory usage | 8-15 MB per service |
+| CPU usage (idle) | ~0% |
+| IMAP connections | 2 (iCloud + imapfilter) |
+| Service restarts | 0 per day normally |
+
+### When to Investigate
+
+- Mail takes > 1 minute to arrive
+- Services restart > 3 times per day
+- Memory usage > 50 MB
+- No IDLE connections shown
+- Errors in logs
+
+## Useful Aliases
+
+Add to your shell config:
+
+```bash
+# Quick mail status
+alias ms='mail-status'
+
+# Watch mail logs
+alias ml='mail-logs'
+
+# Check IDLE connections
+alias mi='mail-idle-status'
+
+# Test mail delivery
+alias mt='mail-test'
+```
+
+## Integration with mu4e
+
+### Verify Emacs Integration
+
+When mail arrives, you should see in Emacs:
+- Modeline updates (if configured)
+- New mail appears in mu4e headers view automatically
+
+### Check mu4e Update Function
+
+In Emacs:
+```elisp
+;; Manually trigger update (should work even with automatic updates)
+M-x mu4e-update-index
+
+;; Check update interval (should be nil)
+C-h v mu4e-update-interval
+;; Should show: nil
+```
+
+## Monitoring Checklist
+
+- [ ] Run `mail-status` - all services green
+- [ ] Run `mail-idle-status` - connections established
+- [ ] Send test email - arrives within 30 seconds
+- [ ] Check logs - no errors in last 24 hours
+- [ ] Verify mu4e updates automatically
+- [ ] Check failure log is empty
+
+## Further Reading
+
+- systemd service management: `man systemctl`
+- journalctl logs: `man journalctl`
+- Email skill: `~/.config/claude/skills/Email/SKILL.md`
+- Database locking: `~/.config/claude/skills/Email/reference/DatabaseLocking.md`
home/common/services/mail-monitor.nix
@@ -0,0 +1,206 @@
+{ pkgs, config, ... }:
+let
+ # Script to check status of all mail-related services
+ mail-status = pkgs.writeShellScriptBin "mail-status" ''
+ #!/usr/bin/env bash
+ # Mail services monitoring script
+
+ set -euo pipefail
+
+ # Colors for output
+ RED='\033[0;31m'
+ GREEN='\033[0;32m'
+ YELLOW='\033[1;33m'
+ BLUE='\033[0;34m'
+ NC='\033[0m' # No Color
+
+ echo -e "''${BLUE}=== Mail Services Status ===""${NC}"
+ echo
+
+ # Check each service
+ check_service() {
+ local service=$1
+ local description=$2
+
+ if systemctl --user is-active --quiet "$service"; then
+ echo -e "''${GREEN}✓""${NC} $description ($service)"
+
+ # Show when it started
+ local since=$(systemctl --user show "$service" --property=ActiveEnterTimestamp --value)
+ echo " Started: $since"
+
+ # Show memory usage
+ local memory=$(systemctl --user show "$service" --property=MemoryCurrent --value)
+ if [ "$memory" != "[not set]" ] && [ "$memory" != "0" ]; then
+ local memory_mb=$((memory / 1024 / 1024))
+ echo " Memory: ''${memory_mb}MB"
+ fi
+ else
+ echo -e "''${RED}✗""${NC} $description ($service)"
+
+ # Check if it failed
+ if systemctl --user is-failed --quiet "$service"; then
+ echo -e " ''${RED}Status: FAILED""${NC}"
+ echo " Run: journalctl --user -u $service -n 20"
+ else
+ echo -e " ''${YELLOW}Status: Inactive""${NC}"
+ fi
+ fi
+ echo
+ }
+
+ # Check services
+ check_service "imapfilter.service" "imapfilter (IMAP IDLE filtering)"
+ check_service "goimapnotify-icloud.service" "goimapnotify (iCloud IDLE sync)"
+
+ # Check if redhat account exists (kyushu only)
+ if systemctl --user list-unit-files "goimapnotify-redhat.service" >/dev/null 2>&1; then
+ check_service "goimapnotify-redhat.service" "goimapnotify (RedHat IDLE sync)"
+ fi
+
+ check_service "imapfilter-rules-update.timer" "imapfilter rules updater (timer)"
+
+ echo -e "''${BLUE}=== Recent Mail Activity ===""${NC}"
+ echo
+
+ # Check for recent mail syncs in journals
+ echo "Recent mbsync activity:"
+ journalctl --user -u "goimapnotify-*.service" --since "30 minutes ago" | \
+ grep -i "mbsync\|index\|new mail" | tail -5 || echo " No recent activity"
+
+ echo
+ echo "Recent imapfilter activity:"
+ journalctl --user -u imapfilter.service --since "30 minutes ago" | \
+ grep -i "filter\|IDLE\|message" | tail -5 || echo " No recent activity"
+
+ echo
+ echo -e "''${BLUE}=== Quick Actions ===""${NC}"
+ echo "View logs:"
+ echo " journalctl --user -u imapfilter.service -f"
+ echo " journalctl --user -u goimapnotify-icloud.service -f"
+ echo
+ echo "Restart services:"
+ echo " systemctl --user restart imapfilter.service"
+ echo " systemctl --user restart goimapnotify-icloud.service"
+ '';
+
+ # Script to watch mail service logs in real-time
+ mail-logs = pkgs.writeShellScriptBin "mail-logs" ''
+ #!/usr/bin/env bash
+ # Watch mail service logs in real-time
+
+ echo "Watching mail service logs (Ctrl+C to exit)..."
+ echo "Services: imapfilter, goimapnotify-*"
+ echo
+
+ journalctl --user -f \
+ -u imapfilter.service \
+ -u "goimapnotify-*.service" \
+ -u imapfilter-rules-update.service
+ '';
+
+ # Script to check IMAP IDLE connection status
+ mail-idle-status = pkgs.writeShellScriptBin "mail-idle-status" ''
+ #!/usr/bin/env bash
+ # Check if IMAP IDLE connections are established
+
+ set -euo pipefail
+
+ GREEN='\033[0;32m'
+ RED='\033[0;31m'
+ NC='\033[0m'
+
+ echo "=== IMAP IDLE Connection Status ==="
+ echo
+
+ # Check for active IMAP connections
+ echo "Active IMAP connections:"
+ if command -v ss >/dev/null 2>&1; then
+ ss -tn | grep ":993" || echo " None found"
+ elif command -v netstat >/dev/null 2>&1; then
+ netstat -tn | grep ":993" || echo " None found"
+ else
+ echo " (ss or netstat not available)"
+ fi
+
+ echo
+ echo "Expected connections:"
+ echo " - imap.mail.me.com:993 (iCloud)"
+ if systemctl --user list-unit-files "goimapnotify-redhat.service" >/dev/null 2>&1; then
+ echo " - imap.gmail.com:993 (Gmail/RedHat)"
+ fi
+
+ echo
+ echo "Service status:"
+ systemctl --user is-active imapfilter.service >/dev/null 2>&1 && \
+ echo -e " ''${GREEN}imapfilter: active""${NC}" || \
+ echo -e " ''${RED}imapfilter: inactive""${NC}"
+
+ systemctl --user is-active goimapnotify-icloud.service >/dev/null 2>&1 && \
+ echo -e " ''${GREEN}goimapnotify-icloud: active""${NC}" || \
+ echo -e " ''${RED}goimapnotify-icloud: inactive""${NC}"
+ '';
+
+ # Script to test mail delivery
+ mail-test = pkgs.writeShellScriptBin "mail-test" ''
+ #!/usr/bin/env bash
+ # Send a test email and monitor for delivery
+
+ set -euo pipefail
+
+ YELLOW='\033[1;33m'
+ GREEN='\033[0;32m'
+ BLUE='\033[0;34m'
+ NC='\033[0m'
+
+ echo -e "''${BLUE}=== Mail Delivery Test ===""${NC}"
+ echo
+ echo "This will help you test instant mail delivery."
+ echo
+ echo "Steps:"
+ echo "1. Send an email to: vincent@demeester.fr"
+ echo "2. Watch the logs for sync activity"
+ echo "3. Check mu4e for the new mail"
+ echo
+ echo -e "''${YELLOW}Ready to monitor? Press Enter to start watching logs...""${NC}"
+ read -r
+
+ echo
+ echo "Watching for new mail (Ctrl+C to stop)..."
+ echo "Looking for: mbsync, mu index, new mail notifications"
+ echo
+
+ journalctl --user -f \
+ -u imapfilter.service \
+ -u "goimapnotify-*.service" | \
+ grep -i --line-buffered "mbsync\|index\|new mail\|IDLE\|message"
+ '';
+in
+{
+ home.packages = [
+ mail-status
+ mail-logs
+ mail-idle-status
+ mail-test
+ ];
+
+ # Optional: Enable failure notifications via systemd
+ # This will log to journal when services fail
+ systemd.user.services.imapfilter.Service.OnFailure = [ "mail-service-failure@%n.service" ];
+ systemd.user.services."goimapnotify-icloud".Service.OnFailure = [ "mail-service-failure@%n.service" ];
+
+ # Service to handle failures
+ systemd.user.services."mail-service-failure@" = {
+ Unit = {
+ Description = "Mail service failure notification for %i";
+ };
+
+ Service = {
+ Type = "oneshot";
+ # Log the failure
+ ExecStart = "${pkgs.coreutils}/bin/echo 'Mail service %i failed at $(date)' >> %h/.local/share/mail-service-failures.log";
+ # Could add notification here (ntfy, email, etc.)
+ # ExecStart = "${pkgs.ntfy-sh}/bin/ntfy publish --token $(passage show ntfy/token) topic 'Mail service %i failed'";
+ };
+ };
+}
systems/athena/home.nix
@@ -5,6 +5,7 @@
../../home/common/services/goimapnotify.nix
../../home/common/services/imapfilter.nix
../../home/common/services/imapfilter-rules-updater.nix
+ ../../home/common/services/mail-monitor.nix
];
systemd.user.services.syncthing.Install.WantedBy = lib.mkForce [ "multi-user.target" ];
systems/kyushu/home.nix
@@ -12,6 +12,7 @@ in
../../home/common/dev/tektoncd.nix
../../home/common/services/color-scheme-timer.nix
../../home/common/services/goimapnotify.nix
+ ../../home/common/services/mail-monitor.nix
../../home/common/services/redhat.nix
];
nixpkgs.config.allowUnfree = true;