Files
mutt-add-account/mutt-add-account.sh
2026-02-12 08:55:20 +05:30

852 lines
28 KiB
Bash
Executable File

#!/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 <return> display-message
bind index o display-message
# Full headers
macro index h "<enter-command>unset weed<enter><display-message><enter-command>set weed<enter>" "show all headers"
macro pager h "<exit><enter-command>unset weed<enter><display-message><enter-command>set weed<enter>" "show all headers"
# Unmark all marked for deleted and tagged messages
bind index u noop
bind pager u noop
macro index u "<untag-pattern>~A<enter><tag-pattern>~A<enter><tag-prefix><undelete-message><untag-pattern>~A<enter>" "undelete all and untag"
macro pager u "<exit><untag-pattern>~A<enter><tag-pattern>~A<enter><tag-prefix><undelete-message><untag-pattern>~A<enter>" "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 <jon@haeggblad.com>
# 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 <eduardo.barretto@canonical.com>
#
# 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 <abi/4.0>,
include <tunables/global>
profile mbsync /usr/bin/mbsync {
include <abstractions/base>
include <abstractions/nameservice-strict>
include <abstractions/ssl_certs>
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 <local/mbsync>
}
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 "<f$next_fkey>" "$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 <f$next_fkey> '<sync-mailbox><enter-command>source $config_file<enter><change-folder>~/Maildir/${shortname}/INBOX/<enter>'"
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 <email>" 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."