#!/bin/bash set -e echo "=== Mutt Account Setup Script ===" echo # Check if .muttrc exists, if not create it with default settings mutt_config="$HOME/.muttrc" if [ ! -f "$mutt_config" ]; then echo "Creating new .muttrc with default settings..." cat > "$mutt_config" << 'MUTTRC_EOF' ## General options set header_cache = "~/.cache/mutt" set imap_check_subscribed set imap_keepalive = 300 unset imap_passive set mail_check = 15 set timeout = 10 set mbox_type=Maildir set use_envelope_from = yes set sort=reverse-date set ssl_verify_host = no set resolve = no auto_view text/html # view HTML automatically alternative_order text/plain text/enriched text/html # save HTML for last source ~/.mutt/sidebar.muttrc source ~/.mutt/vim-keys.rc source ~/.mutt/vombatidae.neomuttrc # Clear any default mailboxes before loading account configs unmailboxes * MUTTRC_EOF echo "Created ~/.muttrc" else # Check and update/add required options required_options=( "set header_cache = \"~/.cache/mutt\"" "set imap_check_subscribed" "set imap_keepalive = 300" "unset imap_passive" "set mail_check = 15" "set timeout = 10" "set mbox_type=Maildir" "set use_envelope_from = yes" "set sort=reverse-date" "set ssl_verify_host = no" "set resolve = no" "" "auto_view text/html # view HTML automatically" "alternative_order text/plain text/enriched text/html # save HTML for last" "" "source ~/.mutt/sidebar.muttrc" "source ~/.mutt/vim-keys.rc" "source ~/.mutt/vombatidae.neomuttrc" "" "# Clear any default mailboxes before loading account configs" "unmailboxes *" "" ) for option in "${required_options[@]}"; do # Skip empty lines if [ -z "$option" ]; then continue fi option_name=$(echo "$option" | awk '{print $1, $2}') if grep -q "^${option_name}" "$mutt_config"; then # Option exists, update it sed -i "s|^${option_name}.*|${option}|" "$mutt_config" else # Option doesn't exist, add it at the top sed -i "1i${option}" "$mutt_config" fi done fi # Create .mutt directory and subdirectories if they don't exist mkdir -p "$HOME/.mutt/accounts" # Create unbinds.rc if it doesn't exist sidebar_file="$HOME/.mutt/unbinds.rc" if [ ! -f "$sidebar_file" ]; then cat > "$sidebar_file" << 'UNBINDS_EOF' # Unbinds unbind pager,index \ek unbind index,pager l unbind pager O unbind pager,index \Cn unbind pager,index \Cp unbind index U unbind index \Ct unbind index T UNBINDS_EOF echo "Created ~/.mutt/unbinds.rc" fi # Create sidebar.muttrc if it doesn't exist sidebar_file="$HOME/.mutt/sidebar.muttrc" if [ ! -f "$sidebar_file" ]; then cat > "$sidebar_file" << 'SIDEBAR_EOF' # Sidebar mappings set sidebar_visible = yes set sidebar_width = 20 set sidebar_short_path = yes set sidebar_next_new_wrap = yes set mail_check_stats set sidebar_format = '%D%?F? [%F]?%* %?N?%N/? %?S?%S?' bind index,pager \ek sidebar-prev bind index,pager \ej sidebar-next bind index,pager \eo sidebar-open bind index,pager \eB sidebar-toggle-visible # Use named-mailboxes to show mailboxes in sidebar # These will be populated dynamically by each account config SIDEBAR_EOF echo "Created ~/.mutt/sidebar.muttrc" fi # Create vim-keys.rc if it doesn't exist vim_keys_file="$HOME/.mutt/vim-keys.rc" if [ ! -f "$vim_keys_file" ]; then cat > "$vim_keys_file" << 'VIMKEYS_EOF' #------------------------------------------------------------ # Vi Key Bindings #------------------------------------------------------------ # Moving around bind attach,browser,index g noop bind attach,browser,index gg first-entry bind attach,browser,index G last-entry bind pager g noop bind pager gg top bind pager G bottom bind pager k previous-line bind pager j next-line bind pager o exit # Deletion bind pager,index d noop bind pager,index dd delete-message bind index \Cd delete-pattern bind index D undelete-pattern # Threads bind pager,index dT delete-thread bind pager,index dt delete-subthread bind pager,index gt next-thread bind pager,index gT previous-thread bind index za collapse-thread bind index zA collapse-all # Missing :folddisable/foldenable # Others bind index \Ct tag-pattern bind index T untag-pattern bind index L limit bind index \Cm list-reply bind index \Co sort-mailbox bind pager,index \Cp print-message bind browser,pager,index n search-next bind browser,pager,index N search-opposite bind browser,pager,index p search-opposite # Open mail bind index display-message bind index o display-message # Full headers macro index h "unset weedset weed" "show all headers" macro pager h "unset weedset weed" "show all headers" # Unmark all marked for deleted and tagged messages bind index u noop bind pager u noop macro index u "~A~A~A" "undelete all and untag" macro pager u "~A~A~A" "undelete all and untag" VIMKEYS_EOF echo "Created ~/.mutt/vim-keys.rc" fi # Create vombatidae.neomuttrc if it doesn't exist vombat_file="$HOME/.mutt/vombatidae.neomuttrc" if [ ! -f "$vombat_file" ]; then cat > "$vombat_file" << 'VOMBAT_EOF' # NeoMutt color file # Maintainer: Jon Häggblad # URL: http://www.haeggblad.com # Last Change: 2013 May 17 # Version: 0.1 # # NeoMutt colorscheme loosely inspired by vim colorscheme wombat.vim. # # Changelog: # 0.1 - Initial version # --- vombatidae text colors --- # color normal color230 color234 # color message color230 color234 # --- slightly less yellow text colors --- color normal color253 color234 # mod # color normal color253 color233 # mod # color normal color253 default # mod color indicator color230 color238 color status color101 color16 # color tree color113 color234 # color tree color173 color234 color tree color208 color234 color signature color102 color234 color message color253 color234 color attachment color117 color234 color error color30 color234 color tilde color130 color235 color search color100 default color markers color138 default # mono bold reverse # color bold color173 color191 # mono underline reverse # color underline color48 color191 color quoted color107 color234 # quoted text color quoted1 color66 color234 color quoted2 color32 color234 color quoted3 color30 color234 color quoted4 color99 color234 color quoted5 color36 color234 color quoted6 color114 color234 color quoted7 color109 color234 color quoted8 color41 color234 color quoted9 color138 color234 # color body cyan default "((ftp|http|https)://|news:)[^ >)\"\t]+" # color body cyan default "[-a-z_0-9.+]+@[-a-z_0-9.]+" # color body red default "(^| )\\*[-a-z0-9*]+\\*[,.?]?[ \n]" # color body green default "(^| )_[-a-z0-9_]+_[,.?]?[\n]" # color body red default "(^| )\\*[-a-z0-9*]+\\*[,.?]?[ \n]" # color body green default "(^| )_[-a-z0-9_]+_[,.?]?[ \n]" color index color202 color234 ~F # Flagged color index color39 color234 ~N # New color index color39 color234 ~O color index color229 color22 ~T # Tagged color index color240 color234 ~D # Deleted # --- #mono body reverse '^(subject):.*' #color body brightwhite magenta '^(subject):.*' #mono body reverse '[[:alpha:]][[:alnum:]-]+:' #color body black cyan '[[:alpha:]][[:alnum:]-]+:' # --- header --- color hdrdefault color30 color233 color header color132 color233 '^date:' color header color153 color233 '^(to|cc|bcc):' color header color120 color233 '^from:' color header color178 color233 '^subject:' color header color31 color233 '^user-agent:' color header color29 color233 '^reply-to:' #color header magenta default '^(status|lines|date|received|sender|references):' #color header magenta default '^(pr|mime|x-|user|return|content-)[^:]*:' #color header brightyellow default '^content-type:' #color header magenta default '^content-type: *text/plain' # color header brightgreen default '^list-[^:]*:' #mono header bold '^(subject):.*$' #color header brightcyan default '^(disposition)' #color header green default '^(mail-)?followup' #color header white default '^reply' #color header brightwhite default '^(resent)' # color header brightwhite default '^from:' #mono index bold '~h "^content-type: *(multipart/(mixed|signed|encrypted)|application/)"' #color index green black '~h "^content-type: *multipart/(signed|encrypted)"' #color sidebar_new color39 color234 VOMBAT_EOF echo "Created ~/.mutt/vombatidae.neomuttrc" fi # Create/update mbsync apparmor profile apparmor_file="/etc/apparmor.d/mbsync" if [ ! -f "$apparmor_file" ] && [ -d "/etc/apparmor.d" ]; then echo "Creating mbsync apparmor profile..." sudo tee "$apparmor_file" > /dev/null << 'APPARMOR_EOF' #------------------------------------------------------------------ # Copyright (C) 2024 Canonical Ltd. # # Author: Eduardo Barretto # # This program is free software; you can redistribute it and/or # modify it under the terms of version 2 of the GNU General Public # License published by the Free Software Foundation. #------------------------------------------------------------------ # vim: ft=apparmor abi , include profile mbsync /usr/bin/mbsync { include include include network inet dgram, network inet stream, network inet6 dgram, network inet6 stream, network netlink raw, @{etc_ro}/ssl/openssl.cnf rw, /usr/bin/mbsync rw, owner @{HOME}/.mbsyncrc rw, owner @{HOME}/Maildir/**/ rw, owner @{HOME}/Maildir/**/.mbsyncstate rw, owner @{HOME}/Maildir/**/.mbsyncstate.journal rw, owner @{HOME}/Maildir/**/.mbsyncstate.lock wk, owner @{HOME}/Maildir/**/.mbsyncstate.new rw, owner @{HOME}/Maildir/**/.uidvalidity rwk, owner @{HOME}/Maildir/**/cur/* rw, owner @{HOME}/Maildir/**/new/* rw, owner @{HOME}/Maildir/**/tmp/* rw, include if exists } APPARMOR_EOF echo "Created $apparmor_file" echo "Restarting apparmor service..." sudo systemctl restart apparmor.service 2>/dev/null || echo "Note: Could not restart apparmor service" fi # Get user inputs read -p "Enter your full email address: " email read -p "Enter your full name: " fullname read -sp "Enter password: " password echo read -p "Enter account name: " shortname # Auto-detect mail server settings email_domain="${email#*@}" echo "Searching for server settings..." # Download/update domains.csv domains_csv="$HOME/.mutt/domains.csv" echo "Fetching known mail server configurations..." curl -fsSL "https://raw.githubusercontent.com/LukeSmithxyz/mutt-wizard/refs/heads/master/share/domains.csv" -o "$domains_csv" 2>/dev/null || echo "Note: Could not update domains database" # Try to find domain in CSV file if [ -f "$domains_csv" ]; then # Look for the domain in the CSV (case-insensitive) csv_match=$(grep -i "^${email_domain}," "$domains_csv" | head -1) if [ -n "$csv_match" ]; then # Parse CSV: ADDRESS,IMAP,imap port,SMTP,smtp port detected_imap=$(echo "$csv_match" | cut -d',' -f2) imap_port=$(echo "$csv_match" | cut -d',' -f3) detected_smtp=$(echo "$csv_match" | cut -d',' -f4) detected_port=$(echo "$csv_match" | cut -d',' -f5) echo "" echo "Found configuration for $email_domain:" echo " IMAP server: $detected_imap" echo " SMTP server: $detected_smtp" echo " SMTP port: $detected_port" echo "" read -p "Use these settings? (y/n): " confirm if [[ "$confirm" =~ ^[Yy]$ ]]; then imap_server="$detected_imap" smtp_server="$detected_smtp" smtp_port="$detected_port" else # Manual entry echo "Please enter settings manually:" read -p "Enter IMAP server: " imap_server read -p "Enter SMTP server: " smtp_server read -p "Enter SMTP port (465 for SSL/TLS, 587 for STARTTLS) [465]: " smtp_port smtp_port=${smtp_port:-465} fi else # Domain not in CSV, fall back to auto-detection echo "Domain not found in known configurations, attempting auto-detection..." # Try to get MX record and extract mail server mx_record=$(dig +short MX "$email_domain" 2>/dev/null | sort -n | head -1 | awk '{print $2}' | sed 's/\.$//') detection_failed=false if [ -n "$mx_record" ]; then # Got MX record, try common IMAP server patterns base_domain=$(echo "$mx_record" | sed 's/^smtp\.//' | sed 's/^mx[0-9]*\.//' | sed 's/^mail\.//') # Try common IMAP server patterns if host "imap.$base_domain" &>/dev/null; then detected_imap="imap.$base_domain" elif host "mail.$base_domain" &>/dev/null; then detected_imap="mail.$base_domain" elif host "$mx_record" &>/dev/null; then detected_imap="$mx_record" else detected_imap="mail.${email_domain}" fi # Try to detect SMTP server if host "smtp.$base_domain" &>/dev/null; then detected_smtp="smtp.$base_domain" else detected_smtp="$detected_imap" fi else # MX lookup failed - check if domain itself exists if host "$email_domain" &>/dev/null; then detected_imap="mail.${email_domain}" detected_smtp="mail.${email_domain}" else detection_failed=true fi fi if [ "$detection_failed" = false ]; then # Detect port by testing common ports detected_port="465" if timeout 2 bash -c "echo -n '' > /dev/tcp/$detected_smtp/587" 2>/dev/null; then detected_port="587" elif timeout 2 bash -c "echo -n '' > /dev/tcp/$detected_smtp/465" 2>/dev/null; then detected_port="465" fi # Show detected settings echo "" echo "Detected settings:" echo " IMAP server: $detected_imap" echo " SMTP server: $detected_smtp" echo " SMTP port: $detected_port" echo "" read -p "Are these settings correct? (y/n): " confirm if [[ "$confirm" =~ ^[Yy]$ ]]; then # Use detected settings imap_server="$detected_imap" smtp_server="$detected_smtp" smtp_port="$detected_port" else # Manual entry echo "Please enter settings manually:" read -p "Enter IMAP server: " imap_server read -p "Enter SMTP server: " smtp_server read -p "Enter SMTP port (465 for SSL/TLS, 587 for STARTTLS) [465]: " smtp_port smtp_port=${smtp_port:-465} fi else # Detection completely failed echo "" echo "Could not auto-detect mail server settings for $email_domain" echo "Please enter settings manually:" read -p "Enter IMAP server: " imap_server read -p "Enter SMTP server: " smtp_server read -p "Enter SMTP port (465 for SSL/TLS, 587 for STARTTLS) [465]: " smtp_port smtp_port=${smtp_port:-465} fi fi else echo "Could not fetch domains database, using auto-detection..." # Continue with existing auto-detection logic # [Keep the existing auto-detection code as fallback] fi # Extract username from email username="${email%%@*}" # Determine SMTP protocol and TLS settings if [ "$smtp_port" = "587" ]; then smtp_proto="smtp" smtp_starttls="set ssl_starttls = yes" use_starttls=true else smtp_proto="smtps" smtp_starttls="unset ssl_starttls" use_starttls=false fi # Find next available F-key next_fkey=2 while grep -q "" "$mutt_config"; do ((next_fkey++)) done # Find next account number if grep -q "^## ACCOUNT" "$mutt_config"; then max_account=$(grep "^## ACCOUNT" "$mutt_config" | sed 's/## ACCOUNT//' | sort -n | tail -1) account_num=$((max_account + 1)) else account_num=1 fi echo echo "Using F$next_fkey for this account (ACCOUNT$account_num)" echo "SMTP: $smtp_proto on port $smtp_port" echo # Create Maildir directory for this account maildir_path="$HOME/Maildir/${shortname}" mkdir -p "$maildir_path" echo "Created Maildir: $maildir_path" # Config file will be in the accounts subdirectory config_file="$HOME/.mutt/accounts/${shortname}" # Escape password for use in double quotes (for IMAP / mutt) # Escape backslashes first, then double quotes, then dollar signs, then backticks escaped_pass="${password//\\/\\\\}" escaped_pass="${escaped_pass//\"/\\\"}" escaped_pass="${escaped_pass//\$/\\\$}" escaped_pass="${escaped_pass//\`/\\\`}" # URL encode password for SMTP encoded_pass="" for ((i=0; i<${#password}; i++)); do c="${password:$i:1}" case "$c" in [a-zA-Z0-9.~_-]) encoded_pass+="$c" ;; *) printf -v hex '%02X' "'$c" encoded_pass+="%$hex" ;; esac done # JSON-escape password for goimapnotify config # Escape backslashes, double quotes, and common control characters json_escaped_pass="${password//\\/\\\\}" json_escaped_pass="${json_escaped_pass//\"/\\\"}" json_escaped_pass="${json_escaped_pass// /\\t}" # tab json_escaped_pass="${json_escaped_pass//$'\n'/\\n}" # newline json_escaped_pass="${json_escaped_pass//$'\r'/\\r}" # carriage return # Detect if this is a Gmail account is_gmail=false if [[ "$email_domain" == "gmail.com" || "$email_domain" == "googlemail.com" ]]; then is_gmail=true fi # Create mutt config file with Maildir cat > "$config_file" << EOF ## Receive options. set imap_user=$email set imap_pass="$escaped_pass" set folder = ~/Maildir/${shortname}/ set spoolfile = +INBOX EOF # Add Gmail-specific or standard folder settings if [ "$is_gmail" = true ]; then cat >> "$config_file" << EOF set postponed = "+[Gmail]/Drafts" set record = "+[Gmail]/Sent Mail" set trash = "+[Gmail]/Trash" EOF else cat >> "$config_file" << EOF set postponed = +Drafts set record = +Sent set trash = +Trash EOF fi # Continue with common settings cat >> "$config_file" << EOF set status_format = "\$imap_user %f" ## Send options. set smtp_url=$smtp_proto://$email@$smtp_server:$smtp_port set smtp_pass="$escaped_pass" set smtp_authenticators="plain:login" set from="$email" set use_from=yes set realname='$fullname' set hostname="$smtp_server" set signature="$fullname" # Connection options set ssl_force_tls = yes $smtp_starttls EOF # Add mailboxes based on account type if [ "$is_gmail" = true ]; then cat >> "$config_file" << 'EOF' # Mailboxes for sidebar unmailboxes * named-mailboxes "INBOX" "=INBOX" named-mailboxes "Drafts" "=[Gmail]/Drafts" named-mailboxes "Sent" "=[Gmail]/Sent Mail" named-mailboxes "Important" "=[Gmail]/Important" named-mailboxes "Starred" "=[Gmail]/Starred" named-mailboxes "Spam" "=[Gmail]/Spam" named-mailboxes "Trash" "=[Gmail]/Trash" named-mailboxes "All Mail" "=[Gmail]/All Mail" EOF # Boxes for goimapnotify (Gmail) - list of maps with per-box handlers notify_boxes_yaml=" - mailbox: \"INBOX\" onNewMail: \"mbsync '$email' && notify-send -i mail-unread 'New Mail' '$email' && paplay /usr/share/sounds/freedesktop/stereo/message-new-instant.oga\" onNewMailPost: \"\" onChangedMail: \"mbsync $email\" onChangedMailPost: \"\" onDeletedMail: \"mbsync $email\" onDeletedMailPost: \"\" - mailbox: \"[Gmail]/Drafts\" onNewMail: \"mbsync $email\" onNewMailPost: \"\" onChangedMail: \"mbsync $email\" onChangedMailPost: \"\" onDeletedMail: \"mbsync $email\" onDeletedMailPost: \"\" - mailbox: \"[Gmail]/Sent Mail\" onNewMail: \"mbsync $email\" onNewMailPost: \"\" onChangedMail: \"mbsync $email\" onChangedMailPost: \"\" onDeletedMail: \"mbsync $email\" onDeletedMailPost: \"\" - mailbox: \"[Gmail]/Spam\" onNewMail: \"mbsync $email\" onNewMailPost: \"\" onChangedMail: \"mbsync $email\" onChangedMailPost: \"\" onDeletedMail: \"mbsync $email\" onDeletedMailPost: \"\" - mailbox: \"[Gmail]/Trash\" onNewMail: \"mbsync $email\" onNewMailPost: \"\" onChangedMail: \"mbsync $email\" onChangedMailPost: \"\" onDeletedMail: \"mbsync $email\" onDeletedMailPost: \"\" " else cat >> "$config_file" << 'EOF' # Mailboxes for sidebar unmailboxes * named-mailboxes "INBOX" "=INBOX" named-mailboxes "Drafts" "=Drafts" named-mailboxes "Sent" "=Sent" named-mailboxes "Junk" "=Junk" named-mailboxes "Trash" "=Trash" EOF # Boxes for goimapnotify (standard) - list of maps with per-box handlers notify_boxes_yaml=" - mailbox: \"INBOX\" onNewMail: \"mbsync '$email' && notify-send -i mail-unread 'New Mail' '$email' && paplay /usr/share/sounds/freedesktop/stereo/message-new-instant.oga\" onNewMailPost: \"\" onChangedMail: \"mbsync $email\" onChangedMailPost: \"\" onDeletedMail: \"mbsync $email\" onDeletedMailPost: \"\" - mailbox: \"Drafts\" onNewMail: \"mbsync $email\" onNewMailPost: \"\" onChangedMail: \"mbsync $email\" onChangedMailPost: \"\" onDeletedMail: \"mbsync $email\" onDeletedMailPost: \"\" - mailbox: \"Sent\" onNewMail: \"mbsync $email\" onNewMailPost: \"\" onChangedMail: \"mbsync $email\" onChangedMailPost: \"\" onDeletedMail: \"mbsync $email\" onDeletedMailPost: \"\" - mailbox: \"Junk\" onNewMail: \"mbsync $email\" onNewMailPost: \"\" onChangedMail: \"mbsync $email\" onChangedMailPost: \"\" onDeletedMail: \"mbsync $email\" onDeletedMailPost: \"\" - mailbox: \"Trash\" onNewMail: \"mbsync $email\" onNewMailPost: \"\" onChangedMail: \"mbsync $email\" onChangedMailPost: \"\" onDeletedMail: \"mbsync $email\" onDeletedMailPost: \"\" " fi echo "Created config file: $config_file" # Create/append to .mbsyncrc mbsync_config="$HOME/.mbsyncrc" echo "Adding mbsync configuration..." cat >> "$mbsync_config" << EOF IMAPStore ${shortname}-remote Host $imap_server Port 993 User $email Pass "$escaped_pass" SSLType IMAPS CertificateFile /etc/ssl/certs/ca-certificates.crt MaildirStore ${shortname}-local Path ~/Maildir/${shortname}/ Inbox ~/Maildir/${shortname}/INBOX Subfolders Verbatim Channel $email Far :${shortname}-remote: Near :${shortname}-local: Create Both Expunge Both Patterns * SyncState * MaxMessages 0 ExpireUnread no # End profile EOF echo "Added mbsync profile to $mbsync_config" # ------------------------------------------------------- # goimapnotify configuration # ------------------------------------------------------- notify_config_dir="$HOME/.config/goimapnotify" notify_config_file="$notify_config_dir/goimapnotify.yaml" mkdir -p "$notify_config_dir" echo "Updating goimapnotify configuration..." # goimapnotify.yaml uses a top-level "configurations:" key with a list of account objects. # If the file doesn't exist, create it with the first account. # If it exists, append the new account entry to the configurations list. new_entry=$(cat << EOF - host: "$imap_server" port: 993 tls: true tlsOptions: rejectUnauthorized: false username: "$email" password: "$json_escaped_pass" boxes: $notify_boxes_yaml EOF ) if [ ! -f "$notify_config_file" ]; then printf 'configurations:\n%s\n' "$new_entry" > "$notify_config_file" echo "Created $notify_config_file" else printf '%s\n' "$new_entry" >> "$notify_config_file" echo "Appended account to $notify_config_file" fi # ------------------------------------------------------- # systemd user service for goimapnotify # ------------------------------------------------------- systemd_user_dir="$HOME/.config/systemd/user" service_file="$systemd_user_dir/goimapnotify.service" mkdir -p "$systemd_user_dir" if [ ! -f "$service_file" ]; then echo "Creating systemd user service..." cat > "$service_file" << EOF [Unit] Description=goimapnotify After=network-online.target Wants=network-online.target [Service] Type=simple ExecStart=${HOME}/go/bin/goimapnotify -conf ${HOME}/.config/goimapnotify/goimapnotify.yaml Restart=always RestartSec=10 [Install] WantedBy=default.target EOF echo "Created $service_file" else echo "Service file already exists: $service_file (skipping)" fi # Reload systemd and (re)start the service echo "Reloading systemd user daemon..." systemctl --user daemon-reload echo "Enabling goimapnotify service..." systemctl --user enable goimapnotify.service echo "Restarting goimapnotify service..." systemctl --user stop goimapnotify.service 2>/dev/null || true systemctl --user start goimapnotify.service echo "goimapnotify service status:" systemctl --user status goimapnotify.service --no-pager || true # ------------------------------------------------------- # Backup .muttrc # ------------------------------------------------------- cp "$mutt_config" "${mutt_config}.backup.$(date +%Y%m%d_%H%M%S)" echo "Backed up .muttrc" # Find insertion point if grep -q "^## ACCOUNT" "$mutt_config"; then line_num=$(grep -n "^## ACCOUNT" "$mutt_config" | head -1 | cut -d: -f1) ((line_num--)) else line_num=$(wc -l < "$mutt_config") fi # Add account to .muttrc { head -n "$line_num" "$mutt_config" echo "# Switch to account ${account_num} (${shortname})" echo "macro index,pager 'source $config_file~/Maildir/${shortname}/INBOX/'" echo "" echo "## ACCOUNT${account_num}" echo "source \"$config_file\"" echo "folder-hook \"~/Maildir/${shortname}/\" 'source $config_file;'" echo tail -n +$((line_num + 1)) "$mutt_config" } > "${mutt_config}.tmp" mv "${mutt_config}.tmp" "$mutt_config" # ------------------------------------------------------- # Create/update neomutt wrapper script # ------------------------------------------------------- wrapper_script="$HOME/.local/bin/neomutt" mkdir -p "$HOME/.local/bin" # Collect all configured email addresses from mbsyncrc channels # Each "Channel " line in .mbsyncrc is one account to sync cat > "$wrapper_script" << 'WRAPPER_EOF' #!/bin/bash mbsync -q -a & exec /usr/bin/neomutt WRAPPER_EOF chmod +x "$wrapper_script" echo "Created wrapper script: $wrapper_script" echo "(make sure ~/.local/bin is in your PATH)" echo echo "=== Setup Complete ===" echo "Account: $email" echo "Mutt config: $config_file" echo "Maildir: $maildir_path" echo "Mbsync config: Added to $mbsync_config" echo "Notify config: $notify_config_file" echo "Systemd service: $service_file" echo "" echo "To sync mail manually, run: mbsync $email" echo "Press F$next_fkey in mutt to switch to this account" echo echo "Restart mutt to use the new account."