# 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//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 | `@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 ```