- Documents recent infrastructure cleanup (8 CTs destroyed, 35 DNS records removed, Headscale cleanup) - Adds 24 new runbooks covering Authentik, PeerTube, Meshtastic, RECON, Proxmox, Mailcow, Internet Archive, GPU routing - Adds project documentation for headscale, vaultwarden, peertube, matrix, mmud, advbbs, arr stack - Updates services.md, environment.md, caddy.md, authentik.md to match live infrastructure - Removes 4 deprecated runbook duplicates (canonical versions live in projects/) - Adds .gitignore for binary archives and editor temp files Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
8.1 KiB
Mailcow: Create Mailbox
Create a new mailbox in Mailcow on the Contabo VPS. Covers both interactive (UI) and API-driven creation, with the critical authsource fix for service accounts.
When to Use This
Any time a new mailbox is created in Mailcow, but especially for service/system accounts that authenticate via SMTP to send mail programmatically (e.g., no-reply@echo6.co used by Authentik, recon@echo6.co used by the RECON pipeline). These accounts don't log in through the Mailcow web UI or SSO — they pass credentials directly to Postfix over SMTP, so they must use local password authentication.
Prerequisites
- SSH access to Contabo (
ssh root@100.64.0.1) - Mailcow API key (stored in Mailcow admin UI under System → Configuration → API)
- Mailcow DB password: source from
/opt/mailcow-dockerized/.env(DBPASS)
Inputs
LOCAL_PART=no-reply # Left side of the @ sign
DOMAIN=echo6.co # Must already exist in Mailcow
DISPLAY_NAME="Echo6 No Reply" # Friendly name
PASSWORD=<strong-password> # Generate with: openssl rand -base64 24 | tr -d '/+='
QUOTA_MB=256 # Mailbox quota in MB
IS_SERVICE_ACCOUNT=true # true = SMTP sender, false = regular user
MAILCOW_API_KEY=<api-key> # From Mailcow admin UI
Step 1: Create the Mailbox
Option A: Via Mailcow API
ssh root@100.64.0.1
curl -sk -X POST "https://127.0.0.1:8443/api/v1/add/mailbox" \
-H "X-API-Key: ${MAILCOW_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"local_part": "'${LOCAL_PART}'",
"domain": "'${DOMAIN}'",
"name": "'${DISPLAY_NAME}'",
"password": "'${PASSWORD}'",
"password2": "'${PASSWORD}'",
"quota": '${QUOTA_MB}',
"active": 1,
"force_pw_update": 0,
"tls_enforce_in": 1,
"tls_enforce_out": 1
}'
Expected response:
[{"type":"success","msg":["mailbox_added","no-reply@echo6.co"]}]
Option B: Via Mailcow Admin UI
- Open https://mail.echo6.co (log in as admin)
- Navigate to Email → Mailboxes → Add mailbox
- Fill in local part, domain, display name, password, quota
- Click Add
Access Flags
For service accounts (send-only), disable unnecessary access after creation:
curl -sk -X POST "https://127.0.0.1:8443/api/v1/edit/mailbox" \
-H "X-API-Key: ${MAILCOW_API_KEY}" \
-H "Content-Type: application/json" \
-d '{
"items": ["'${LOCAL_PART}@${DOMAIN}'"],
"attr": {
"sogo_access": "0",
"imap_access": "0",
"pop3_access": "0",
"smtp_access": "1"
}
}'
Regular user accounts can leave all access flags at their defaults (all enabled).
Step 2: Fix authsource (CRITICAL for Service Accounts)
The Problem
Mailcow domains configured with OIDC authentication (like echo6.co with Authentik SSO) set authsource=generic-oidc on every new mailbox by default. This tells Dovecot to authenticate the account through the OIDC provider instead of the local password hash.
For service accounts that log in via SMTP with a username and password, this means:
- Postfix receives the SMTP AUTH credentials
- Postfix hands them to Dovecot for verification
- Dovecot's Lua passdb sees
authsource=generic-oidc - Dovecot tries to authenticate via Authentik SSO
- The service account doesn't exist in Authentik → auth fails silently
- SMTP returns
535 5.7.8 Error: authentication failed: (reason unavailable)
The failure message gives no indication that OIDC is the cause. The password is correct, the mailbox exists, and the Mailcow API reports success on password changes — but SMTP auth never works.
The Fix
Change the authsource from generic-oidc to mailcow in the database:
ssh root@100.64.0.1
# Source the DB password
DBPASS=$(grep ^DBPASS /opt/mailcow-dockerized/.env | cut -d= -f2)
# Check current authsource
docker exec mailcowdockerized-mysql-mailcow-1 \
mysql -u mailcow -p${DBPASS} mailcow -N \
-e "SELECT username, authsource FROM mailbox WHERE username='${LOCAL_PART}@${DOMAIN}'"
# Fix: set authsource to local password auth
docker exec mailcowdockerized-mysql-mailcow-1 \
mysql -u mailcow -p${DBPASS} mailcow \
-e "UPDATE mailbox SET authsource='mailcow' WHERE username='${LOCAL_PART}@${DOMAIN}'"
When to apply:
| Account Type | authsource | Reason |
|---|---|---|
| Service account (SMTP sender) | mailcow |
Authenticates with local password via SMTP |
| Regular user (SSO login) | generic-oidc |
Authenticates through Authentik web SSO |
| Regular user (IMAP/SMTP client) | mailcow |
Authenticates with local password from mail client |
Rule of thumb: if the account will ever authenticate with a username + password (SMTP, IMAP, POP3), set authsource=mailcow. Only leave generic-oidc for accounts that exclusively use SSO web login.
Step 3: Verify SMTP Authentication
Wait a few seconds after the authsource fix, then test:
# From the Contabo host
python3 -c "
import smtplib
s = smtplib.SMTP('mail.echo6.co', 587, timeout=10)
s.starttls()
s.login('${LOCAL_PART}@${DOMAIN}', '${PASSWORD}')
print('SMTP auth: OK')
s.quit()
"
If SMTP auth is being used from inside a Docker container (like Authentik), also test from there:
docker exec authentik-worker python3 -c "
import smtplib
s = smtplib.SMTP('mail.echo6.co', 587, timeout=10)
s.starttls()
s.login('${LOCAL_PART}@${DOMAIN}', '${PASSWORD}')
print('Container SMTP auth: OK')
s.quit()
"
Both should print OK. If either fails with 535 5.7.8 Error: authentication failed, re-check the authsource (Step 2).
Step 4: Store Credentials
Add the new mailbox credentials to /home/zvx/projects/.ref/credentials:
# Mailcow: ${LOCAL_PART}@${DOMAIN}
MAILCOW_${LOCAL_PART^^}_USER=${LOCAL_PART}@${DOMAIN}
MAILCOW_${LOCAL_PART^^}_PASS=${PASSWORD}
Troubleshooting
SMTP auth fails immediately after mailbox creation
Cause: authsource=generic-oidc (see Step 2).
SMTP auth fails after it was previously working
Cause 1: Mailcow may have reset the authsource during a stack restart or update. Re-apply Step 2.
Cause 2: The password hash may have been corrupted by a failed API password reset. Mailcow's password edit API (/api/v1/edit/mailbox) sometimes reports success but doesn't actually update the hash. Workaround: Delete the mailbox and recreate it from scratch (Step 1), then re-apply the authsource fix (Step 2). Do not attempt to reset the password via API.
"Unknown user" in Dovecot logs
Check that the mailbox exists and is active:
curl -sk "https://127.0.0.1:8443/api/v1/get/mailbox/${LOCAL_PART}@${DOMAIN}" \
-H "X-API-Key: ${MAILCOW_API_KEY}" | python3 -m json.tool
Checking Dovecot auth logs
docker logs mailcowdockerized-dovecot-mailcow-1 --since 5m 2>&1 | grep -i auth
Checking netfilter/fail2ban
Too many failed SMTP login attempts can trigger Mailcow's brute-force protection:
docker logs mailcowdockerized-netfilter-mailcow-1 --since 10m 2>&1 | grep -i ban
If the Contabo IP (5.189.158.149) is banned, restart the netfilter container:
cd /opt/mailcow-dockerized && docker compose restart netfilter-mailcow
Checklist
[ ] Mailbox created (API or UI)
[ ] Access flags set appropriately for account type
[ ] authsource checked — set to 'mailcow' if service account
[ ] SMTP auth verified from host
[ ] SMTP auth verified from consuming container (if applicable)
[ ] Credentials stored in /home/zvx/projects/.ref/credentials
Reference: Current Service Accounts
| Mailbox | Used By | authsource | Purpose |
|---|---|---|---|
| no-reply@echo6.co | Authentik | mailcow | SSO invitation emails, notifications |
| cipher@echo6.co | CIPHER | generic-oidc | Daily intelligence briefs |
| recon@echo6.co | RECON | generic-oidc | Pipeline notifications |
| fulcrum@echo6.co | Fulcrum | generic-oidc | Hub notifications |
Note: cipher, recon, and fulcrum currently use generic-oidc. If any of these need to send mail via SMTP (not through the SSO web UI), their authsource must be changed to mailcow per Step 2.
Created: 2026-02-16