---
title: "Mailcow: Create Mailbox"
type: runbook
tags:
  - auth
aliases: []
related:
  - [[authentik]]
  - [[authentik-oidc-application]]
  - [[caddy]]
  - [[authentik-create-invitation]]
  - [[proxmox-onboard-node]]
updated: 2026-06-18
---
# 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*
