Documentation

Last updated in git: 2026-06-11

Getting started: Inbound mail

This walkthrough shows how to start Everlock with inbound SMTP enabled, add a simple rules.toml, send a hello-world inbound mail, and verify that the message landed in the versioned mail store.

What “vhost” means for mail

Mail does not use HTTP-style vhosts.

The equivalent pieces are:

  • the recipient domain in the mail address, such as alice@example.com
  • the MX record for that domain, which points at the machine running Everlock

So when you want Everlock to receive mail for example.com, you point the MX record for example.com at your Everlock host.

1. Start Everlock with SMTP

For the first pass, use explicit CLI flags:

everlock serve \
  --frontend-ssh \
  --backend-admin-ssh \
  --frontend-smtp \
  --frontend-smtp-listen 0.0.0.0:2525 \
  --backend-mail-smtp \
  --admin-user admin \
  --admin-password change-me

Expected startup shape:

[INFO  everlock] starting backend-mail-smtp
[INFO  everlock_backend_mail_smtp::module] backend-mail-smtp registered (store: everlock-mail, delivery path: domain/mailbox/YYYY/MM/DD/*.eml)
[INFO  everlock] starting frontend-smtp
[INFO  everlock_frontend_smtp::module] frontend-smtp: using backend-mail-smtp
[INFO  everlock_frontend_smtp::module] frontend-smtp: binding listener on 0.0.0.0:2525
[INFO  everlock_frontend_smtp::module] SMTP server listening on 0.0.0.0:2525

2. Optionally add rules.toml

This step is optional. SMTP can start without a rules.toml, and in that case Everlock stores mail by default into the recipient mailbox under the inbox folder.

When you define rules, Everlock evaluates them by ascending priority. Lower numbers run first. If priority is omitted, it defaults to 10.

Recipient acceptance also has a bootstrap behavior:

  • if no local mail domains are configured yet, inbound SMTP accepts syntactically valid recipients
  • once you create the first mail domain with /mail domains create <domain>, inbound accepts only configured local domains

This bootstrap mode is a setup convenience, not a general outbound relay.

Add a rules file when you want behavior other than the default, such as:

  • rejecting specific messages
  • forwarding messages
  • storing into a different mailbox
  • storing into a different folder

Create data/everlock-mail/rules.toml:

[[rule]]
id = "rule-local-example"
name = "store all example.com mail"
priority = 10
receiver = "*@example.com"
type = "store"
folder = "inbox"

Commit it into the versioned store:

git -C ./data/everlock-mail add rules.toml
git -C ./data/everlock-mail commit -m "add initial mail rules"

Expected result:

[main abc1234] add initial mail rules
 1 file changed, 7 insertions(+)
 create mode 100644 rules.toml

If you skip this step entirely, the current backend default is:

  • no matching rule
  • store the message in the recipient mailbox
  • use inbox as the folder

3. Point DNS at the Everlock host

For real inbound delivery, publish:

  • A or AAAA for mail.example.com
  • MX for example.com pointing to mail.example.com

Example DNS intent:

mail.example.com.  A   203.0.113.24
example.com.       MX  10 mail.example.com.

For a local test, you can skip public DNS and just connect directly to the listener on 127.0.0.1:2525.

4. Send a hello-world mail from the CLI

The easiest CLI test is swaks:

swaks \
  --server 127.0.0.1:2525 \
  --from sender@example.net \
  --to alice@example.com \
  --header "Subject: Hello world" \
  --body "Hello from Everlock SMTP"

Expected output shape:

=== Trying 127.0.0.1:2525...
<~  220
 ~> EHLO
<~  250
 ~> MAIL FROM:<sender@example.net>
<~  250
 ~> RCPT TO:<alice@example.com>
<~  250
 ~> DATA
<~  354
 ~> .
<~  250 2.0.0 Accepted

If you do not have swaks, you have two simple alternatives:

Plain SMTP without TLS:

printf 'EHLO localhost\r\nMAIL FROM:<sender@example.net>\r\nRCPT TO:<alice@example.com>\r\nDATA\r\nSubject: Hello world\r\nFrom: sender@example.net\r\nTo: alice@example.com\r\n\r\nHello from Everlock SMTP\r\n.\r\nQUIT\r\n' \
  | nc 127.0.0.1 2525

SMTP with STARTTLS:

openssl s_client -starttls smtp -crlf -connect 127.0.0.1:2525 <<'EOF'
EHLO localhost
MAIL FROM:<sender@example.net>
RCPT TO:<alice@example.com>
DATA
Subject: Hello world
From: sender@example.net
To: alice@example.com

Hello from Everlock SMTP
.
QUIT
EOF

Expected final acceptance line:

250 2.0.0 Accepted

Do not use plain openssl s_client -connect ...:25 for SMTP. That attempts implicit TLS immediately. Everlock speaks SMTP first and upgrades with STARTTLS on the same listener.

5. Send a test mail from a desktop mail client

Everlock supports inbound SMTP and a separate authenticated submission listener. For local testing against the inbound listener, use:

  • server: 127.0.0.1
  • port: 2525
  • connection security: None or STARTTLS
  • authentication: None
  • from address: sender@example.net
  • recipient: alice@example.com

That is enough for a hello-world test from a real mail client.

6. Check the stored message

Inspect the latest mail-store commit:

git -C ./data/everlock-mail log --stat -1

Expected shape:

commit <sha>
Author: ...

    receive mail for alice@example.com

 example.com/alice/2026/05/21/<timestamp>-<id>.eml  | ...
 example.com/alice/2026/05/21/<timestamp>-<id>.toml | ...

List the stored paths:

git -C ./data/everlock-mail ls-tree -r --name-only HEAD | grep 'example.com/alice/'

Expected shape:

example.com/alice/2026/05/21/20260521T101530Z-7f3c2b1a.eml
example.com/alice/2026/05/21/20260521T101530Z-7f3c2b1a.toml

Inspect the sidecar:

git -C ./data/everlock-mail show HEAD:example.com/alice/2026/05/21/<timestamp>-<id>.toml

Expected fields include:

recipient_address = "alice@example.com"
folder = "inbox"
subject = "Hello world"
forwarded = false
source_ip = "127.0.0.1"

STARTTLS note

frontend-smtp manages its own certificate material under config/frontend-smtp/fullchain.pem and config/frontend-smtp/privkey.pem. If no certificate exists yet, it generates a self-signed STARTTLS certificate automatically.

For local testing, that self-signed certificate includes loopback names such as localhost, 127.0.0.1, and ::1, plus the configured SMTP listen host when it is a specific hostname or IP address. For public SMTP hostnames, replace the generated certificate files with operator-provided ones for the hostname your clients actually connect to.

When certificate material exists, EHLO advertises STARTTLS automatically.

Read next

mail smtp getting-started