Files
docs-alpha.jayfield.org/MAIL-ACCOUNTS.md
T
jensandClaude Sonnet 5 92d871f2da Initial docs: alpha.jayfield.org server documentation
Records the host's service inventory, setup runbook, mail account list,
sync plan, package diff vs. clean install, and hardening TODOs, including
today's SSH hardening (key-only, no root login) and the fail2ban sshd
findtime fix for a low-and-slow brute-force evasion pattern.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RdTyvEJkfNLDVAWt8WQ6X9
2026-07-19 23:09:27 +02:00

123 lines
5.5 KiB
Markdown

# alpha.jayfield.org — Adding Email Accounts (How-To)
Accounts, aliases, and domains for the mail stack (Postfix + Dovecot) all
live in one place: the `vmail` MySQL database on this host. There's no
admin UI — everything below is a `mysql` insert plus one hash-generation
command. See `SETUP.md` §3 for how this schema was built in the first
place; this doc is just the day-to-day "add a mailbox" recipe.
**No service restart is ever needed for account changes.** Postfix and
Dovecot query MySQL live on every delivery/login (`auth_cache_size` is
unset/disabled on this host — verified in `/etc/dovecot/conf.d/10-auth.conf`)
so a new row is usable immediately.
## 1. Prerequisite: the domain must already exist
```bash
sudo mysql vmail -e "SELECT * FROM domains;"
```
Currently just `jayfield.org`. If you ever need a second domain, insert it
here first (`INSERT INTO vmail.domains (domain) VALUES ('newdomain.tld');`)
— but note that's the *easy* part; a real second domain also needs its own
DNS zone/MX/SPF/DMARC records and DKIM selector (see `SETUP.md` §2/§3), a
TLS cert covering it, and its own `mynetworks`/`inet_interfaces`
consideration. Out of scope for just adding a mailbox — this doc assumes
`jayfield.org`.
## 2. Generate the password hash
Never put a plaintext password in the `accounts` table — hash it first:
```bash
sudo doveadm pw -s SHA512-CRYPT
```
(You'll be prompted twice, interactively — don't pass the password as a
CLI argument, it'd land in shell history.) Copy the full
`{SHA512-CRYPT}$6$...` output; that's the exact string that goes in the
`password` column.
You may see `Error: net_connect_unix(/run/dovecot/stats-writer) failed:
Permission denied` printed before the hash — that's `doveadm` trying to
report stats, unrelated to the hash it prints right after; harmless, not a
sign the hash is wrong.
## 3. Insert the account
```bash
sudo mysql vmail -e "INSERT INTO accounts (username, domain, password, quota, enabled, sendonly) VALUES ('newuser', 'jayfield.org', '{SHA512-CRYPT}\$6\$...', 2048, 1, 0);"
```
- `quota` is in **MB** (existing accounts use `2048` = 2GB — match that
unless there's a reason not to).
- `enabled = 1` — required for the account to authenticate or receive mail
at all. Setting it to `0` disables the account without deleting it (see
§6).
- `sendonly = 0` — normal mailbox: can send *and* receive. Set to `1` only
for a send-only address that should never accept incoming mail (see §5).
That's it — no mailbox directory to create by hand. Dovecot auto-creates
`/var/vmail/mailboxes/jayfield.org/<user>/mail/` (owned `vmail:vmail`,
`700`) the first time the account logs in or receives mail.
## 4. Client configuration (no webmail — this stack is IMAP/SMTP only)
| Setting | Value |
|---|---|
| IMAP (recommended) | `mail.jayfield.org` : `993`, implicit TLS |
| IMAP (STARTTLS) | `mail.jayfield.org` : `143` |
| SMTP submission | `mail.jayfield.org` : `587`, STARTTLS + SASL (PLAIN) auth required |
| Username | `<user>@jayfield.org` (full address, not just the local part) |
| Password | the plaintext password you hashed in §2 |
| Port 25 | **not for clients** — server-to-server only, no SASL, no relay (`reject_unauth_destination`) |
`disable_plaintext_auth = yes` is set — clients must actually negotiate TLS
first; a client configured for plaintext IMAP/SMTP on the wrong port will
just fail to auth, not silently send credentials in the clear.
## 5. Send-only accounts (`sendonly = 1`)
Postfix's `recipient-access.cf` query rejects any inbound mail to a
`sendonly=1` address at `RCPT TO` time (`450`/`550` before it's even
accepted), while the account can still authenticate via SASL on `587` and
send outbound. Use this for something like a monitoring/alerting sender
address that should never actually receive replies.
## 6. Aliases (forward one address to another mailbox)
Aliases don't need their own mailbox or password — they're a pure
redirect, resolved at `RCPT TO` time via `aliases.cf`:
```bash
sudo mysql vmail -e "INSERT INTO aliases (source_username, source_domain, destination_username, destination_domain, enabled) VALUES ('sales', 'jayfield.org', 'jens', 'jayfield.org', 1);"
```
This host already has `postmaster`/`hostmaster`/`webmaster`/`wlan`
`jens` as standing aliases (RFC-required roles + a house one) — check
`SELECT * FROM aliases;` before adding a new one to avoid duplicates.
## 7. Disabling / removing an account
Prefer disabling over deleting — it's reversible and doesn't touch the
Maildir:
```bash
sudo mysql vmail -e "UPDATE accounts SET enabled = 0 WHERE username = 'olduser' AND domain = 'jayfield.org';"
```
This blocks both authentication and inbound delivery immediately (both
`accounts.cf` and `recipient-access.cf` filter on `enabled = true`). The
actual mail data stays on disk at
`/var/vmail/mailboxes/jayfield.org/olduser/` until you decide to remove it
by hand — nothing auto-deletes it.
## 8. Verify a new account end-to-end
Don't trust the INSERT alone — confirm both directions actually work,
same discipline as `SETUP.md` §7:
```bash
# IMAP auth works
doveadm auth test newuser@jayfield.org
# Watch a real inbound + outbound test the same way §7 of SETUP.md describes:
# send TO newuser@jayfield.org from an external provider, confirm in
# /var/log/mail.log:
# dovecot: lmtp(newuser@jayfield.org)<...>: sieve: msgid=<...>: stored mail into mailbox 'INBOX'
# then send FROM the new account via a real mail client on 587, confirm:
# postfix/submission/smtpd[...]: sasl_method=PLAIN, sasl_username=newuser@jayfield.org
```