Postfix and the milter
scailine-milter runs on your mail server and signs outgoing mail as Postfix passes it along.
Message content never leaves the server. The Quickstart walks through a first
installation; this page is the reference.
Enrolment#
Each server is a milter node, enrolled under Milter nodes in the console. Enrolment
returns a token (smn_…) once; the console stores only a hash of it. Revoke a node there when a
server is retired or the token may have leaked: the node stops receiving updates immediately and
keeps signing with its last copy until you stop it.
Configuration#
/etc/scailine/.env, readable only by root and the milter's group:
| Setting | Meaning |
|---|---|
MILTER_API_BASE_URL |
Where snapshots come from (https://scailine.scailabs.ai). |
MILTER_ENROLMENT_TOKEN |
The node token from enrolment. |
MILTER_SNAPSHOT_PUBLIC_KEY |
Public key that snapshots must be signed with. Without it nothing is loaded and mail passes unsigned. |
MILTER_SOCKET |
Unix socket Postfix connects to, e.g. /var/spool/postfix/scailine/milter.sock. |
MILTER_SNAPSHOT_DIR |
Where the last good snapshot is kept (/var/lib/scailine-milter, private to the milter). |
MILTER_MAX_MESSAGE_BYTES |
Larger messages pass unsigned. Default 25 MiB. |
The snapshot contains your organisation's compiled signatures and the key used to sign the
X-ScaiLine header, which is why its directory must be private to the milter user.
Postfix#
Sign outgoing mail only:
| Setting | Value | Why |
|---|---|---|
non_smtpd_milters |
unix:scailine/milter.sock |
Local submission (sendmail, pickup): grommunio's outgoing path and system mail. |
smtpd_milters on the submission service (master.cf, -o) |
unix:scailine/milter.sock |
Authenticated clients sending on port 587. |
smtpd_milters for port 25 |
empty | Incoming mail must never be signed. |
milter_default_action |
accept |
If the milter is down or slow, mail is delivered unsigned instead of held. |
milter_protocol |
6 |
|
milter_connect_timeout, milter_command_timeout, milter_content_timeout |
5s, 15s, 30s |
Bound the worst-case delay. |
The socket path is relative to Postfix's queue directory, so it also works when Postfix runs
chrooted. Postfix must be able to open the socket: put the postfix user in the milter's group.
Keep a copy of main.cf and master.cf before changing them; restoring them and running
postfix reload removes ScaiLine from the mail path entirely.
What the milter changes#
- The message body, where the signature is inserted, and the embedded images if the template uses them.
- One added
X-ScaiLineheader. - For a message that consists only of an HTML part, its top-level
Content-Type(it becomesmultipart/relatedwhen images are embedded).
Nothing else. If a change would require touching any other header, the message passes unmodified.
Snapshots#
The milter asks for a new snapshot every 60 seconds and gets "no change" most of the time. A snapshot with a bad signature, a network error or a server error never replaces the copy on disk. After a restart the milter starts from the copy on disk, so it signs mail even when the control plane cannot be reached.
Operations#
- Status:
systemctl status scailine-milter. - Logs go to ScaiLog; they never contain message content, and senders are pseudonymised.
- Processing counts per day (signed, skipped, passed through) are reported to ScaiLine as statistics; they contain no message data.
- To switch signing off:
systemctl stop scailine-milter. Postfix keeps delivering (withmilter_default_action = accept), without signatures.