fix(nextcloud): dedupe + update mail accounts

This commit is contained in:
Brad Stein 2026-01-03 06:52:53 -03:00
parent 9d8c113850
commit 51f94194be

View File

@ -11,19 +11,33 @@ if ! command -v jq >/dev/null 2>&1; then
apt-get update && apt-get install -y jq curl >/dev/null
fi
account_exists() {
list_mail_accounts() {
local user_id="${1}"
local email="${2}"
local export_out
# Nextcloud Mail does not provide a list command; export is safe (does not print passwords).
local export
if ! export=$(/usr/sbin/runuser -u www-data -- php occ mail:account:export "${user_id}" 2>/dev/null); then
if ! export_out=$(/usr/sbin/runuser -u www-data -- php occ mail:account:export "${user_id}" 2>/dev/null); then
echo "WARN: unable to export mail accounts for ${user_id}; skipping sync for safety" >&2
return 0
return 1
fi
# Output formatting varies by Nextcloud/Mail versions and locale; match by email address.
grep -Fq -- "${email}" <<<"${export}"
# The export output is human-readable and includes blocks like:
# Account 10:
# - E-Mail: user@example.com
# Extract "account-id <tab> email" pairs.
awk '
/^Account[[:space:]]+[0-9]+:/ {
id=$2;
sub(/:$/, "", id);
next;
}
id != "" && /@/ {
if (match($0, /[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/, m)) {
printf("%s\t%s\n", id, m[0]);
id="";
}
}
' <<<"${export_out}" | sort -u
}
token=$(
@ -59,13 +73,60 @@ echo "${users}" | jq -c '.[]' | while read -r user; do
fi
[[ -z "${mailu_email}" || -z "${app_pw}" ]] && continue
if account_exists "${username}" "${mailu_email}"; then
echo "Skipping ${mailu_email}, already exists"
if ! accounts=$(list_mail_accounts "${username}"); then
continue
fi
echo "Syncing ${mailu_email}"
/usr/sbin/runuser -u www-data -- php occ mail:account:create \
"${username}" "${username}" "${mailu_email}" \
mail.bstein.dev 993 ssl "${mailu_email}" "${app_pw}" \
mail.bstein.dev 587 tls "${mailu_email}" "${app_pw}" || true
# Manage only internal Mailu-domain accounts; leave any external accounts untouched.
mailu_accounts=$(awk -v d="${MAILU_DOMAIN,,}" 'tolower($2) ~ ("@" d "$") {print}' <<<"${accounts}" || true)
desired_email="${mailu_email}"
primary_id=""
primary_email=""
if [[ -n "${mailu_accounts}" ]]; then
while IFS=$'\t' read -r account_id account_email; do
if [[ -z "${primary_id}" ]]; then
primary_id="${account_id}"
primary_email="${account_email}"
fi
if [[ "${account_email,,}" == "${desired_email,,}" ]]; then
primary_id="${account_id}"
primary_email="${account_email}"
break
fi
done <<<"${mailu_accounts}"
echo "Updating ${username} mail account ${primary_id} (${primary_email})"
/usr/sbin/runuser -u www-data -- php occ mail:account:update -q "${primary_id}" \
--name "${username}" \
--email "${desired_email}" \
--imap-host mail.bstein.dev \
--imap-port 993 \
--imap-ssl-mode ssl \
--imap-user "${desired_email}" \
--imap-password "${app_pw}" \
--smtp-host mail.bstein.dev \
--smtp-port 587 \
--smtp-ssl-mode tls \
--smtp-user "${desired_email}" \
--smtp-password "${app_pw}" \
--auth-method password >/dev/null 2>&1 || true
# Remove any extra Mailu-domain accounts for this user to prevent duplicates.
while IFS=$'\t' read -r account_id account_email; do
if [[ "${account_id}" == "${primary_id}" ]]; then
continue
fi
echo "Deleting extra mail account ${account_id} (${account_email})"
/usr/sbin/runuser -u www-data -- php occ mail:account:delete -q "${account_id}" >/dev/null 2>&1 || true
done <<<"${mailu_accounts}"
else
echo "Creating mail account for ${username} (${desired_email})"
/usr/sbin/runuser -u www-data -- php occ mail:account:create -q \
"${username}" "${username}" "${desired_email}" \
mail.bstein.dev 993 ssl "${desired_email}" "${app_pw}" \
mail.bstein.dev 587 tls "${desired_email}" "${app_pw}" password >/dev/null 2>&1 || true
fi
done