# Dovecot SMTP Submission Proxy Dovecot deployment acting as a pure SMTP submission proxy, companion to [imap-proxy](../imap-proxy): it listens on your hostname (e.g. `smtp.example.com`) with its own SSL certificate, accepts and terminates the client connections (implicit TLS on 465, STARTTLS on 587), then connects to the destination server (e.g. `smtp.example.net`) as if it were the client, over the destination's own SSL, and forwards the traffic bit-by-bit in both directions. Your mail clients (Thunderbird, Apple Mail, the Gmail app, ...) are configured once against your hostname and certificate; which provider actually serves the mail is decided in one config line and can be changed at will — no need to buy the provider a certificate for your domain or pay for custom-hostname setups. ## How it works Dovecot's login proxy is used with a `static` passdb: any username is accepted, no password is verified locally (`nopassword`), and the login is forwarded (credentials included) to the destination submission server, which performs the real authentication. Once the remote login succeeds, dovecot becomes a dumb pipe between client and destination. No mail is ever stored or queued locally: if the destination rejects a message, the client sees the rejection directly. Because the password must be forwarded, clients have to use cleartext mechanisms (`PLAIN` / `LOGIN`); dovecot only allows them after TLS is negotiated, so nothing travels unencrypted. Port 25 is intentionally not handled: it is server-to-server traffic driven by your MX records, which can point straight at the provider — no certificate for your client-facing hostname is involved there. ## Configuration Copy `example.env` to `.env` and adjust: - `SSL_CERT` / `SSL_KEY`: certificate and key for the hostname the proxy serves (e.g. Let's Encrypt live paths). - `SUBMISSION_EXPOSE` / `SMTPS_EXPOSE`: host bindings for ports 587/465. Copy `example.dovecot.conf` to `${DOVECOT_CONF}` (default `./data/dovecot.conf`) and set `host` in the `passdb static` block to your destination submission server (port 465 with `ssl = yes`, or port 587 with `starttls = yes`). The destination certificate is verified against the system CA bundle (`ssl_client_ca_file`); use `ssl = any-cert` instead of `ssl = yes` if the destination has a self-signed certificate. ## Usage ```sh cp example.env .env mkdir -p data && cp example.dovecot.conf data/dovecot.conf $EDITOR .env data/dovecot.conf docker compose up -d ``` ## Testing ```sh openssl s_client -connect smtp.example.com:465 -quiet # then authenticate as an existing user on the destination server: EHLO test AUTH PLAIN ``` (generate the AUTH string with `printf '\0user@example.com\0password' | base64`) ## Notes The `-root` image flavor is used so dovecot can read certificates that are only readable by root (as the Let's Encrypt live folder is); dovecot itself still drops privileges per-service. If your certificates are world-readable you can drop the `-root` suffix from `DOVECOT_VERSION`.