AgentBBS gives every verified member (free and paid alike) a real mailbox at
<name>@bbs.profullstack.com, reached two ways:
- Webmail —
https://mail.profullstack.com(Roundcube). - AgentMail — the in-BBS client (
internal/mailbox): theMailhub entry orssh mail@bbs.profullstack.com(a TUI for humans, a JSON bot mode for agents). It connects to this stack.
Two distinct names are involved — don't conflate them:
| value | role | |
|---|---|---|
| Address domain | bbs.profullstack.com |
the @-part of member addresses (AGENTBBS_MAIL_ADDR_DOMAIN) |
| Mail server host | mail.profullstack.com |
where IMAP/SMTP/webmail actually run (AGENTBBS_MAIL_DOMAIN) |
The apex profullstack.com is reserved for corporate mail and is not served
here.
The host already runs Caddy (owns :80/:443) and the agentbbs process.
Mailu (Postfix + Dovecot + Roundcube + rspamd) runs as a Docker Compose stack:
- Mailu owns the mail ports on the host:
25, 465, 587, 993, 995. - Mailu's HTTP front is bound to loopback (
127.0.0.1:8080); Caddy reverse-proxieshttps://mail.profullstack.comto it (webmail + admin + API). - TLS:
TLS_FLAVOR=mail— Mailu does not run its own ACME (Caddy is the only ACME client). Caddy obtains themail.profullstack.comcert; the cert refresher copies it into Mailu and reloads on renewal. - The agentbbs gateway reads/sends on behalf of members: IMAP via a Dovecot
master user (one secret opens any mailbox), SMTP via the co-located relay
on
127.0.0.1:25. Members therefore never manage an IMAP/SMTP password. - Provisioning is automatic: when a member verifies their email at
join@(or opensMail), agentbbs ensures<name>@bbs.profullstack.comexists via Mailu's admin REST API (internal/mailu, token =API_TOKEN). The manualdeploy/mailu/provision-mailbox.shis only for the gateway master user and backfills.
┌─────────── Caddy (:443) ───────────┐
webmail → │ mail.profullstack.com → 127.0.0.1:8080 (Mailu front: webmail/admin/API)
└───────────────┬─────────────────────┘
│ copies LE cert (refresh-certs.sh)
clients → Mailu front (:25 :465 :587 :993 :995) ──→ Postfix / Dovecot / rspamd
▲
agentbbs ──IMAP 993 (master user)──┘ ──SMTP 127.0.0.1:25 (local relay)──▶
agentbbs ──admin API (token) http://127.0.0.1:8080/api/v1──▶ (auto-provision)
Mail is delivered to the address domain (bbs.profullstack.com), so its MX
must point at the server host (mail.profullstack.com):
| Type | Host | Value |
|---|---|---|
| A | mail.profullstack.com |
host IP |
| MX | bbs.profullstack.com |
10 mail.profullstack.com. |
| TXT (SPF) | bbs.profullstack.com |
v=spf1 mx -all |
| TXT (DMARC) | _dmarc.bbs.profullstack.com |
v=DMARC1; p=quarantine; rua=mailto:postmaster@bbs.profullstack.com |
| TXT (DKIM) | dkim._domainkey.bbs.profullstack.com |
from flask mailu config-export after first boot |
| PTR | host IP | mail.profullstack.com (set at your VPS provider) |
Port 25 / deliverability: many cloud providers (incl. DigitalOcean) block outbound
:25by default — request an unblock, set the PTR/rDNS, and warm the IP, or relay outbound through a smarthost. Inbound MX and the gateway's local submission work regardless.
cd /opt/agentbbs/deploy/mailu
cp mailu.env.example mailu.env # fill SECRET_KEY, INITIAL_ADMIN_PW, API_TOKEN, DOMAIN=bbs.profullstack.com, HOSTNAMES=mail.profullstack.com
docker compose up -d
# add the address domain + the gateway master user:
docker compose exec admin flask mailu domain bbs.profullstack.com
AGENTBBS_MAIL_MASTER_USER=gateway ./provision-mailbox.sh --master "$(openssl rand -hex 16)"setup.sh writes the Caddy mail.profullstack.com site and the cert-refresh
timer when MAIL=1, and brings the stack up once mailu.env exists.
Set these on the agentbbs service (setup.sh §9e upserts the non-secret ones):
| Var | Value |
|---|---|
AGENTBBS_MAIL_ADDR_DOMAIN |
bbs.profullstack.com |
AGENTBBS_MAIL_DOMAIN |
mail.profullstack.com |
AGENTBBS_MAIL_IMAP_ADDR |
127.0.0.1:14143 (Dovecot direct, loopback) |
AGENTBBS_MAIL_IMAP_PLAINTEXT |
1 (the loopback path is plaintext) |
AGENTBBS_MAIL_SMTP_ADDR |
127.0.0.1:25 |
AGENTBBS_MAIL_ADMIN_URL |
http://127.0.0.1:8080 |
AGENTBBS_MAIL_API_TOKEN |
the Mailu API_TOKEN (secret) |
AGENTBBS_MAIL_MASTER_USER |
gateway |
AGENTBBS_MAIL_MASTER_PASS |
the master password set above (secret) |
AGENTBBS_WEBMAIL_URL |
https://mail.profullstack.com (default = mail host) |
Without AGENTBBS_MAIL_API_TOKEN auto-provisioning is skipped (the address is
still shown); without AGENTBBS_MAIL_MASTER_PASS the gateway can't open
mailboxes.
AGENTBBS_MAIL_SMTP_ADDRis127.0.0.1:25on purpose — it's the gateway's loopback hand-off into the on-box Mailu/Postfix MTA, not a remote submission client, so25is correct (465/587 are for authenticated remote clients). This is a separate config fromAGENTBBS_SMTP_*(the transactional sender for confirmation codes andnotify-creds, which defaults to STARTTLS:587). Seecredentials.md.
Mailu's front (nginx mail proxy) pre-authenticates every IMAP/SMTP login
against Mailu's user DB before proxying to Dovecot — and it rejects the Dovecot
master-user login form <addr>*gateway. So the gateway must reach Dovecot
directly, bypassing the front. The imap container has no TLS cert (only the
front does), so the bypass is plaintext over loopback — safe because the
connection (and the master password) never leave the host. Wiring:
-
Publish Dovecot's IMAP on loopback (docker-compose.override.yml):
imap.ports: ["127.0.0.1:14143:143"]. -
The Dovecot master user is defined in
data/overrides/dovecot/dovecot.conf(Mailu includes exactly that filename — not*.conf):auth_master_user_separator = * passdb { driver = passwd-file; master = yes; args = /overrides/master-users }with
data/overrides/dovecot/master-usersholdinggateway:{SHA512-CRYPT}$6$…(the hash ofAGENTBBS_MAIL_MASTER_PASS). The file must be world-readable (644) — Dovecot reads it as a non-root user, and 640 root:root yields atemp_fail. Do not addresult_success = continue(that would also require the target user's own password); the target mailbox comes from userdb. -
Point the gateway at it:
AGENTBBS_MAIL_IMAP_ADDR=127.0.0.1:14143+AGENTBBS_MAIL_IMAP_PLAINTEXT=1.
The join@ verification code and signup notifications use internal/mail (the
AGENTBBS_SMTP_* knobs), separate from the per-member mailbox client. Point
them at the local Mailu relay so codes actually send:
AGENTBBS_SMTP_HOST=127.0.0.1
AGENTBBS_SMTP_PORT=25
AGENTBBS_SMTP_FROM=bbs@bbs.profullstack.com
# user/pass omitted: the co-located relay accepts local submission unauthenticated
Provisioning is automatic at join@ verification. To create or backfill by hand:
deploy/mailu/provision-mailbox.sh alice # creates alice@bbs.profullstack.com(Set MAIL_DOMAIN=bbs.profullstack.com for the script, since the address domain
differs from the server host.)
The Dovecot master user (gateway) authenticates as any member with the
login form alice*gateway + the master password — exactly what
internal/mailbox's IMAP adapter sends. See
deploy/mailu/README.md for details.
Members are pointed at https://mail.profullstack.com (Roundcube) and the BBS
Mail client — they are not given the Mailu admin UI or alias management. Admin
is operator-only.