diff --git a/content/2.getting-started/2.installation.md b/content/2.getting-started/2.installation.md
index 1adc920..909cf26 100644
--- a/content/2.getting-started/2.installation.md
+++ b/content/2.getting-started/2.installation.md
@@ -65,3 +65,14 @@ docker run -d \
Once this has started, Caddy will issue an SSL certificate for your domain and you'll be able to immediately access the Postal web interface and login with the user you created in one of the previous steps.

+
+## Next steps
+
+Once you can log in:
+
+1. Create an organization and a mail server.
+2. Add the domain you want to send from and follow the [Sending domains](/features/sending-domains) page to verify it and publish its SPF, DKIM and return path records.
+3. Create an **SMTP** or **API** [credential](/features/smtp-authentication) and send a test message.
+4. Point the `smtp` section of `postal.yml` at your new mail server so that Postal can send its own notification e-mails, then `postal restart`.
+
+The full set of commands provided by the `postal` helper is documented on [The postal command](/getting-started/postal-command) page.
diff --git a/content/2.getting-started/4.dns-configuration.md b/content/2.getting-started/4.dns-configuration.md
index a5ca5b1..dd8c999 100644
--- a/content/2.getting-started/4.dns-configuration.md
+++ b/content/2.getting-started/4.dns-configuration.md
@@ -99,7 +99,7 @@ You may wish to replace ~all with -all to make the SPF
## Return Path
-The return path domain is the default domain that is used as the `MAIL FROM` for all messages sent through a mail server. You should add DNS records as below.
+The return path domain is the default domain that is used as the `MAIL FROM` for all messages sent through a mail server, so bounces and auto-responses are delivered here. It is also the domain Postal signs messages with (using your `signing.key`) whenever a sending domain does not yet have a working DKIM record of its own. You should add DNS records as below.
@@ -133,7 +133,7 @@ The return path domain is the default domain that is used as the `MAIL FROM` for
| postal._domainkey.rp.postal.example.com |
TXT |
- Value from postal default-dkim-record |
+ Value from postal default-dkim-record (the postal selector is the value of dns.dkim_identifier) |
@@ -141,7 +141,7 @@ The return path domain is the default domain that is used as the `MAIL FROM` for
## Route domain
-If you wish to receive incoming e-mail by forwarding messages directly to routes in Postal, you'll need to configure a domain for this just to point to your server using an MX record.
+If you wish to receive incoming e-mail by forwarding messages directly to routes in Postal (each route has a unique `{token}@routes.postal.example.com` address - see [Routing incoming e-mail](/features/routing-incoming-email)), you'll need to configure a domain for this just to point to your server using an MX record.
@@ -186,6 +186,10 @@ If you would like to make use of Click and Open Tracking then you should set up
+## Records for each sending domain
+
+The records above are for the Postal installation itself. Each domain you send mail *from* additionally needs its own SPF, DKIM and (optionally) return path and MX records, which Postal generates for you and checks automatically. These are described on the [Sending domains](/features/sending-domains) page.
+
## Example Postal Configuration
In your `postal.yml` you should have something that looks like the below to cover the key DNS records.
diff --git a/content/2.getting-started/7.configuration-reference.md b/content/2.getting-started/7.configuration-reference.md
new file mode 100644
index 0000000..646e0c3
--- /dev/null
+++ b/content/2.getting-started/7.configuration-reference.md
@@ -0,0 +1,240 @@
+---
+title: Configuration reference
+description: 'Every Postal configuration option, its default value and environment variable name.'
+category: Installation
+---
+This page lists every configuration option available in Postal 3.3.7. Each option can be set in the `postal.yml` configuration file under the section heading shown, or with the environment variable shown. See [Configuration](/getting-started/configuration) for how the file and environment variables are loaded.
+
+This list is derived from the [configuration schema](https://github.com/postalserver/postal/blob/main/lib/postal/config_schema.rb) in the Postal repository. The upstream repository also publishes it as an [example YAML file](https://github.com/postalserver/postal/blob/main/doc/config/yaml.yml) and a [list of environment variables](https://github.com/postalserver/postal/blob/main/doc/config/environment-variables.md), which may include options added after this page was written.
+
+An empty default means the option is unset unless you provide a value. Array options are written as YAML lists in the file and as comma-separated values in environment variables.
+
+## postal
+
+Installation-wide settings.
+
+| Option | Environment variable | Default | Description |
+|---|---|---|---|
+| `web_hostname` | `POSTAL_WEB_HOSTNAME` | `postal.example.com` | The hostname that the Postal web interface runs on. |
+| `web_protocol` | `POSTAL_WEB_PROTOCOL` | `https` | The HTTP protocol to use for the Postal web interface. |
+| `smtp_hostname` | `POSTAL_SMTP_HOSTNAME` | `postal.example.com` | The hostname that the Postal SMTP server runs on. |
+| `use_ip_pools` | `POSTAL_USE_IP_POOLS` | `false` | Should IP pools be enabled for this installation? See [IP Pools](/features/ip-pools). |
+| `default_maximum_delivery_attempts` | `POSTAL_DEFAULT_MAXIMUM_DELIVERY_ATTEMPTS` | `18` | The maximum number of delivery attempts. After this many attempts a message is hard failed (and, for outgoing mail, the recipient is added to the suppression list). |
+| `default_maximum_hold_expiry_days` | `POSTAL_DEFAULT_MAXIMUM_HOLD_EXPIRY_DAYS` | `7` | The number of days to hold a message before they will be expired. Held messages are released without action after this long. |
+| `default_suppression_list_automatic_removal_days` | `POSTAL_DEFAULT_SUPPRESSION_LIST_AUTOMATIC_REMOVAL_DAYS` | `30` | The number of days an address will remain in a suppression list before being removed. |
+| `default_spam_threshold` | `POSTAL_DEFAULT_SPAM_THRESHOLD` | `5` | The default threshold at which a message should be treated as spam. Used as the initial value for new mail servers; changeable per server. |
+| `default_spam_failure_threshold` | `POSTAL_DEFAULT_SPAM_FAILURE_THRESHOLD` | `20` | The default threshold at which a message should be treated as spam failure. Used as the initial value for new mail servers; changeable per server. |
+| `use_local_ns_for_domain_verification` | `POSTAL_USE_LOCAL_NS_FOR_DOMAIN_VERIFICATION` | `false` | Domain verification and checking usually checks with a domain's nameserver. Enable this to check with the server's local nameservers. |
+| `use_resent_sender_header` | `POSTAL_USE_RESENT_SENDER_HEADER` | `true` | Append a `Resent-Sender` header (containing the envelope sender) to all outgoing e-mails. |
+| `signing_key_path` | `POSTAL_SIGNING_KEY_PATH` | `$config-file-root/signing.key` | Path to the private key used for signing. RSA private key used to sign webhook/HTTP endpoint requests and for the return path DKIM record. |
+| `smtp_relays` | `POSTAL_SMTP_RELAYS` | `[]` | An array of SMTP relays in the format of smtp://host:port. Format `smtp://host:port?ssl_mode=MODE` where MODE is `Auto`, `STARTLS`, `TLS` or `None`. When set, all outgoing mail goes via the relays. See [SMTP relays](/getting-started/configuration#smtp-relays). |
+| `trusted_proxies` | `POSTAL_TRUSTED_PROXIES` | `[]` | An array of IP addresses to trust for proxying requests to Postal (in addition to localhost addresses). IP addresses or CIDR ranges. |
+| `allowed_request_destinations` | `POSTAL_ALLOWED_REQUEST_DESTINATIONS` | `[]` | Hostnames or IP/CIDR ranges that outbound webhook and HTTP endpoint requests are permitted to reach even when they resolve to a private, loopback, link-local or otherwise reserved address. All other such destinations are blocked to prevent SSRF. See [Blocked destinations](/developer/http-payloads#blocked-destinations). |
+| `queued_message_lock_stale_days` | `POSTAL_QUEUED_MESSAGE_LOCK_STALE_DAYS` | `1` | The number of days after which to consider a lock as stale. Messages with stale locks will be removed and not retried. See [Workers & background tasks](/other/workers-and-background-tasks#stale-locks). |
+| `batch_queued_messages` | `POSTAL_BATCH_QUEUED_MESSAGES` | `true` | When enabled queued messages will be de-queued in batches based on their destination. |
+
+## web_server
+
+Settings for the `postal web-server` process. See also the `PORT` and `BIND_ADDRESS` environment variables.
+
+| Option | Environment variable | Default | Description |
+|---|---|---|---|
+| `default_port` | `WEB_SERVER_DEFAULT_PORT` | `5000` | The default port the web server should listen on unless overriden by the PORT environment variable. |
+| `default_bind_address` | `WEB_SERVER_DEFAULT_BIND_ADDRESS` | `127.0.0.1` | The default bind address the web server should listen on unless overriden by the BIND_ADDRESS environment variable. |
+| `max_threads` | `WEB_SERVER_MAX_THREADS` | `5` | The maximum number of threads which can be used by the web server. |
+
+## worker
+
+Settings for `postal worker` processes. See [Workers & background tasks](/other/workers-and-background-tasks).
+
+| Option | Environment variable | Default | Description |
+|---|---|---|---|
+| `default_health_server_port` | `WORKER_DEFAULT_HEALTH_SERVER_PORT` | `9090` | The default port for the worker health server to listen on. |
+| `default_health_server_bind_address` | `WORKER_DEFAULT_HEALTH_SERVER_BIND_ADDRESS` | `127.0.0.1` | The default bind address for the worker health server to listen on. |
+| `threads` | `WORKER_THREADS` | `2` | The number of threads to execute within each worker. The database connection pool is grown automatically to at least `threads + 3`. |
+
+## main_db
+
+The main MariaDB database which stores organizations, servers, users, domains, routes and the message queue.
+
+| Option | Environment variable | Default | Description |
+|---|---|---|---|
+| `host` | `MAIN_DB_HOST` | `localhost` | Hostname for the main MariaDB server. |
+| `port` | `MAIN_DB_PORT` | `3306` | The MariaDB port to connect to. |
+| `username` | `MAIN_DB_USERNAME` | `postal` | The MariaDB username. |
+| `password` | `MAIN_DB_PASSWORD` | | The MariaDB password. |
+| `database` | `MAIN_DB_DATABASE` | `postal` | The MariaDB database name. |
+| `pool_size` | `MAIN_DB_POOL_SIZE` | `5` | The maximum size of the MariaDB connection pool. Workers automatically grow this to at least `worker.threads + 3`. |
+| `encoding` | `MAIN_DB_ENCODING` | `utf8mb4` | The encoding to use when connecting to the MariaDB database. |
+
+## message_db
+
+Connection details for the MariaDB server on which a separate database is created for each mail server. This may be the same server as `main_db`. Databases are named `{database_name_prefix}-server-{id}`.
+
+| Option | Environment variable | Default | Description |
+|---|---|---|---|
+| `host` | `MESSAGE_DB_HOST` | `localhost` | Hostname for the MariaDB server which stores the mail server databases. |
+| `port` | `MESSAGE_DB_PORT` | `3306` | The MariaDB port to connect to. |
+| `username` | `MESSAGE_DB_USERNAME` | `postal` | The MariaDB username. |
+| `password` | `MESSAGE_DB_PASSWORD` | | The MariaDB password. |
+| `encoding` | `MESSAGE_DB_ENCODING` | `utf8mb4` | The encoding to use when connecting to the MariaDB database. |
+| `database_name_prefix` | `MESSAGE_DB_DATABASE_NAME_PREFIX` | `postal` | The MariaDB prefix to add to database names. |
+
+## logging
+
+See [Logging](/features/logging).
+
+| Option | Environment variable | Default | Description |
+|---|---|---|---|
+| `rails_log_enabled` | `LOGGING_RAILS_LOG_ENABLED` | `false` | Enable the default Rails logger. |
+| `sentry_dsn` | `LOGGING_SENTRY_DSN` | | A DSN which should be used to report exceptions to Sentry. |
+| `enabled` | `LOGGING_ENABLED` | `true` | Enable the Postal logger to log to STDOUT. |
+| `highlighting_enabled` | `LOGGING_HIGHLIGHTING_ENABLED` | `false` | Enable highlighting of log lines. |
+
+## gelf
+
+Send log output to a Graylog/GELF server over UDP in addition to STDOUT. Enabled when `host` is set.
+
+| Option | Environment variable | Default | Description |
+|---|---|---|---|
+| `host` | `GELF_HOST` | | GELF-capable host to send logs to. |
+| `port` | `GELF_PORT` | `12201` | GELF port to send logs to. |
+| `facility` | `GELF_FACILITY` | `postal` | The facility name to add to all log entries sent to GELF. |
+
+## smtp_server
+
+Settings for the `postal smtp-server` process. See [SMTP TLS](/features/smtp-tls) and [SMTP Authentication](/features/smtp-authentication).
+
+| Option | Environment variable | Default | Description |
+|---|---|---|---|
+| `default_port` | `SMTP_SERVER_DEFAULT_PORT` | `25` | The default port the SMTP server should listen on unless overriden by the PORT environment variable. |
+| `default_bind_address` | `SMTP_SERVER_DEFAULT_BIND_ADDRESS` | `::` | The default bind address the SMTP server should listen on unless overriden by the BIND_ADDRESS environment variable. `::` listens on all IPv4 and IPv6 addresses. |
+| `default_health_server_port` | `SMTP_SERVER_DEFAULT_HEALTH_SERVER_PORT` | `9091` | The default port for the SMTP server health server to listen on. |
+| `default_health_server_bind_address` | `SMTP_SERVER_DEFAULT_HEALTH_SERVER_BIND_ADDRESS` | `127.0.0.1` | The default bind address for the SMTP server health server to listen on. |
+| `tls_enabled` | `SMTP_SERVER_TLS_ENABLED` | `false` | Enable TLS for the SMTP server (requires certificate). |
+| `tls_certificate_path` | `SMTP_SERVER_TLS_CERTIFICATE_PATH` | `$config-file-root/smtp.cert` | The path to the SMTP server's TLS certificate. |
+| `tls_private_key_path` | `SMTP_SERVER_TLS_PRIVATE_KEY_PATH` | `$config-file-root/smtp.key` | The path to the SMTP server's TLS private key. |
+| `tls_ciphers` | `SMTP_SERVER_TLS_CIPHERS` | | Override ciphers to use for SSL. |
+| `ssl_version` | `SMTP_SERVER_SSL_VERSION` | `SSLv23` | The SSL versions which are supported. An OpenSSL version constant such as `SSLv23`, `TLSv1_2` or `TLSv1_3`. |
+| `proxy_protocol` | `SMTP_SERVER_PROXY_PROTOCOL` | `false` | Enable proxy protocol for use behind some load balancers (supports proxy protocol v1 only). When enabled the `220` greeting is delayed until the `PROXY` line is received. |
+| `log_connections` | `SMTP_SERVER_LOG_CONNECTIONS` | `false` | Enable connection logging. |
+| `max_message_size` | `SMTP_SERVER_MAX_MESSAGE_SIZE` | `14` | The maximum message size to accept from the SMTP server (in MB). Checked once the whole message has been received; clients receive `552 Message too large`. |
+| `log_ip_address_exclusion_matcher` | `SMTP_SERVER_LOG_IP_ADDRESS_EXCLUSION_MATCHER` | | A regular expression to use to exclude connections from logging. Ruby regular expression matched against the client IP address. |
+
+## dns
+
+The DNS names your installation uses. See [DNS configuration](/getting-started/dns-configuration) and [Sending domains](/features/sending-domains).
+
+| Option | Environment variable | Default | Description |
+|---|---|---|---|
+| `mx_records` | `DNS_MX_RECORDS` | `mx1.postal.example.com, mx2.postal.example.com` | The names of the default MX records. |
+| `spf_include` | `DNS_SPF_INCLUDE` | `spf.postal.example.com` | The location of the SPF record. |
+| `return_path_domain` | `DNS_RETURN_PATH_DOMAIN` | `rp.postal.example.com` | The return path hostname. |
+| `route_domain` | `DNS_ROUTE_DOMAIN` | `routes.postal.example.com` | The domain to use for hosting route-specific addresses. |
+| `track_domain` | `DNS_TRACK_DOMAIN` | `track.postal.example.com` | The CNAME which tracking domains should be pointed to. |
+| `helo_hostname` | `DNS_HELO_HOSTNAME` | | The hostname to use in HELO/EHLO when connecting to external SMTP servers. Falls back to `postal.smtp_hostname`. When sending from an IP pool address, the address's own hostname is used instead. |
+| `dkim_identifier` | `DNS_DKIM_IDENTIFIER` | `postal` | The identifier to use for DKIM keys in DNS records. Per-domain DKIM selectors are `{dkim_identifier}-{random}`, e.g. `postal-AB1CDE._domainkey`. |
+| `domain_verify_prefix` | `DNS_DOMAIN_VERIFY_PREFIX` | `postal-verification` | The prefix to add before TXT record verification string. Verification TXT records are `{domain_verify_prefix} {token}`. |
+| `custom_return_path_prefix` | `DNS_CUSTOM_RETURN_PATH_PREFIX` | `psrp` | The domain to use on external domains which points to the Postal return path domain. Domains may CNAME `{prefix}.yourdomain.com` to `return_path_domain`. |
+| `timeout` | `DNS_TIMEOUT` | `5` | The timeout to wait for DNS resolution. |
+| `resolv_conf_path` | `DNS_RESOLV_CONF_PATH` | `/etc/resolv.conf` | The path to the resolv.conf file containing addresses for local nameservers. Used for MX lookups when sending and, when `postal.use_local_ns_for_domain_verification` is enabled, for domain checks. |
+
+## smtp
+
+The SMTP server Postal uses to send its **own** e-mails (password resets, send limit warnings, suspension notices, test messages). This is not used for mail sent through your mail servers. Once Postal is running you can point this at one of your own mail servers.
+
+| Option | Environment variable | Default | Description |
+|---|---|---|---|
+| `host` | `SMTP_HOST` | `127.0.0.1` | The hostname to send application-level e-mails to. |
+| `port` | `SMTP_PORT` | `25` | The port number to send application-level e-mails to. |
+| `username` | `SMTP_USERNAME` | | The username to use when authentication to the SMTP server. |
+| `password` | `SMTP_PASSWORD` | | The password to use when authentication to the SMTP server. |
+| `authentication_type` | `SMTP_AUTHENTICATION_TYPE` | `login` | The type of authentication to use. `plain`, `login` or `cram_md5`. |
+| `enable_starttls` | `SMTP_ENABLE_STARTTLS` | `false` | Use STARTTLS when connecting to the SMTP server and fail if unsupported. |
+| `enable_starttls_auto` | `SMTP_ENABLE_STARTTLS_AUTO` | `true` | Detects if STARTTLS is enabled in the SMTP server and starts to use it. |
+| `openssl_verify_mode` | `SMTP_OPENSSL_VERIFY_MODE` | `peer` | When using TLS, you can set how OpenSSL checks the certificate. Use 'none' for no certificate checking. `peer` or `none`. |
+| `from_name` | `SMTP_FROM_NAME` | `Postal` | The name to use as the from name outgoing emails from Postal. |
+| `from_address` | `SMTP_FROM_ADDRESS` | `postal@example.com` | The e-mail to use as the from address outgoing emails from Postal. |
+
+## rails
+
+Settings for the underlying Rails application.
+
+| Option | Environment variable | Default | Description |
+|---|---|---|---|
+| `environment` | `RAILS_ENVIRONMENT` | `production` | The Rails environment to run the application in. Leave as `production`. |
+| `secret_key` | `RAILS_SECRET_KEY` | | The secret key used to sign and encrypt cookies and session data in the application. Generated for you by `postal bootstrap`. Changing it invalidates all sessions. |
+
+## rspamd
+
+See [Spam & Virus Checking](/features/spam-and-virus-checking). If both rspamd and spamd are enabled, only rspamd is used.
+
+| Option | Environment variable | Default | Description |
+|---|---|---|---|
+| `enabled` | `RSPAMD_ENABLED` | `false` | Enable rspamd for message inspection. |
+| `host` | `RSPAMD_HOST` | `127.0.0.1` | The hostname of the rspamd server. |
+| `port` | `RSPAMD_PORT` | `11334` | The port of the rspamd server. |
+| `ssl` | `RSPAMD_SSL` | `false` | Enable SSL for the rspamd connection. |
+| `password` | `RSPAMD_PASSWORD` | | The password for the rspamd server. |
+| `flags` | `RSPAMD_FLAGS` | | Any flags for the rspamd server. |
+
+## spamd
+
+See [Spam & Virus Checking](/features/spam-and-virus-checking).
+
+| Option | Environment variable | Default | Description |
+|---|---|---|---|
+| `enabled` | `SPAMD_ENABLED` | `false` | Enable SpamAssassin for message inspection. |
+| `host` | `SPAMD_HOST` | `127.0.0.1` | The hostname for the SpamAssassin server. |
+| `port` | `SPAMD_PORT` | `783` | The port of the SpamAssassin server. |
+
+## clamav
+
+See [Spam & Virus Checking](/features/spam-and-virus-checking).
+
+| Option | Environment variable | Default | Description |
+|---|---|---|---|
+| `enabled` | `CLAMAV_ENABLED` | `false` | Enable ClamAV for message inspection. |
+| `host` | `CLAMAV_HOST` | `127.0.0.1` | The host of the ClamAV server. |
+| `port` | `CLAMAV_PORT` | `2000` | The port of the ClamAV server. |
+
+## smtp_client
+
+Timeouts (in seconds) for outgoing SMTP connections made by workers when delivering mail.
+
+| Option | Environment variable | Default | Description |
+|---|---|---|---|
+| `open_timeout` | `SMTP_CLIENT_OPEN_TIMEOUT` | `30` | The open timeout for outgoing SMTP connections. |
+| `read_timeout` | `SMTP_CLIENT_READ_TIMEOUT` | `30` | The read timeout for outgoing SMTP connections. |
+
+## migration_waiter
+
+See [Our container image](/other/containers#waiting-for-database-migrations).
+
+| Option | Environment variable | Default | Description |
+|---|---|---|---|
+| `enabled` | `MIGRATION_WAITER_ENABLED` | `false` | Wait for all migrations to run before starting a process. |
+| `attempts` | `MIGRATION_WAITER_ATTEMPTS` | `120` | The number of attempts to try waiting for migrations to complete before start. |
+| `sleep_time` | `MIGRATION_WAITER_SLEEP_TIME` | `2` | The number of seconds to wait between each migration check. |
+
+## oidc
+
+See [OpenID Connect](/features/oidc).
+
+| Option | Environment variable | Default | Description |
+|---|---|---|---|
+| `enabled` | `OIDC_ENABLED` | `false` | Enable OIDC authentication. |
+| `local_authentication_enabled` | `OIDC_LOCAL_AUTHENTICATION_ENABLED` | `true` | When enabled, users with passwords will still be able to login locally. If disable, only OpenID Connect will be available. |
+| `name` | `OIDC_NAME` | `OIDC Provider` | The name of the OIDC provider as shown in the UI. |
+| `issuer` | `OIDC_ISSUER` | | The OIDC issuer URL. |
+| `identifier` | `OIDC_IDENTIFIER` | | The client ID for OIDC. |
+| `secret` | `OIDC_SECRET` | | The client secret for OIDC. |
+| `scopes` | `OIDC_SCOPES` | `openid, email` | Scopes to request from the OIDC server. Must include enough scopes for the provider to return the user's e-mail address. |
+| `uid_field` | `OIDC_UID_FIELD` | `sub` | The field to use to determine the user's UID. |
+| `email_address_field` | `OIDC_EMAIL_ADDRESS_FIELD` | `email` | The field to use to determine the user's email address. |
+| `name_field` | `OIDC_NAME_FIELD` | `name` | The field to use to determine the user's name. |
+| `discovery` | `OIDC_DISCOVERY` | `true` | Enable discovery to determine endpoints from .well-known/openid-configuration from the Issuer. |
+| `authorization_endpoint` | `OIDC_AUTHORIZATION_ENDPOINT` | | The authorize endpoint on the authorization server (only used when discovery is false). |
+| `token_endpoint` | `OIDC_TOKEN_ENDPOINT` | | The token endpoint on the authorization server (only used when discovery is false). |
+| `userinfo_endpoint` | `OIDC_USERINFO_ENDPOINT` | | The user info endpoint on the authorization server (only used when discovery is false). |
+| `jwks_uri` | `OIDC_JWKS_URI` | | The JWKS endpoint on the authorization server (only used when discovery is false). |
diff --git a/content/2.getting-started/8.postal-command.md b/content/2.getting-started/8.postal-command.md
new file mode 100644
index 0000000..d6d483e
--- /dev/null
+++ b/content/2.getting-started/8.postal-command.md
@@ -0,0 +1,83 @@
+---
+title: The postal command
+description: 'Reference for the postal helper command installed from the postalserver/install repository.'
+category: Installation
+---
+
+The `postal` command used throughout these docs is a small Bash script from the [installation helper repository](https://github.com/postalserver/install), which the [pre-requisites](/getting-started/prerequisites) page has you clone to `/opt/postal/install` and symlink to `/usr/bin/postal`. It wraps Docker Compose so that you don't need to remember the container commands.
+
+All commands operate on a `docker-compose.yml` in `/opt/postal/install`, which is generated for you from a template (`templates/docker-compose.v3.yml`) the first time you run `bootstrap`, `upgrade` or any command that needs it. Docker Compose is run with the project name `postal`, so the containers are named `postal-web-1`, `postal-smtp-1`, `postal-worker-1` and so on.
+
+## Running Postal
+
+| Command | Description |
+|---|---|
+| `postal start` | Start all services in the background (`docker compose up -d`). Extra arguments are passed through, e.g. `postal start web`. |
+| `postal stop` | Stop and remove the containers (`docker compose down`). |
+| `postal restart` | Restart all containers. Required after changing `postal.yml`. |
+| `postal status` | Show the running containers (`docker compose ps`). |
+| `postal logs [service]` | Show logs for all services or one of `web`, `smtp`, `worker`. Extra arguments are passed through, e.g. `postal logs -f worker`. |
+| `postal bash [service]` | Open a shell inside a running service container. |
+| `postal dc [args]` | Run any other `docker compose` command against the Postal project, e.g. `postal dc pull`. |
+
+## Setup and upgrade
+
+| Command | Description |
+|---|---|
+| `postal bootstrap hostname [path]` | Create initial configuration in `path` (default `/opt/postal/config`): `postal.yml` from the example file with your hostname and a random `rails.secret_key` filled in, a `Caddyfile`, and a 1024-bit RSA `signing.key`. Existing files are never overwritten. Also generates `docker-compose.yml` for the latest release. |
+| `postal initialize` | Pull the image and run `postal initialize` inside a temporary container to create the main database and load the schema. |
+| `postal upgrade [version]` | Upgrade to the given version (or the latest release). See [Upgrading](/getting-started/upgrading). |
+| `postal upgrade-db` | Run database migrations only, without pulling a new image or restarting. Useful after restoring a database from another installation. |
+| `postal set-version x.x.x` | Regenerate `docker-compose.yml` for a specific version without pulling or restarting anything. |
+
+## Other tools
+
+These run the corresponding command from the [container image](/other/containers#other-commands) in a temporary `runner` container.
+
+| Command | Description |
+|---|---|
+| `postal make-user` | Interactively create a global administrator user (prompts for e-mail address, first name, last name and password). |
+| `postal default-dkim-record` | Print the DKIM TXT record to publish at `postal._domainkey.{return path domain}`. |
+| `postal test-app-smtp address` | Send a test e-mail using the `smtp` section of your configuration. |
+| `postal console` | Open a Rails console against your installation. |
+| `postal version` | Print the version of Postal in the configured image. |
+
+## Options
+
+| Option | Description |
+|---|---|
+| `--version x.x.x` | With `bootstrap` or `upgrade`, use this version instead of looking up the latest release on GitHub. |
+| `--no-git-pull` | With `upgrade`, skip updating the helper repository first. |
+| `--dev` | Print the commands that would be run instead of running them. |
+
+Looking up the latest release requires `curl` and `jq` and makes an unauthenticated request to the GitHub API, which is rate limited. If you hit the limit, pass an explicit version.
+
+## Customising the installation
+
+### Number of workers
+
+To run more than one worker container, add a `docker-compose.override.yml` (see below) that sets the number of replicas for the `worker` service. This survives upgrades, whereas `postal start --scale worker=3` is reset to one worker the next time `postal upgrade` runs.
+
+```yaml
+services:
+ worker:
+ deploy:
+ replicas: 3
+```
+
+### Overriding the compose file
+
+Docker Compose automatically merges `docker-compose.override.yml` from the same directory. Use this for changes such as [log drivers](/features/logging#redirecting-logs-to-the-host-syslog), extra environment variables or resource limits, so that they survive upgrades (the generated `docker-compose.yml` is replaced on every upgrade).
+
+### Hooks
+
+If a `hooks` directory exists in `/opt/postal/install`, the Bash script with the matching name in it is run at various points. Available hook names are `pre-start`, `post-start`, `pre-stop`, `post-stop`, `pre-restart`, `post-restart`, `pre-initialize-pull`, `pre-initialize`, `post-initialize`, `pre-upgrade-pull`, `post-upgrade-pull`, `pre-upgrade-db`, `post-upgrade-db`, `post-upgrade`, `pre-bootstrap`, `post-bootstrap` and `set-postal-version`.
+
+## The generated compose file
+
+For reference, the v3 template starts the following services, all using host networking and mounting `/opt/postal/config` at `/config`:
+
+* `web` - `postal web-server`
+* `smtp` - `postal smtp-server` with the `NET_BIND_SERVICE` capability
+* `worker` - `postal worker`
+* `runner` - a `tools` profile service used by the helper for one-off commands; it is not started by `postal start`
diff --git a/content/3.features/click-and-open-tracking.md b/content/3.features/click-and-open-tracking.md
index 7d8acb9..cfd1708 100644
--- a/content/3.features/click-and-open-tracking.md
+++ b/content/3.features/click-and-open-tracking.md
@@ -1,6 +1,6 @@
---
title: Click & Open Tracking
-description: ''
+description: 'Track when recipients open your e-mails and click links within them.'
category: Features
---
@@ -8,22 +8,35 @@ Postal supports tracking opens and clicks from e-mails. This allows you to see w
-
## How it works
-Once enabled, Postal will automatically scan your outgoing messages and replace any links and images with new URLs that go via your Postal web server. When the link is clicked, Postal will log the click and redirect to the user to the original URL automatically. The links that are included in the e-mail should be on the same domain as the sender and therefore you need to configure a subdomain like `click.yourdomain.com` and point it to your Postal server.
+Once enabled, Postal will automatically scan your outgoing messages and replace any links with new URLs that go via your Postal web server, and insert a tracking image into HTML messages. When the link is clicked, Postal will log the click and redirect the user to the original URL automatically. The links that are included in the e-mail should be on the same domain as the sender and therefore you need to configure a subdomain like `click.yourdomain.com` and point it to your Postal server.
+
+For a message to be rewritten, all of the following must be true:
+
+* The message is an outgoing message with an authenticated sending domain.
+* The server has a **tracking domain** attached to that sending domain (e.g. `click.yourdomain.com` for messages from `yourdomain.com`).
+* The tracking domain's DNS check has passed - its status must be **OK**. Postal checks for a CNAME record at the tracking domain pointing at the value of `dns.track_domain` in your configuration (`track.postal.example.com` in the [DNS configuration](/getting-started/dns-configuration) examples). Tracking domains are re-checked automatically every hour.
+* The message does not have an `X-AMP: skip` header.
+
+Tracking domains have three options which are all enabled by default:
+
+* **SSL** - rewritten URLs use `https://`. You must have a valid certificate for the tracking domain on your web proxy. It is **highly** recommended to leave this enabled as anything else is likely to cause problems with reputation and user experience.
+* **Track loads** - a 1×1 pixel image is inserted before the closing `