259 lines
8.1 KiB
Markdown
259 lines
8.1 KiB
Markdown
|
|
# 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
|
||
|
|
|
||
|
|
```bash
|
||
|
|
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:
|
||
|
|
|
||
|
|
```json
|
||
|
|
[{"type":"success","msg":["mailbox_added","no-reply@echo6.co"]}]
|
||
|
|
```
|
||
|
|
|
||
|
|
### Option B: Via Mailcow Admin UI
|
||
|
|
|
||
|
|
1. Open https://mail.echo6.co (log in as admin)
|
||
|
|
2. Navigate to **Email → Mailboxes → Add mailbox**
|
||
|
|
3. Fill in local part, domain, display name, password, quota
|
||
|
|
4. Click **Add**
|
||
|
|
|
||
|
|
### Access Flags
|
||
|
|
|
||
|
|
For service accounts (send-only), disable unnecessary access after creation:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
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:
|
||
|
|
|
||
|
|
1. Postfix receives the SMTP AUTH credentials
|
||
|
|
2. Postfix hands them to Dovecot for verification
|
||
|
|
3. Dovecot's Lua passdb sees `authsource=generic-oidc`
|
||
|
|
4. Dovecot tries to authenticate via Authentik SSO
|
||
|
|
5. The service account doesn't exist in Authentik → **auth fails silently**
|
||
|
|
6. 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:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
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:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
# 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:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
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:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
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
|
||
|
|
|
||
|
|
```bash
|
||
|
|
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:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
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:
|
||
|
|
|
||
|
|
```bash
|
||
|
|
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*
|