smb — standalone SMTP→dmsg bridge
Standalone, dmsg-only SMTP→skywire bridge. Speaks SMTP on a local
TCP port, dials peers via its own dmsg.Client, and does not
require a running visor. Intended for hosts that bridge a
mailserver's outbound queue onto dmsg without otherwise running
skywire.
Reachable two ways:
- As a standalone binary built from
cmd/smb/ — invoke smb ….
- As a subcommand of the unified skywire binary — invoke
skywire dmsg smb …. Both share the same cobra.Command.
For hosts that already run a visor, use the in-process bridge
embedded in the visor (pkg/visor/embedded_skymail_bridge.go). It
runs in the visor process, reuses the visor's dmsg session, and is
managed via the resolver-style CLI:
skywire cli mail # status
skywire cli mail up # enable
skywire cli mail down # disable
The in-process bridge is configured under skymail_bridge in the
visor config (autogenerated by skywire cli config gen --skymail-bridge).
Both flavors share the protocol core in pkg/skymailbridge. They
differ only in where the dmsg session comes from.
Address shapes and the --mode flag
Two recipient address shapes are recognized, independent of mode:
- host-prefixed:
user@<host>.<base32-pk>.skynet — the host
label tells the receiver's Postfix which of its domains the
delivery should land under (e.g. magnetosphere.net).
- bare:
user@<base32-pk>.skynet — no host label; delivery
is governed entirely by the receiver's Postfix configuration
for the bare-PK domain.
--mode chooses the RCPT TO rewrite rule:
b (default) — strip-when-prefixed: a host-prefixed
address has .<pk>.skynet stripped before forwarding, so the
receiver's existing virtual_alias chain handles delivery
natively. A bare address falls through to verbatim — receiver's
Postfix must accept the bare-PK domain directly (via
mydestination or virtual_alias_domains). Strict superset
of mode a: any address mode a accepts is accepted identically
in mode b; mode b additionally strips the host-prefixed shape.
a — verbatim: forward both shapes unchanged. Useful when
the receiver explicitly wants the full .<pk>.skynet domain in
every envelope.
Practical implication: with mode b the receiver can support both
address shapes simultaneously by extending mydestination (or
virtual_alias_domains + alias rows) with the bare-PK suffix —
e.g. add <pk-base32>.skynet alongside the existing virtual_alias
domains. Senders then mail either form with no bridge-side
reconfiguration.
PubKey is encoded as a lowercase RFC 4648 base32 label (53 chars —
fits in a single 63-octet DNS label per RFC 1035 §2.3.1). Helpers
live in pkg/cipher as PubKey.DNSLabel() / ParseDNSLabel.
Usage
# Persistent identity recommended. Provide via --sk, --sk-file, or
# $SKYMAIL_SK; otherwise an ephemeral keypair is generated per
# launch (PK won't match any receiver's allowlist across restarts).
export SKYMAIL_SK="<hex-secret-key>"
skymail-bridge \
--addr 127.0.0.1:1025 \
--mode b \
--suffix .skynet \
--remote-port 25
Then add to Postfix main.cf:
transport_maps = lmdb:/etc/postfix/transport
And /etc/postfix/transport:
.skynet relay:[127.0.0.1]:1025
After postmap + reload, mail addressed to user@…<pk>.skynet
routes through the standalone bridge over dmsg to the peer.
Receiver side
Identical regardless of which sender flavor (standalone or
in-process) is used: the receiver exposes its local Postfix smtpd
on the visor's dmsg face:
skywire cli serve add 25 --to 127.0.0.1:25 --label skymail-bridge
skywire cli serve whitelist 25 <allowed-sender-pk>,<other-pk>
Host-prefixed form (user@<host>.<pk>.skynet): zero Postfix-side
changes — the bridge strips .<pk>.skynet and the envelope hits
your existing virtual_alias chain as user@<host> (e.g.
user@magnetosphere.net).
Bare form (user@<pk>.skynet): the bridge forwards verbatim, so
the receiver's Postfix has to know the bare-PK domain. Two ways:
# Simplest: add the bare-PK domain to mydestination so Postfix
# delivers user@<pk>.skynet to the matching local Unix user.
sudo postconf -e 'mydestination = $myhostname, localhost.$mydomain,
localhost, $mydomain, <pk-base32>.skynet'
sudo systemctl reload postfix
# Or, to route to non-system users / different mailboxes, add the
# bare-PK domain as a virtual_alias_domain and write alias rows
# in /etc/postfix/virtual.
sudo postconf -e 'virtual_alias_domains = magnetosphere.net, <pk-base32>.skynet'
echo 'foo@<pk-base32>.skynet d0mo' | sudo tee -a /etc/postfix/virtual
sudo postmap /etc/postfix/virtual && sudo systemctl reload postfix
With mode b (default) you can enable both address shapes
simultaneously — there's no bridge-side toggle. The receiver
decides which to honor via the Postfix knobs above.
Out of scope
- STARTTLS on either hop. Local Postfix submission stays plain;
the cross-wire hop is dmsg-encrypted end-to-end.
- SMTP AUTH at the bridge inbound side (auth happens at MUA →
sender's Postfix, before the bridge).
- Multi-peer envelopes (returns 451 on the second RCPT so Postfix
retries per-recipient).
- Sender-side spam filtering — receiver enforces via the standard
skywire cli serve whitelist.